/* ==========================================================================
   DSM Accountancy — Design System
   ========================================================================== */

:root {
  /* Palette */
  --color-ink:        #0e1f33;   /* primary text / deep navy */
  --color-ink-soft:    #33465c;
  --color-navy:        #101b2d;
  --color-navy-2:       #16273f;
  --color-paper:        #f7f7f5;
  --color-paper-2:       #ffffff;
  --color-line:           #e3e2dd;
  --color-line-soft:       #edece7;
  --color-gold:              #a97c3f;
  --color-gold-soft:          #c8a06a;
  --color-gold-tint:           #f4ead9;
  --color-success:              #2f7a5c;

  /* Secondary accent palette — used sparingly (topic tags, icon
     badges, section washes) to give the site more colour without
     drifting from the navy/gold core identity. */
  --color-teal:               #2f6f6b;
  --color-teal-tint:          #e2eeec;
  --color-blue:                #3b5f8a;
  --color-blue-tint:           #e4eaf3;
  --color-terracotta:           #b6603f;
  --color-terracotta-tint:      #f4e4dd;
  --color-plum:                  #6c4a7c;
  --color-plum-tint:             #ece3ef;

  /* Type */
  --font-display: "Fraunces", "Iowan Old Style", "Georgia", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* Layout */
  --maxw: 1180px;
  --maxw-narrow: 760px;
  --radius-sm: 6px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --shadow-sm: 0 1px 2px rgba(14, 31, 51, 0.06), 0 1px 1px rgba(14, 31, 51, 0.04);
  --shadow-md: 0 8px 24px rgba(14, 31, 51, 0.08), 0 2px 6px rgba(14, 31, 51, 0.05);
  --shadow-lg: 0 20px 48px rgba(14, 31, 51, 0.12), 0 4px 12px rgba(14, 31, 51, 0.06);

  /* A softer, more premium easing curve than the browser's default
     "ease" — decelerates gently at the end instead of stopping abruptly. */
  --ease-elegant: cubic-bezier(0.16, 1, 0.3, 1);

  /* Frosted-glass tokens. Every translucent/backdrop-blur surface on
     the site (the hero card, the stats strip, filter chips, the
     mobile nav panel, quick-facts callouts, the floating CTA's close
     button, the sticky header) previously had its own hand-picked
     blur/saturate/opacity values — 8px here, 10px there, 12px,
     18px, 20px, opacity anywhere from 0.55 to 0.97 — so the "glass"
     look read differently depending which page or component you
     were looking at. These three variables are the single source of
     truth now; every glass surface below references them (an
     element that wants to look slightly more solid or more subtle
     still can, via --glass-bg-strong / --glass-bg-soft, but the
     blur and saturation are always the same). */
  --glass-blur: 18px;
  --glass-saturate: 220%;
  --glass-bg-soft: rgba(255, 255, 255, 0.22);
  --glass-bg: rgba(255, 255, 255, 0.3);
  --glass-bg-strong: rgba(255, 255, 255, 0.4);
  --glass-border: rgba(255, 255, 255, 0.65);
  /* A faint warm-to-cool diagonal tint, layered on top of the plain
     white above wherever a surface needs to read as genuinely tinted
     glass rather than frosted white — a card sitting over the page's
     pastel wash with only a flat white translucency behind it just
     looks like a plain white box, because there's so little colour in
     that wash for the white to pick up. This gives the glass its own
     colour to carry regardless of what's directly behind it. */
  --glass-tint: linear-gradient(135deg, rgba(169,124,63,0.14) 0%, rgba(59,95,138,0.10) 55%, rgba(47,111,107,0.08) 100%);
}

*, *::before, *::after { box-sizing: border-box; }
/* The earlier attempt combined CSS scroll-snap with a global
   `scroll-behavior: smooth` — every wheel/trackpad tick then triggered
   BOTH the browser's own smooth-scroll animation AND a snap
   correction at once, and the two fighting each other was what made
   scrolling feel jittery. Fixed by splitting the two apart instead of
   dropping smoothness altogether: scroll-snap-type below is
   "proximity" (only ever nudges the page into place once a scroll
   gesture has already stopped near a section, never mid-glide), and
   `scroll-behavior: smooth` is left off html entirely — main.js
   applies it only to the handful of same-page anchor jumps (skip
   link, services.html's #accounts-style links) via
   scrollIntoView({behavior:"smooth"}), so it never runs during
   ordinary wheel scrolling where it could clash with the snap. */
html {
  scroll-snap-type: y proximity;
}
.hero, .section, .section-tight, .site-footer {
  scroll-snap-align: start;
  scroll-margin-top: 72px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-snap-type: none; }
}
/* Scroll-snap reads as intentional "rhythm" on a desktop trackpad/wheel,
   where each scroll tick is small and controlled — but on a phone,
   momentum/inertia scrolling covers much bigger distances per gesture,
   so the browser is constantly fighting the user's fling to snap back
   to the nearest section boundary. That's the jitter. Snap is desktop-
   only; touch devices get plain, uninterrupted scrolling. */
@media (max-width: 900px) {
  html { scroll-snap-type: none; }
}

/* Skip link — invisible until keyboard-focused, then jumps straight to
   <main id="main">. Lets keyboard/screen-reader users bypass the full
   nav on every page load instead of tabbing through it every time. */
.skip-link {
  position: absolute;
  top: -48px;
  left: 12px;
  z-index: 1000;
  background: var(--color-navy);
  color: #fff;
  padding: 12px 20px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.9rem;
  transition: top 0.2s ease;
}
.skip-link:focus {
  top: 12px;
}

/* Soft cross-fade between pages in browsers that support the View
   Transitions API (progressive enhancement — ignored elsewhere, and
   every page still renders and works identically without it). */
@view-transition {
  navigation: auto;
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* One continuous, multi-colour wash painted once across the entire
   document height, rather than a separate tinted "orb" repeated
   inside every section. Percentage-based radial-gradient positions
   resolve against body's own (full-page) box, so the wash flows
   smoothly from top to bottom of the page with no seam anywhere —
   there is nothing for a section boundary to interrupt, because the
   colour isn't reset at each section, it's one shared canvas behind
   all of them. Plain background-image, normal (scrolling) attachment
   — no filter, no fixed positioning, no per-frame cost. */
body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-ink);
  background-color: var(--color-paper);
  background-repeat: no-repeat;
  background-image:
    radial-gradient(720px 720px at 6% 3%,   rgba(244,234,217,0.68) 0%, rgba(244,234,217,0) 70%),
    radial-gradient(660px 660px at 96% 12%, rgba(210,222,238,0.62) 0%, rgba(210,222,238,0) 70%),
    radial-gradient(680px 680px at 3% 26%,  rgba(214,236,232,0.58) 0%, rgba(214,236,232,0) 70%),
    radial-gradient(640px 640px at 97% 38%, rgba(244,220,209,0.54) 0%, rgba(244,220,209,0) 70%),
    radial-gradient(700px 700px at 5% 50%,  rgba(244,234,217,0.6)  0%, rgba(244,234,217,0) 70%),
    radial-gradient(660px 660px at 96% 62%, rgba(210,222,238,0.58) 0%, rgba(210,222,238,0) 70%),
    radial-gradient(680px 680px at 3% 74%,  rgba(228,213,233,0.52) 0%, rgba(228,213,233,0) 70%),
    radial-gradient(660px 660px at 97% 86%, rgba(214,236,232,0.54) 0%, rgba(214,236,232,0) 70%),
    radial-gradient(700px 700px at 7% 98%,  rgba(244,234,217,0.62) 0%, rgba(244,234,217,0) 70%);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  font-size: 16px;
  position: relative;
}

/* A very faint grain, fixed to the viewport over the whole page. On
   its own this reads as almost nothing consciously — that's the
   point: it's the same trick a physical, printed or textured surface
   has that a perfectly flat digital gradient doesn't, and its absence
   is part of why large smooth colour washes (like the one above) can
   read as slightly synthetic. mix-blend-mode: overlay lets it darken
   or lighten depending on what's under it rather than sitting as a
   flat grey layer, and it costs nothing to animate since nothing
   about it moves. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
@media (prefers-reduced-transparency: reduce) {
  body::after { display: none; }
}

img, svg { max-width: 100%; display: block; }
a { color: inherit; }

/* Cross-fade between pages (see main.js). Opacity only, on the body
   itself, so it's dirt cheap and never fights layout. Gated behind
   the .page-transitions class main.js adds, so a visitor with
   JavaScript disabled — or who has prefers-reduced-motion on — just
   gets ordinary, instant navigation instead of a body that's stuck
   invisible. */
.page-transitions body { opacity: 1; transition: opacity 0.18s ease; }
.page-transitions.is-leaving body { opacity: 0; }

/* A single, deliberate focus ring for every focusable element,
   rather than each browser's own default (a thin blue rectangle in
   Chrome, a different one in Safari/Firefox) — small, but it's one of
   the details that makes a site feel like one considered piece of
   work rather than an assembly of browser defaults. :focus-visible
   only shows it for keyboard/assistive-tech navigation, never on an
   ordinary mouse click, so it never looks like stray outlines when
   clicking around. */
:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: 3px;
  border-radius: 4px;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 0.5em;
  color: var(--color-navy);
}

/* h1 was trimmed hard in an earlier pass (down from 3.4rem) because a
   fixed-height hero meant a bigger headline pushed the next section
   into view. The hero now sizes itself with min-height instead of a
   fixed height, so there's room to bring some of that back — a
   larger, more confident h1 is one of the cheapest ways to make a
   page read as considered rather than templated. Its own tighter
   letter-spacing (vs. the shared -0.01em above) reads as more
   "designed" at this size, the same way a magazine masthead tracks
   tighter than its body copy. */
h1 { font-size: clamp(2.2rem, 4.6vw, 3.35rem); letter-spacing: -0.02em; }
h2 { font-size: clamp(1.5rem, 2.4vw, 1.9rem); }
h3 { font-size: 1.2rem; }
p { margin: 0 0 1em; color: var(--color-ink-soft); font-size: 0.97rem; line-height: 1.7; }

/* An italic, gold accent for one key phrase inside a heading — an
   editorial flourish (think of how a magazine sets one word in a
   pull-quote) rather than a uniform weight all the way through.
   Wrap the phrase in <em> where it's wanted; nowhere is required to
   use it. Needs Fraunces' italic axis, which the Google Fonts <link>
   on every page now requests alongside the upright weights. */
h1 em, h2 em {
  font-style: italic;
  font-weight: 500;
  color: var(--color-gold);
}

/* Standard "sub-heading" intro paragraph — the one larger, lighter
   paragraph directly under an h1 (homepage hero, every inner page's
   page-hero). Centralised here so every page's intro paragraph is the
   same size instead of each page carrying its own inline
   font-size override (they'd drifted to 1.1rem on inner pages vs
   1.02rem on the homepage hero before this). max-width still varies
   per instance since that's a layout choice, not a type-scale one. */
.lead { font-size: 1.05rem; }

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

/* overflow: clip (not hidden) — it still clips the ambient orb below
   so it can't cause horizontal scroll, but unlike `hidden` it does not
   register as a scroll container, so CSS scroll-driven .reveal
   animations on elements inside still resolve against the real page
   scroller instead of getting stuck reporting "always fully in view". */
.section { position: relative; overflow: clip; }
/* .section-tight never clips: unlike .hero it has no decorative
   ::before/::after blobs to hide, and several .section-tight blocks
   (about.html, index.html) hold a .hero-card whose --shadow-lg (48px
   blur, 20px offset) needs ~68px of clearance below it. .section-tight's
   own padding is only 32px, so clipping here sliced that shadow into a
   hard flat line right where the next section begins — dropping the
   clip lets it fade out naturally instead. */
.section-tight { position: relative; }
.section { padding: 56px 0; }
.section-tight { padding: 32px 0; }
.section > .container, .section-tight > .container { position: relative; z-index: 1; }

/* .section-alt is a translucent panel, not a solid one — it lets the
   body's colour wash keep showing through faintly at full strength,
   so there is never a hard edge where one section's background meets
   the next. Fully transparent at its own top/bottom edge (matching
   whatever is already behind it) and only lightly tinted toward
   white in the middle, for just enough contrast to read as a
   distinct panel without ever blocking the wash outright. */
.section-alt {
  /* Percentage-based stops (not a fixed px inset) so the fade is always
     proportionally the same size as the panel, however tall it renders —
     a fixed px inset looks fine on a tall desktop section but reads as an
     abrupt, barely-there fade on a short mobile section, since the inset
     eats a much bigger share of a shorter box. */
  background: linear-gradient(
    180deg,
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,0.86) 18%,
    rgba(255,255,255,0.86) 82%,
    rgba(255,255,255,0) 100%
  );
}
/* .section-tight is shorter (32px top/bottom padding vs .section's 56px),
   so a short .section-tight.section-alt panel (e.g. the homepage's compact
   "who we help" stats strip) can be under 144px tall — leaving the fixed
   72px fade-in/fade-out inset from .section-alt above with nowhere to
   land: the two middle gradient stops end up in the wrong order, which
   browsers clamp by just holding the panel solid white with almost no
   visible fade, reading as a harder edge than every other section.
   Percentage-based stops (rather than a fixed px inset) scale with
   whatever height the panel actually renders at, so the fade is always
   proportionally the same size as the panel — soft and gradual — no
   matter how short the content inside it is. */
.section-tight.section-alt {
  background: linear-gradient(
    180deg,
    rgba(255,255,255,0) 0%,
    rgba(255,255,255,0.86) 32%,
    rgba(255,255,255,0.86) 68%,
    rgba(255,255,255,0) 100%
  );
}

.section-navy {
  background: linear-gradient(160deg, var(--color-navy) 0%, var(--color-navy-2) 100%);
  color: #eef1f5;
}
.section-navy h2, .section-navy h3 { color: #ffffff; }
.section-navy p { color: #b9c3d0; }
.section-navy::before { opacity: 0.15; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--color-gold);
  margin-bottom: 14px;
}
.eyebrow::before {
  content: "";
  width: 22px;
  height: 1px;
  background: var(--color-gold);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 26px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.005em;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.35s var(--ease-elegant), box-shadow 0.35s var(--ease-elegant), background-color 0.25s ease, color 0.25s ease;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn:active { transform: translateY(-1px) scale(0.98); transition-duration: 0.1s; }
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.28) 48%, transparent 66%);
  transform: translateX(-120%);
  transition: transform 0.6s var(--ease-elegant);
  z-index: 1;
  pointer-events: none;
}
.btn:hover::before { transform: translateX(120%); }
/* A subtle top-lit gradient plus an inset highlight along the top
   edge, rather than one flat fill colour — the kind of detail that
   reads as "considered" mostly subconsciously, the way a well-made
   physical object catches light slightly differently than a flat
   sticker of the same colour. */
.btn-primary {
  background: linear-gradient(180deg, var(--color-navy-2) 0%, var(--color-navy) 100%);
  color: #fff;
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.12);
}
.btn-primary:hover { background: linear-gradient(180deg, #17263f 0%, #0a1420 100%); box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255,255,255,0.14); }
.btn-gold {
  background: linear-gradient(180deg, var(--color-gold-soft) 0%, var(--color-gold) 100%);
  color: #fff;
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,0.22);
}
.btn-gold:hover { background: linear-gradient(180deg, var(--color-gold) 0%, #93692f 100%); box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255,255,255,0.22); }
.btn-outline {
  background: transparent;
  border-color: rgba(255,255,255,0.35);
  color: #fff;
}
.btn-outline:hover { background: rgba(255,255,255,0.1); }
.btn-outline-navy {
  background: transparent;
  border-color: var(--color-line);
  color: var(--color-navy);
}
.btn-outline-navy:hover { background: #fff; box-shadow: var(--shadow-sm); }
.btn-block { width: 100%; }

/* ---------- Header / Nav ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(247, 247, 245, 0.92);
  backdrop-filter: saturate(var(--glass-saturate)) blur(var(--glass-blur));
  -webkit-backdrop-filter: saturate(var(--glass-saturate)) blur(var(--glass-blur));
  border-bottom: 1px solid transparent;
  box-shadow: none;
  transition: box-shadow 0.35s var(--ease-elegant), border-color 0.35s var(--ease-elegant), background-color 0.35s var(--ease-elegant);
}
/* A soft fade below the header rather than a hard edge where its
   background meets whatever is scrolling underneath — extends past
   the header's own box, purely decorative (pointer-events: none), so
   it never intercepts clicks on the content beneath it. */
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 32px;
  background: linear-gradient(180deg, rgba(247,247,245,0.92) 0%, rgba(247,247,245,0) 100%);
  pointer-events: none;
}
/* Toggled by main.js once the page has scrolled a little — a soft
   lift that reinforces the header is now floating over content,
   rather than sitting flush against it. Purely decorative: the
   header looks and works identically before this class is ever
   added. */
.site-header.is-scrolled {
  border-bottom-color: var(--color-line);
  box-shadow: 0 8px 30px rgba(14, 31, 51, 0.06);
  background: rgba(247, 247, 245, 0.94);
}
.site-header.is-scrolled::after {
  background: linear-gradient(180deg, rgba(247,247,245,0.94) 0%, rgba(247,247,245,0) 100%);
}
@media (prefers-reduced-motion: reduce) {
  .site-header { transition: none; }
}
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 16px;
  padding-bottom: 16px;
  flex-wrap: nowrap;
  gap: 12px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.25rem;
  color: var(--color-navy);
  min-width: 0;
}
.brand > span:last-child { white-space: nowrap; min-width: 0; }
.brand-mark-img {
  height: 30px;
  width: auto;
  display: block;
  flex: none;
}
.brand .brand-mark {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--color-navy);
  color: var(--color-gold-soft);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  flex: none;
}
.brand .brand-tail { font-family: var(--font-body); font-weight: 500; font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-gold); display: block; }
@media (max-width: 480px) {
  .brand { font-size: 1.02rem; }
  .brand .brand-tail { display: none; }
  .nav-cta .btn-primary { display: none; }
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 34px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-links a {
  text-decoration: none;
  font-size: 0.94rem;
  font-weight: 500;
  color: var(--color-ink-soft);
  position: relative;
  padding: 4px 0;
}
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--color-navy); }
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -4px;
  height: 2px;
  background: var(--color-gold);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.25s ease;
}
.nav-links a:hover::after { transform: scaleX(1); }
.nav-links a[aria-current="page"]::after { transform: scaleX(1); }
.nav-cta { display: flex; align-items: center; gap: 14px; }
.nav-toggle {
  display: none;
  border: none;
  background: none;
  padding: 8px;
  cursor: pointer;
}
.nav-toggle span, .nav-toggle span::before, .nav-toggle span::after {
  content: "";
  display: block;
  width: 22px;
  height: 2px;
  background: var(--color-navy);
  position: relative;
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.nav-toggle span::before { position: absolute; top: -7px; }
.nav-toggle span::after { position: absolute; top: 7px; }

@media (max-width: 900px) {
  .nav-links {
    position: fixed;
    inset: 68px 16px auto 16px;
    /* This is the one glass surface where legibility trumps matching
       the shared --glass-* tokens exactly: it's a full menu of text
       sitting directly over the page's own content, so it needs a
       much stronger blur (to properly soften whatever's behind it,
       rather than leaving a sharp-edged ghost of it visible) and a
       near-opaque background, rather than the lighter touch that
       suits a small decorative card. */
    background: rgba(255, 255, 255, 0.96);
    backdrop-filter: blur(28px) saturate(var(--glass-saturate));
    -webkit-backdrop-filter: blur(28px) saturate(var(--glass-saturate));
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    flex-direction: column;
    align-items: stretch;
    padding: 12px;
    box-shadow: var(--shadow-lg);
    gap: 2px;
    display: flex;
    opacity: 0;
    transform: translateY(-8px) scale(0.98);
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
  }
  .nav-links.open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
  .nav-links a { padding: 12px 14px; border-radius: 8px; }
  .nav-links a:hover { background: var(--color-paper); }
  .nav-links a::after { display: none; }
  .nav-cta .btn-primary { padding: 10px 18px; font-size: 0.88rem; }
  .nav-toggle { display: block; }
  .nav-toggle[aria-expanded="true"] span { background: transparent; }
  .nav-toggle[aria-expanded="true"] span::before { transform: translateY(7px) rotate(45deg); }
  .nav-toggle[aria-expanded="true"] span::after { transform: translateY(-7px) rotate(-45deg); }
  .nav-toggle span::before, .nav-toggle span::after { transition: transform 0.2s ease; }
}
@media (prefers-reduced-motion: reduce) {
  .nav-links { transition: none; }
}

/* ---------- Hero ---------- */
/* Fills the space below the sticky header up to the bottom of the
   viewport, so the hero reads as a proper "first screen" without the
   next section peeking in underneath — and centers its content
   vertically within that space rather than needing hand-tuned
   padding to hit an exact height. min-height (not height) means a
   phone with a very long lead paragraph or wrapped heading still
   just grows the section rather than clipping anything. */
.hero {
  padding: 36px 0 28px;
  min-height: calc(100svh - 81px);
  display: flex;
  align-items: center;
  position: relative;
  overflow: clip;
}
.hero > .container { width: 100%; }
/* Below 900px the hero-grid (further down) stacks to one column, so
   the hero-card becomes the last thing in the section, sitting right
   against its bottom edge. The card's shadow (--shadow-lg: a 48px
   blur, 20px y-offset) needs more clearance than the 28px bottom
   padding above gives it, so .hero's own overflow:clip was slicing
   the shadow off in a hard flat line instead of letting it fade out —
   this restores enough room for it to fade naturally. */
@media (max-width: 900px) {
  .hero { min-height: 0; padding-bottom: 88px; }
}
/* Soft ambient glow — a multi-stop radial-gradient rather than a
   filter: blur() circle. Visually just as soft, but far cheaper to
   render: a real Gaussian blur has to be recomposited every time
   anything behind or in front of it changes (including every frame
   of the drift animation below, or a sticky/blurred header scrolling
   past it), while a gradient is just a flat paint. This is what
   keeps scrolling smooth even with several of these per page. */
.hero::before, .hero::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  z-index: 0;
  pointer-events: none;
}
/* Both blobs fade to fully transparent by 45% of their own radius,
   leaving a wide, guaranteed-transparent buffer zone all the way out
   to the box's actual edge (100%). .hero has overflow:clip, and these
   boxes are positioned partly outside the section (so the glow reads
   as drifting in from off-canvas) — that previously meant the section
   boundary sliced straight through still-visible colour, showing up
   as a hard rectangular cutoff right where the hero met the next
   section. With the colour gone well before the edge, clipping the
   box now only ever clips empty space. */
.hero::before {
  width: 560px; height: 560px;
  top: -220px; right: -160px;
  background: radial-gradient(circle at 30% 30%, rgba(244,234,217,0.9) 0%, rgba(244,234,217,0.4) 24%, rgba(244,234,217,0) 45%);
  animation: drift-a 22s ease-in-out infinite;
}
.hero::after {
  width: 460px; height: 460px;
  bottom: -120px; left: -140px;
  background: radial-gradient(circle at 60% 40%, rgba(223,230,238,0.85) 0%, rgba(223,230,238,0.35) 24%, rgba(223,230,238,0) 45%);
  animation: drift-b 26s ease-in-out infinite;
}
@keyframes drift-a {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(-30px, 30px) scale(1.08); }
}
@keyframes drift-b {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50% { transform: translate(24px, -24px) scale(1.05); }
}
.hero-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 56px;
  align-items: center;
  position: relative;
  z-index: 1;
}
@media (prefers-reduced-motion: reduce) {
  .hero::before, .hero::after { animation: none; }
}
.hero-copy p.lead {
  max-width: 46ch;
}
.hero-actions { display: flex; gap: 14px; margin-top: 22px; flex-wrap: wrap; }
.hero-meta {
  display: flex;
  gap: 28px;
  margin-top: 28px;
  flex-wrap: wrap;
}
.hero-meta div { min-width: 120px; }
/* Below 480px, 3 items x their 120px min-width plus 28px gaps no longer
   fit on one line, so the row wraps to an uneven 2-then-1 stack. Shrinking
   the min-width and gap here (rather than letting it wrap) keeps all three
   stats on a single row on a phone screen, matching the desktop layout. */
@media (max-width: 480px) {
  .hero-meta { gap: 14px; flex-wrap: nowrap; }
  .hero-meta div { min-width: 0; flex: 1 1 0; }
  .hero-meta .num { font-size: 1.25rem; }
  .hero-meta .lbl { font-size: 0.72rem; line-height: 1.25; }
}
.hero-meta .num {
  font-family: var(--font-display);
  font-size: 1.6rem;
  color: var(--color-navy);
  font-weight: 600;
  display: block;
}
.hero-meta .lbl { font-size: 0.82rem; color: var(--color-ink-soft); }

.hero-card {
  position: relative;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 30px;
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  transition: transform 0.5s var(--ease-elegant), box-shadow 0.5s var(--ease-elegant);
  will-change: transform;
}
/* Purely decorative abstract growth motif — an ascending line with
   accent nodes, floated above the hero card like a badge. Aria-hidden
   and never implies any real figure or statistic. */
.hero-graphic {
  position: absolute;
  top: -26px;
  right: 22px;
  z-index: 2;
  pointer-events: none;
  filter: drop-shadow(0 6px 14px rgba(169,124,63,0.25));
}
@media (max-width: 900px) { .hero-graphic { display: none; } }
.hero-card .row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--color-line-soft);
  transition: transform 0.35s var(--ease-elegant);
}
.hero-card .row:last-child { border-bottom: none; }
.hero-card .row:hover { transform: translateX(4px); }
.hero-card .ico {
  width: 38px; height: 38px; border-radius: 10px;
  background: var(--color-gold-tint);
  color: var(--color-gold);
  display: flex; align-items: center; justify-content: center;
  flex: none;
  transition: transform 0.4s var(--ease-elegant);
}
.hero-card .row:hover .ico { transform: scale(1.1) rotate(-4deg); }
.hero-card h4 { margin: 0 0 4px; font-size: 1rem; }
@media (prefers-reduced-motion: reduce) {
  .hero-card, .hero-card .row, .hero-card .ico { transition: none; }
}
.hero-card p { margin: 0; font-size: 0.9rem; }

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  /* Not touching .hero's bottom padding here — a separate, earlier
     @media (max-width: 900px) block already sets it to 88px specifically
     so the hero-card's shadow has room to fade out instead of getting
     clipped; this block used to also set padding-bottom: 32px here,
     which (being later in the file) silently won and undid that fix. */
  .hero { padding-top: 40px; }
}

/* ---------- Cards / grids ---------- */
.grid { display: grid; gap: 24px; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) {
  .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
}

.card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Cards in the same grid row get stretched to match the tallest
     sibling (CSS Grid's default row behaviour) — e.g. when one card's
     heading wraps to two lines and its neighbours' don't. Without
     align-content:flex-start, the wrapped flex container's default
     ("normal", which behaves like stretch) shares that extra height
     out BETWEEN the icon+heading row and the paragraph row, opening a
     big gap between them instead of leaving it at the bottom of the
     card where it belongs. */
  align-content: flex-start;
  column-gap: 16px;
  row-gap: 4px;
  /* Frosted glass, matching every other translucent surface on the
     site (see the --glass-* tokens) rather than the plain opaque
     white these cards used to have — that flatness is what made them
     read as generic white boxes instead of part of the same "glass"
     visual language as the hero card, stats strip, etc. */
  background: var(--glass-bg-strong);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 26px;
  box-shadow: var(--shadow-sm);
  transition: transform 0.45s var(--ease-elegant), box-shadow 0.45s var(--ease-elegant), border-color 0.3s ease;
  position: relative;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
}
/* Icon sits beside the heading on one row instead of stacked above
   it, then the paragraph drops to its own full-width row below —
   shortens every card noticeably, which matters most on mobile where
   these stack one after another down a long single column. */
.card .ico { margin-bottom: 0; flex: 0 0 auto; }
.card h3, .card h4 { flex: 1 1 0%; min-width: 0; margin: 0; }
.card p { flex: 1 1 100%; margin: 6px 0 0; }
.card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--color-gold), var(--color-gold-soft));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease-elegant);
}
.card:hover {
  transform: translateY(-6px) scale(1.008);
  /* A soft gold glow added alongside the usual lift shadow, rather
     than just a darker/bigger version of the resting shadow — a small
     amount of colour in a hover state (vs. plain grey) is what separates
     "this reacted" from "this is important/branded and reacted". */
  box-shadow: var(--shadow-md), 0 0 0 1px rgba(169,124,63,0.18), 0 12px 32px -8px rgba(169,124,63,0.22);
  border-color: rgba(169,124,63,0.35);
}
.card:hover::before { transform: scaleX(1); }
.card .ico {
  width: 46px; height: 46px; border-radius: 13px;
  background: linear-gradient(150deg, var(--color-gold-tint) 0%, rgba(169,124,63,0.28) 100%);
  color: var(--color-gold);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 18px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 3px rgba(169,124,63,0.18);
  transition: transform 0.4s var(--ease-elegant), box-shadow 0.4s var(--ease-elegant);
}
.card:hover .ico { transform: scale(1.1) rotate(-4deg); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 4px 12px rgba(169,124,63,0.3); }

/* Small standalone icon badge for plain text lists (e.g. the "why
   DSM Accountancy" grid) that aren't inside a .card — same colour
   language as the service card icons, at a smaller size. */
.feature-ico {
  width: 32px; height: 32px; border-radius: 9px;
  background: var(--color-gold-tint);
  color: var(--color-gold);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 12px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.6);
}
/* .feature-row: same "icon beside the heading, paragraph full-width
   underneath" treatment as .card above, for the icon+heading+text
   items that aren't wrapped in a card (e.g. the homepage "why DSM
   Accountancy" grid). Stacking the icon above the heading, as before,
   made each item taller than it needed to be — noticeable on mobile
   where six of these run one after another down a single column. */
.feature-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  align-content: flex-start;
  column-gap: 14px;
  row-gap: 2px;
  padding: 20px;
  background: var(--glass-bg-strong);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  transition: transform 0.4s var(--ease-elegant), box-shadow 0.4s var(--ease-elegant), border-color 0.3s ease;
}
.feature-row:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md), 0 0 0 1px rgba(169,124,63,0.18), 0 12px 32px -8px rgba(169,124,63,0.22);
  border-color: rgba(169,124,63,0.35);
}
.feature-row:hover .feature-ico { transform: scale(1.08) rotate(-3deg); }
.feature-row .feature-ico { margin-bottom: 0; flex: 0 0 auto; transition: transform 0.4s var(--ease-elegant); }
.feature-row h3 { flex: 1 1 0%; min-width: 0; margin: 0; }
.feature-row p { flex: 1 1 100%; margin: 6px 0 0; }
@media (max-width: 640px) {
  .feature-row { margin-bottom: 4px; }
}
.feature-ico.ico-blue   { background: var(--color-blue-tint); color: var(--color-blue); }
.feature-ico.ico-teal    { background: var(--color-teal-tint); color: var(--color-teal); }
.feature-ico.ico-terracotta { background: var(--color-terracotta-tint); color: var(--color-terracotta); }
.feature-ico.ico-plum    { background: var(--color-plum-tint); color: var(--color-plum); }
.feature-ico.ico-navy    { background: #e7eaf0; color: var(--color-navy); }

/* Colour variants so a grid of service cards reads with more variety
   than one repeated gold tint — each still pairs a soft tint
   background with a matching mid-tone icon colour. */
.card .ico.ico-blue   { background: linear-gradient(150deg, var(--color-blue-tint) 0%, rgba(59,95,138,0.28) 100%); color: var(--color-blue); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 3px rgba(59,95,138,0.18); }
.card .ico.ico-teal    { background: linear-gradient(150deg, var(--color-teal-tint) 0%, rgba(47,111,107,0.28) 100%); color: var(--color-teal); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 3px rgba(47,111,107,0.18); }
.card .ico.ico-terracotta { background: linear-gradient(150deg, var(--color-terracotta-tint) 0%, rgba(182,96,63,0.28) 100%); color: var(--color-terracotta); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 3px rgba(182,96,63,0.18); }
.card .ico.ico-plum    { background: linear-gradient(150deg, var(--color-plum-tint) 0%, rgba(108,74,124,0.28) 100%); color: var(--color-plum); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 3px rgba(108,74,124,0.18); }
.card .ico.ico-navy    { background: linear-gradient(150deg, #e7eaf0 0%, rgba(16,27,45,0.22) 100%); color: var(--color-navy); box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 3px rgba(16,27,45,0.14); }
.card:hover .ico.ico-blue   { box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 4px 12px rgba(59,95,138,0.3); }
.card:hover .ico.ico-teal    { box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 4px 12px rgba(47,111,107,0.3); }
.card:hover .ico.ico-terracotta { box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 4px 12px rgba(182,96,63,0.3); }
.card:hover .ico.ico-plum    { box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 4px 12px rgba(108,74,124,0.3); }
.card:hover .ico.ico-navy    { box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 4px 12px rgba(16,27,45,0.22); }

/* Staggered entrance for grids of cards — purely cosmetic timing on
   top of the always-visible .reveal fade (see below), never a
   visibility gate. */
.grid.reveal, .steps .reveal {}
.grid > .reveal:nth-child(1), .steps > .reveal:nth-child(1) { animation-delay: 0.05s; }
.grid > .reveal:nth-child(2), .steps > .reveal:nth-child(2) { animation-delay: 0.12s; }
.grid > .reveal:nth-child(3), .steps > .reveal:nth-child(3) { animation-delay: 0.19s; }
.grid > .reveal:nth-child(4), .steps > .reveal:nth-child(4) { animation-delay: 0.26s; }
.grid > .reveal:nth-child(5) { animation-delay: 0.33s; }
.grid > .reveal:nth-child(6) { animation-delay: 0.4s; }
.grid > .reveal:nth-child(7) { animation-delay: 0.47s; }
.grid > .reveal:nth-child(8) { animation-delay: 0.54s; }
.card h3 { margin-bottom: 8px; }
.card p:last-child { margin-bottom: 0; }
.card .tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.card .tags span {
  font-size: 0.76rem;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--color-paper);
  border: 1px solid var(--color-line);
  color: var(--color-ink-soft);
}
.card a.card-link, .card .card-link {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 16px; font-weight: 600; font-size: 0.9rem;
  text-decoration: none; color: var(--color-navy);
  transition: gap 0.25s ease, color 0.25s ease;
}
.card:hover .card-link { gap: 10px; color: var(--color-gold); }
@media (prefers-reduced-motion: reduce) {
  .card a.card-link, .card .card-link { transition: none; }
}

/* Section heading block */
.head-block { max-width: 640px; margin: 0 0 36px; }
.head-block.center { margin-left: auto; margin-right: auto; text-align: center; }
/* Keeps a short heading on one line at desktop/tablet widths, where
   there's easily enough room, while still allowing it to wrap
   naturally on narrow phones rather than forcing an overflow. */
@media (min-width: 560px) {
  .no-wrap-sm { white-space: nowrap; }
}

/* ---------- Stats strip ---------- */
/* Frosted-glass pills rather than a plain bordered strip — small
   elements, so the backdrop-filter cost here is negligible even
   though it was worth removing from large full-width surfaces. */
.stats-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  padding: 8px 0;
}
.stats-strip div {
  text-align: center;
  padding: 22px 14px;
  border-radius: var(--radius-md);
  background: var(--glass-bg-soft);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  box-shadow: 0 1px 2px rgba(14,31,51,0.04);
  transition: transform 0.4s var(--ease-elegant), box-shadow 0.4s var(--ease-elegant);
}
.stats-strip div:hover { transform: translateY(-3px); box-shadow: var(--shadow-sm); }
.stats-strip .num { font-family: var(--font-display); font-size: clamp(1.3rem, 2.6vw, 1.9rem); color: var(--color-navy); font-weight: 600; display: block; margin-bottom: 6px; white-space: nowrap; }
.stats-strip .lbl { font-size: 0.85rem; color: var(--color-ink-soft); display: block; }
.stats-strip div:nth-child(1) .num { color: var(--color-gold); }
.stats-strip div:nth-child(2) .num { color: var(--color-blue); }
.stats-strip div:nth-child(3) .num { color: var(--color-teal); }
.stats-strip div:nth-child(4) .num { color: var(--color-terracotta); }
@media (max-width: 640px) { .stats-strip { grid-template-columns: repeat(2, 1fr); } }

/* ---------- Process steps ---------- */
/* A gold connecting line runs behind the circular step badges on
   desktop, reinforcing that this is one continuous flow rather than
   four unrelated boxes — purely decorative (::before), removed on
   narrower layouts where the grid stacks and a straight line no
   longer makes visual sense. */
.steps { counter-reset: step; display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; position: relative; }
.steps::before {
  content: "";
  position: absolute;
  top: 26px;
  left: 12.5%;
  right: 12.5%;
  height: 2px;
  /* Was faded to transparent at both ends (meant as a soft taper past
     circles 1 and 4) but at this line's actual length that fade ate
     into a good chunk of the 1-2 segment, reading as a broken or
     half-missing line rather than a deliberate taper — solid the
     whole way across is more legible as "these four steps are
     connected". */
  background: var(--color-gold-soft);
  z-index: 0;
}
.step { position: relative; padding-top: 8px; z-index: 1; }
.step::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  color: #fff;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: linear-gradient(150deg, var(--color-gold) 0%, #8a642f 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
  box-shadow: 0 4px 14px rgba(169,124,63,0.32), 0 0 0 6px var(--color-paper);
  transition: transform 0.4s var(--ease-elegant);
}
.step:hover::before { transform: scale(1.08); }
/* Below 900px the connecting line is already hidden (it only makes
   sense as a straight line across a 4-column row), so the numbered
   circle no longer needs to sit centred above the heading either —
   putting it inline beside the heading instead, same as the .card
   and .feature-row treatment, keeps this from being yet another
   stacked icon+heading block making the page longer than it needs
   to be on mobile. */
@media (max-width: 900px) {
  .steps { grid-template-columns: repeat(2, 1fr); }
  .steps::before { display: none; }
  .step {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    align-content: flex-start;
    column-gap: 14px;
    row-gap: 2px;
    padding-top: 0;
  }
  .step::before { width: 44px; height: 44px; font-size: 0.92rem; margin-bottom: 0; flex: 0 0 auto; }
  .step h3 { flex: 1 1 0%; min-width: 0; margin: 0; }
  .step p { flex: 1 1 100%; margin: 6px 0 0; }
}
@media (max-width: 560px) { .steps { grid-template-columns: 1fr; } }

/* ---------- CTA banner ---------- */
.cta-banner {
  border-radius: var(--radius-lg);
  padding: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 30px;
  flex-wrap: wrap;
  background: linear-gradient(160deg, var(--color-navy) 0%, var(--color-navy-2) 100%);
  color: #fff;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.cta-banner::before {
  content: "";
  position: absolute;
  width: 420px; height: 420px;
  top: -180px; right: -100px;
  border-radius: 50%;
  background:
    radial-gradient(circle, rgba(201,151,63,0.4) 0%, rgba(201,151,63,0.16) 35%, rgba(201,151,63,0) 70%),
    radial-gradient(circle at 15% 85%, rgba(70,140,135,0.3) 0%, rgba(70,140,135,0) 55%);
  z-index: -1;
  animation: drift-a 20s ease-in-out infinite;
}
/* A slow, periodic light sweep across the banner — a glass-like
   reflection passing over the surface every few seconds. Pure
   transform animation (compositor-only), so it's effectively free. */
.cta-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,0.1) 50%, transparent 58%);
  transform: translateX(-150%);
  animation: cta-sheen 7s ease-in-out infinite;
  pointer-events: none;
}
@keyframes cta-sheen {
  0% { transform: translateX(-150%); }
  35% { transform: translateX(150%); }
  100% { transform: translateX(150%); }
}
.cta-banner h2 { color: #fff; margin-bottom: 6px; }
.cta-banner p { color: #b9c3d0; margin: 0; }
@media (prefers-reduced-motion: reduce) {
  .cta-banner::before, .cta-banner::after { animation: none; }
}

/* ---------- Forms ---------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

label { display: block; font-size: 0.86rem; font-weight: 600; color: var(--color-navy); margin-bottom: 6px; }
input, select, textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-line);
  background: #fff;
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: var(--color-ink);
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--color-gold-soft);
  box-shadow: 0 0 0 3px var(--color-gold-tint);
}
textarea { resize: vertical; min-height: 130px; }
.form-note { font-size: 0.82rem; color: var(--color-ink-soft); margin-top: 14px; }

/* ---------- Floating-label fields ---------- */
/* .field wraps an input/select/textarea followed by its <label> (the
   label comes AFTER the control in the markup specifically so the
   plain `+` sibling selector below can react to the control's own
   state — no JS, no :has()). At rest the label sits inside the field
   doing the job a plain grey placeholder used to; the moment the
   field is focused or has a value, it shrinks and lifts to the
   top edge, so the field never demands two labels' worth of space
   (a static label above, plus a placeholder inside) the way the
   previous version of this form did. */
.field { position: relative; margin-bottom: 0; }
.field input, .field select, .field textarea { padding: 21px 14px 9px; }
.field textarea { padding-top: 24px; }
.field label {
  position: absolute;
  left: 14px;
  top: 15px;
  margin: 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--color-ink-soft);
  background: #fff;
  padding: 0 3px;
  pointer-events: none;
  transform-origin: left top;
  transition: transform 0.2s var(--ease-elegant), color 0.2s ease;
}
.field input:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:focus + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-13px) scale(0.8);
  color: var(--color-gold);
}
/* A <select> always shows some value (there's no empty/placeholder
   state to rest a label inside), so its label is simply parked in the
   floated position permanently rather than trying to fake a
   :placeholder-shown-style transition for a control that has no
   equivalent state. */
.field.select-field label { transform: translateY(-13px) scale(0.8); }
.field.select-field select:focus + label { color: var(--color-gold); }
.field-hint { font-size: 0.8rem; color: var(--color-ink-soft); margin: 6px 0 0; }
.form-status { font-size: 0.9rem; margin-top: 14px; display: none; padding: 12px 14px; border-radius: var(--radius-sm); }
.form-status.ok { display: block; background: #e7f3ec; color: var(--color-success); }
.form-status.err { display: block; background: #fbeaea; color: #a02f2f; }

/* ---------- Footer ---------- */
.site-footer {
  background: var(--color-navy);
  color: #b9c3d0;
  padding: 36px 0 16px;
  position: relative;
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid rgba(255,255,255,0.1);
}
.footer-grid p { font-size: 0.88rem; margin-bottom: 0; }
.site-footer h4 { color: #fff; font-size: 0.9rem; margin-bottom: 8px; font-family: var(--font-body); }
.site-footer ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 6px; }
.site-footer a { text-decoration: none; color: #b9c3d0; font-size: 0.87rem; }
.site-footer a:hover { color: #fff; }
.footer-brand { display: flex; align-items: center; gap: 10px; font-family: var(--font-display); font-size: 1.05rem; color: #fff; margin-bottom: 8px; text-decoration: none; }
.footer-brand-img { height: 24px; width: auto; display: block; flex: none; }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 12px;
  font-size: 0.8rem;
  color: #7c8ba0;
  flex-wrap: wrap;
  gap: 8px;
}
/* Below 900px, pairing the brand block against "Explore" in one grid
   row forced that row's height to match whichever of the two was
   taller — since the brand block (logo + a wrapped paragraph) and a
   short link list are very different heights, that left a large empty
   gap under the shorter one before the next row started. Giving the
   brand block its own full-width row means "Explore" and "Get in
   touch" (similar, short heights) sit evenly side by side underneath
   instead. Font sizes and gaps are also trimmed further at this width
   — a footer that's a quarter of the browser window on a
   half-screen/tablet-width browser is still disproportionate even
   without the row-mismatch bug. */
@media (max-width: 900px) {
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 20px; row-gap: 20px; }
  .footer-grid > div:first-child { grid-column: 1 / -1; }
  .footer-grid p { max-width: none !important; }
  .site-footer h4 { font-size: 0.85rem; margin-bottom: 6px; }
  .site-footer ul { gap: 5px; }
  .site-footer a { font-size: 0.83rem; }
}
/* Raised from 480px to 600px: on a real phone (as opposed to a resized
   desktop browser), "Explore" and "Get in touch" were still landing
   side-by-side, half-width each, at widths just above 480px — cramped,
   and it stretched the footer's overall height. Below 600px both columns
   now stack full-width instead, and the section's own padding is
   trimmed further so the stack doesn't take up an outsized share of
   the screen on mobile. */
/* Mobile footer, take two: rather than stacking every block full-width
   (tall), the brand block keeps its own compact top row, and the
   remaining height is split 50/50 into two columns — "Get in touch" on
   the left, "Explore" on the right — using `order` to reposition them
   without touching the HTML (they're 2nd/3rd in the markup). Sizes are
   trimmed hard across the board so the whole footer takes roughly half
   the vertical space it did before on a phone. */
@media (max-width: 600px) {
  .site-footer { padding: 18px 0 10px; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 10px 16px; padding-bottom: 12px; }
  /* Link columns first (order 1/2), brand block last (order 3) and
     given its own full-width row underneath them. */
  .footer-grid > div:first-child { grid-column: 1 / -1; order: 3; margin-top: 4px; }
  .footer-grid > div:nth-child(2) { order: 2; text-align: right; }
  .footer-grid > div:nth-child(3) { order: 1; }
  .footer-grid > div:nth-child(2) ul { justify-items: end; }
  .footer-brand { font-size: 0.92rem; margin-bottom: 4px; }
  .footer-brand-img { height: 18px; }
  .footer-grid > div:first-child p { font-size: 0.76rem; margin-bottom: 0; }
  .site-footer h4 { font-size: 0.76rem; margin-bottom: 4px; }
  .site-footer ul { gap: 3px; }
  .site-footer a { font-size: 0.76rem; }
  .footer-bottom { padding-top: 8px; font-size: 0.72rem; }
}

/* ---------- Page hero (inner pages) ---------- */
.page-hero { padding: 40px 0 32px; position: relative; overflow: clip; }
.page-hero .eyebrow { }
.page-hero > .container { position: relative; z-index: 1; }
/* An optional abstract decorative graphic for a page-hero — concentric
   arcs, aria-hidden, colour-varied per page via a modifier class.
   Pure SVG strokes, no filter, so it costs nothing on scroll. */
.page-hero-graphic {
  position: absolute;
  top: 50%;
  right: 6%;
  transform: translateY(-50%);
  z-index: 0;
  pointer-events: none;
  opacity: 0.9;
}
@media (max-width: 1000px) { .page-hero-graphic { display: none; } }
.breadcrumb { font-size: 0.85rem; color: var(--color-ink-soft); margin-bottom: 18px; }
.breadcrumb a { text-decoration: none; color: var(--color-ink-soft); }
.breadcrumb a:hover { color: var(--color-navy); }

/* ---------- Reveal animation ----------
   Pure CSS, no JS or scroll-position dependency: every .reveal
   element fades up once, shortly after the page paints. This keeps
   content visible in every context — JS disabled, slow scripts,
   screen readers, print, or automated rendering — since visibility
   never depends on scrolling or script execution succeeding. */
@keyframes reveal-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.reveal {
  animation: reveal-in 0.7s var(--ease-elegant) both;
  animation-delay: 0.05s;
}

/* In browsers that support scroll-driven animations, layer on a
   SECOND animation that adds scroll-linked slide/scale motion, so
   elements below the fold visibly arrive as they're scrolled into
   view rather than all firing together on paint. Opacity is
   deliberately left to the time-based reveal-in animation above,
   never to this one — so even somewhere this scroll-linked motion
   can't resolve properly (printing a page, a crawler or screenshot
   tool that renders without scrolling, an old engine that partially
   supports the spec) the absolute worst case is fully-opaque text
   sitting a few pixels off its final position, never invisible
   content. That guarantee is worth more than the extra polish, so
   it's kept even though it means opacity and motion are no longer a
   single animation. */
@supports (animation-timeline: view()) {
  .reveal {
    animation: reveal-in 0.7s var(--ease-elegant) both, reveal-slide linear both;
    animation-delay: 0.05s, 0s;
    animation-timeline: auto, view();
    animation-range: normal, entry 0% entry 55%;
  }
}
@keyframes reveal-slide {
  from { transform: translateY(30px) scale(0.985); }
  to   { transform: translateY(0) scale(1); }
}
@media print {
  .reveal { animation: none !important; opacity: 1 !important; transform: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .reveal { animation: none; opacity: 1; transform: none; }
}

/* ---------- Prose (blog posts) ---------- */
/* Narrowed from 720px: at that width with this body type, a line ran
   to roughly 85-90 characters — noticeably past the ~65-75 character
   measure that's generally considered comfortable to read, and part
   of why the long-form blog pages felt denser than the rest of the
   site. */
.prose { max-width: 660px; margin: 0 auto; }
.prose p { line-height: 1.75; }
.prose h2 { margin-top: 1.8em; }
.prose h3 { margin-top: 1.4em; }
.prose ul, .prose ol { color: var(--color-ink-soft); padding-left: 1.2em; }
.prose li { margin-bottom: 0.5em; }
.prose blockquote {
  margin: 1.6em 0;
  padding: 4px 0 4px 20px;
  border-left: 3px solid var(--color-gold);
  color: var(--color-ink-soft);
  font-style: italic;
}
.prose .callout {
  background: var(--color-gold-tint);
  border: 1px solid #ecd9b8;
  border-radius: var(--radius-md);
  padding: 20px 22px;
  margin: 1.8em 0;
}
.prose .callout p:last-child { margin-bottom: 0; }

/* "At a glance" quick-facts box for Insights articles — a frosted
   glass panel with a topic-coloured accent edge, giving readers the
   single most useful takeaway without reading the full piece. */
.quick-facts {
  --accent: var(--color-gold);
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-md);
  padding: 22px 24px;
  margin: 1.8em 0;
  box-shadow: var(--shadow-sm);
  transition: transform 0.4s var(--ease-elegant), box-shadow 0.4s var(--ease-elegant);
}
.quick-facts:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.quick-facts h3 {
  margin: 0 0 12px; font-size: 0.78rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent);
}
.quick-facts ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.quick-facts li { padding-left: 26px; position: relative; color: var(--color-ink); }
.quick-facts li::before {
  content: "✓"; position: absolute; left: 0; top: 0.05em;
  color: var(--accent); font-weight: 700; font-size: 0.9em;
}
.quick-facts.accent-blue   { --accent: var(--color-blue); }
.quick-facts.accent-teal    { --accent: var(--color-teal); }
.quick-facts.accent-terracotta { --accent: var(--color-terracotta); }
.quick-facts.accent-plum    { --accent: var(--color-plum); }
.quick-facts.accent-navy    { --accent: var(--color-navy); }

.post-meta { display: flex; gap: 14px; align-items: center; color: var(--color-ink-soft); font-size: 0.88rem; margin-bottom: 8px; }
/* .post-tags always takes its own full flex line inside .card (basis
   100%), so a post's topic tag(s) sit on their own row above the
   heading in every case — one tag or two — rather than a single short
   tag sitting beside the heading with a big gap while two tags happen
   to wrap onto their own row. Tags inside are real <button>s (not
   nested inside the card's link, which the stretched-link pattern
   below replaces) so each one is independently clickable to jump
   straight to that topic filter. */
.card .post-tags {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 4px;
  position: relative;
  z-index: 2;
}
.post-tag {
  display: inline-block;
  font-size: 0.74rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-gold); background: var(--color-gold-tint); padding: 4px 10px; border-radius: 999px;
  border: none; font-family: inherit; cursor: pointer; text-decoration: none;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.post-tag:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(16,27,45,0.16); }
.post-tag:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 2px; }
/* Whole-card click target without nesting an <a> inside another <a>
   (the .post-tag buttons need to be independently clickable): the
   heading's own link is stretched to cover the entire card via
   ::after, sitting at a lower z-index than the tag buttons above. */
.card h3 a.stretched-link {
  color: inherit;
  text-decoration: none;
}
.card h3 a.stretched-link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}
/* Each Insights topic gets its own accent from the secondary palette,
   so the blog grid and filter chips read with more colour and are
   easier to tell apart at a glance. */
.post-tag.tag-mtd   { color: var(--color-blue);       background: var(--color-blue-tint); }
.post-tag.tag-vat   { color: var(--color-teal);       background: var(--color-teal-tint); }
.post-tag.tag-book  { color: var(--color-terracotta); background: var(--color-terracotta-tint); }
.post-tag.tag-pay   { color: var(--color-plum);       background: var(--color-plum-tint); }
.post-tag.tag-cosec { color: var(--color-navy);       background: #e7eaf0; }
.post-tag.tag-adv   { color: var(--color-teal);       background: var(--color-teal-tint); }

/* ---------- Misc ---------- */
.badge-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
.badge {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.82rem; color: var(--color-ink-soft);
  border: 1px solid var(--color-line); background: #fff;
  padding: 7px 13px; border-radius: 999px;
}
.divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--color-line) 25%, var(--color-line) 75%, transparent);
  margin: 0;
  border: none;
  position: relative;
  z-index: 1;
}

.upload-steps { display: grid; gap: 18px; }
.upload-step { display: flex; gap: 16px; align-items: flex-start; }
/* Previously had no explicit size at all, so it fell back to the
   browser's default h4 (~1.33em, larger than every other small
   heading on the site) instead of matching .hero-card h4's 1rem —
   the same "small heading beside a body paragraph" pattern used
   elsewhere (About, Contact, homepage hero). */
.upload-step h4 { font-size: 1rem; }
.upload-step .n {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--color-navy); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.85rem; font-weight: 700; flex: none;
}

.security-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 900px) { .security-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .security-grid { grid-template-columns: 1fr; } }

/* ---------- Insights filter bar ---------- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  margin-bottom: 40px;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--color-line);
}
.filter-search {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 10px 16px;
  color: var(--color-ink-soft);
  flex: 0 1 260px;
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.filter-search:focus-within { border-color: var(--color-gold-soft); box-shadow: 0 0 0 3px var(--color-gold-tint); }
.filter-search input {
  border: none; padding: 0; background: transparent; font-size: 0.92rem;
  width: 100%;
}
.filter-search input:focus { outline: none; box-shadow: none; }
.filter-chips { display: flex; flex-wrap: wrap; gap: 8px; flex: 1 1 auto; }
.chip {
  font-size: 0.84rem;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg-soft);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  color: var(--color-ink-soft);
  cursor: pointer;
  transition: all 0.3s var(--ease-elegant);
  white-space: nowrap;
}
.chip:hover { border-color: var(--color-gold-soft); color: var(--color-navy); transform: translateY(-1px); }
.chip.is-active { background: var(--color-navy); border-color: var(--color-navy); color: #fff; }
#postGrid .card[hidden] { display: none !important; }

/* ---------- Two-column split layouts (About / Contact) ----------
   Previously set with an inline style="grid-template-columns:..." on
   the page itself, which meant there was no way to add a responsive
   breakpoint — on narrow screens the two columns stayed forced side
   by side, squeezed well below their content's minimum width, so
   text and cards visually overlapped instead of stacking. These
   classes carry the same column ratios but collapse to a single
   column on mobile like every other grid on the site. */
.split-equal {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: center;
}
.split-wide {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 48px;
  align-items: flex-start;
}
@media (max-width: 900px) {
  .split-equal, .split-wide { grid-template-columns: 1fr; }
}

/* ---------- Services page: heading + service cards row ----------
   Each services.html section pairs a numbered heading with a grid of
   service cards. On mobile the heading now sits full-width above the
   cards (rather than being squeezed into a narrow side column), and
   the cards themselves stay in a 2-column grid instead of collapsing
   to one, per how the client wants the services list to read on a
   phone. */
.services-row {
  display: grid;
  grid-template-columns: 0.9fr 2fr;
  gap: 40px;
}
/* Was a one-off inline style="font-size:1.6rem" repeated on all 5
   numbered headings on this page — moved to a class so it's a
   deliberate, named size in the type scale (a "sub-section heading",
   between the site's default h2 and h3) rather than a magic number
   duplicated five times. */
.section-num-heading { font-size: 1.6rem; }
@media (max-width: 900px) {
  .services-row { grid-template-columns: 1fr; gap: 20px; }
}
.services-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}
@media (max-width: 480px) {
  .services-cards { gap: 14px; }
}

/* ---------- Services grid (homepage) ---------- */
/* Evenly matched tiles — no single service is sized or styled as more
   important than the others. */
.services-bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
.services-bento > .reveal:nth-child(1) { animation-delay: 0.05s; }
.services-bento > .reveal:nth-child(2) { animation-delay: 0.12s; }
.services-bento > .reveal:nth-child(3) { animation-delay: 0.19s; }
.services-bento > .reveal:nth-child(4) { animation-delay: 0.26s; }
.services-bento > .reveal:nth-child(5) { animation-delay: 0.33s; }
.services-bento > .reveal:nth-child(6) { animation-delay: 0.4s; }
@media (max-width: 900px) {
  .services-bento { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .services-bento { grid-template-columns: 1fr; }
}

/* ---------- FAQ accordion ---------- */
.faq-list { display: grid; gap: 16px; max-width: 760px; margin: 0 auto; }
.faq-item {
  background: var(--color-paper-2);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: border-color 0.3s var(--ease-elegant), box-shadow 0.3s var(--ease-elegant), transform 0.3s var(--ease-elegant);
}
.faq-item[open] { border-color: #d8d6cf; box-shadow: var(--shadow-sm); }
.faq-item summary {
  list-style: none;
  cursor: pointer;
  padding: 20px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-weight: 600;
  color: var(--color-navy);
  font-family: var(--font-display);
  font-size: 1.05rem;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "";
  width: 9px; height: 9px;
  border-right: 2px solid var(--color-gold);
  border-bottom: 2px solid var(--color-gold);
  transform: rotate(45deg);
  transition: transform 0.35s var(--ease-elegant);
  flex: none;
}
.faq-item[open] summary::after { transform: rotate(-135deg); }
.faq-item:hover { border-color: var(--color-gold-soft); }
.faq-item .faq-body { padding: 0 24px 22px; color: var(--color-ink-soft); }
.faq-item .faq-body p:last-child { margin-bottom: 0; }
.faq-item[open] .faq-body { animation: faq-in 0.35s ease; }
@keyframes faq-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .faq-item, .faq-item summary::after { transition: none; }
  .faq-item[open] .faq-body { animation: none; }
}

/* ---------- Floating quote CTA (injected by main.js on every page) ---------- */
.floating-cta {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 200;
  display: flex;
  align-items: center;
  gap: 10px;
  opacity: 0;
  transform: translateY(16px) scale(0.98);
  pointer-events: none;
  transition: opacity 0.4s var(--ease-elegant), transform 0.4s var(--ease-elegant);
}
.floating-cta.is-visible { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.floating-cta .btn { box-shadow: var(--shadow-lg); }
.floating-cta-close {
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg-soft);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  color: var(--color-ink-soft);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-sm);
  padding: 0;
  transition: transform 0.3s var(--ease-elegant), color 0.2s ease;
}
.floating-cta-close:hover { color: var(--color-navy); transform: scale(1.08); }
@media (max-width: 560px) {
  .floating-cta { right: 14px; bottom: 14px; }
  .floating-cta .btn { padding: 11px 18px; font-size: 0.88rem; }
}
@media (prefers-reduced-motion: reduce) {
  .floating-cta, .floating-cta-close { transition: none; }
}

/* ---------- Scroll progress bar (injected by main.js on every page) ---------- */
.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 100%;
  background: linear-gradient(90deg, var(--color-gold), var(--color-gold-soft));
  z-index: 300;
  transform: scaleX(0);
  transform-origin: left;
  pointer-events: none;
}

/* ---------- Glass utility ---------- */
.glass {
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
}
