/* ==========================================================================
   JWA Digital — stylesheet
   Structure: 1. Custom properties  2. Reset/base  3. Typography  4. Layout
   utilities  5. Header/nav  6. Buttons  7. Hero  8. Section heading  9. Cards
   (founders/pricing/projects)  10. Contact  11. Footer  12. Scroll-reveal
   13. Responsive
   ========================================================================== */

/* 1. Custom properties -------------------------------------------------- */
/* Brand palette (2026 refresh): Slate (primary text/footer) / White (base) /
   Sky (accent + highlights) / Linen (secondary base). Token names kept from
   the old navy/icy-blue palette to avoid a sitewide variable-name rename;
   only the hex values changed.
   --color-oxford-navy / --color-text-dark = #3B4E5E, the one and only text
   colour on the site now (no more near-black anywhere).
   --color-icy-blue / --color-charcoal-blue used to be a single dark-slate
   accent; they now split roles instead of sharing one value:
     - --color-icy-blue is the true accent, #A7C8E8 - buttons, tags, badges,
       borders, focus rings, underlines. #A7C8E8 is a pale sky blue with
       only ~1.7:1 contrast against white, so it is NEVER used as a colour
       for body/caption/label text sitting on a light surface - only as a
       fill/border/background, or as text on a dark (--color-oxford-navy)
       surface where it reads at ~5:1.
     - --color-charcoal-blue is now a muted tint of the primary text colour
       (70% opacity slate), used everywhere secondary/caption text needs to
       read as "quieter than a heading" while keeping real contrast on
       white - it replaces every previous body-text use of the shared
       accent value. */
:root {
  --color-oxford-navy: #3B4E5E;
  --color-charcoal-blue: rgba(59, 78, 94, 0.7);
  --color-icy-blue: #A7C8E8;
  --color-mint-cream: #F5F3EE;
  --color-white: #FFFFFF;
  --color-text-dark: #3B4E5E;

  --font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-serif: 'Playfair Display', Georgia, serif;
  --font-display: 'Anton', var(--font-sans);

  --header-height: 88px;
  /* One radius sitewide, matching the What We Offer cards - the three
     names are kept (hundreds of existing references) but all resolve to
     the same value now instead of three different corner roundings. */
  --radius-lg: 18px;
  --radius-md: var(--radius-lg);
  --radius-sm: var(--radius-lg);
  --shadow-card: 0 4px 20px rgba(59, 78, 94, 0.08);
  --shadow-card-hover: 0 10px 30px rgba(59, 78, 94, 0.14);
  --transition-base: 0.25s ease;
  --max-width: 1180px;
}

/* 2. Reset / base -------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
}
body {
  margin: 0;
  /* Flat secondary-base fill, no gradient - the original subtle grain
     texture (inline SVG noise, no image request) is kept for a touch of
     tactility, but the coloured gradient blobs are gone. */
  background-color: var(--color-mint-cream);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.025'/%3E%3C/svg%3E");
  background-repeat: repeat;
  color: var(--color-text-dark);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
h1, h2, h3, h4 { margin: 0; font-family: var(--font-sans); color: var(--color-oxford-navy); line-height: 1.2; }
p { margin: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* Focus visibility for keyboard users */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 3px solid var(--color-icy-blue);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--color-oxford-navy);
  color: var(--color-white);
  padding: 0.75rem 1.25rem;
  z-index: 1000;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus {
  left: 0;
}

/* Fixed scroll-progress bar, filled by JS in main.js */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  z-index: 300;
  background: transparent;
}
.scroll-progress-bar {
  height: 100%;
  width: 0%;
  background: var(--color-icy-blue);
}

/* Intro animation: plays once on page load, pure CSS (no JS dependency
   means it can never get stuck open if a script fails). */
.intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-oxford-navy);
  overflow: hidden;
  animation: intro-exit 0.7s cubic-bezier(0.6, 0, 0.4, 1) forwards;
  animation-delay: 1.5s;
}
.intro-tagline {
  font-family: var(--font-display);
  text-transform: uppercase;
  text-align: center;
  font-size: clamp(2rem, 7vw, 4.5rem);
  line-height: 1.05;
  color: var(--color-white);
}
.intro-line {
  display: block;
  overflow: hidden;
  white-space: nowrap;
}
.intro-line span {
  display: block;
  transform: translateY(110%);
  animation: intro-line-up 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: 0.2s;
}
.intro-line:last-child span {
  animation-delay: 0.38s;
}
.tagline-emphasis {
  display: inline-block;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 800;
  text-transform: none;
  color: var(--color-oxford-navy);
  font-size: 1.25em;
  border-bottom: 3px solid var(--color-icy-blue);
  padding-bottom: 0.04em;
}
/* Reused inside .intro-overlay's dark background (see palette note
   at the top of this file) - the italic serif already distinguishes it
   from the surrounding uppercase display type, no colour needed here. */
.intro-tagline .tagline-emphasis {
  color: var(--color-white);
  border-bottom: none;
}
@keyframes intro-line-up {
  to { transform: translateY(0); }
}
@keyframes intro-exit {
  to {
    opacity: 0;
    transform: translateY(-100%);
    visibility: hidden;
    pointer-events: none;
  }
}
/* Set by js/intro-gate.js (a blocking script, first thing in <head>) once
   this session has already seen the intro once - skips it outright rather
   than fading it out, and zeroes the hero's reveal delays below (which
   exist purely to wait for the intro to finish lifting away) so the page
   doesn't sit on a multi-second dead pause with nothing to wait for. */
html.intro-skipped .intro-overlay { display: none; }
html.intro-skipped .hero-headline.reveal,
html.intro-skipped .hero-subline.reveal,
html.intro-skipped .hero-actions.reveal,
html.intro-skipped .hero-scroll-cue.reveal { transition-delay: 0s; }

/* 3. Typography ----------------------------------------------------------- */
.overline {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-oxford-navy);
  margin: 0 0 0.9rem;
  padding: 0.35rem 0.9rem;
  border: 1px solid rgba(59, 78, 94, 0.16);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.section-heading--light .overline {
  color: var(--color-white);
  border-color: rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.08);
}

.underline-accent {
  display: block;
  width: 56px;
  height: 4px;
  margin-top: 0.4rem;
  background: var(--color-icy-blue);
  border-radius: 2px;
}
.section-heading--light .underline-accent {
  background: var(--color-white); /* dark-section: avoid icy-blue, see palette note */
}

/* 4. Layout utilities ------------------------------------------------------ */
.container {
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: 1.5rem;
}
.section {
  padding-block: clamp(2.25rem, 4.5vw, 4rem);
  scroll-margin-top: var(--header-height);
}
.section-dark {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}
.section-heading {
  max-width: 700px;
  margin-bottom: 1.75rem;
  overflow: hidden;
}
.section-heading h1,
.section-heading h2 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 0.95;
  font-size: clamp(2.6rem, 6.5vw, 5.5rem);
}
.section-heading--light h1,
.section-heading--light h2 { color: var(--color-white); }

/* Bigger scroll-reveal specifically for headings: a slower, larger rise
   than the standard .reveal fade used elsewhere on the page. */
.reveal-heading {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.38s cubic-bezier(0.16, 1, 0.3, 1), transform 0.38s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal-heading.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.section-intro {
  max-width: 640px;
  font-size: 1.125rem;
  color: var(--color-charcoal-blue);
  margin-bottom: 2.5rem;
}

/* 5. Header / nav ----------------------------------------------------------- */
/* Floats a fixed gap below the very top of the viewport rather than sitting
   flush against it, and stays full-width at every scroll position so page
   content is never blurred at the sides - only background opacity/shadow
   change on scroll (paint-only, no layout-affecting properties), since
   animating height/width here previously caused visible shake while
   scrolling on a sticky + backdrop-filter element. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--header-height);
  display: flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.45);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.5);
  transition: box-shadow var(--transition-base), background var(--transition-base);
}
.site-header.is-scrolled {
  background: rgba(255, 255, 255, 0.65);
  box-shadow: 0 8px 24px rgba(59, 78, 94, 0.1);
}
/* On the page with the hero video, the header stays fully transparent
   until scrolled, so the video reads full-bleed with only the nav
   elements themselves floating over it. */
body:has(.hero-video) .site-header:not(.is-scrolled) {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom-color: transparent;
}
/* The navy logo/nav links/CTA are tuned for a light header background -
   floating transparent over the dark hero overlay, they need to flip to
   light so they stay legible against the video rather than blending in. */
body:has(.hero-video) .site-header:not(.is-scrolled) .logo-mark {
  filter: brightness(0) invert(1);
}
/* Desktop only - below 769px the nav links live inside the mobile
   dropdown panel, which has its own solid light background (see the
   768px breakpoint further down) regardless of header-scroll state, so
   forcing white text there made them unreadable (white-on-light). */
@media (min-width: 769px) {
  body:has(.hero-video) .site-header:not(.is-scrolled) .primary-nav a:not(.btn) {
    color: rgba(255, 255, 255, 0.92);
  }
  body:has(.hero-video) .site-header:not(.is-scrolled) .primary-nav a:not(.btn):hover,
  body:has(.hero-video) .site-header:not(.is-scrolled) .primary-nav a:not(.btn):focus-visible {
    color: var(--color-white);
  }
}
body:has(.hero-video) .site-header:not(.is-scrolled) .nav-cta.btn-primary {
  background: var(--color-white);
  border-color: var(--color-white);
  color: var(--color-oxford-navy);
}
body:has(.hero-video) .site-header:not(.is-scrolled) .nav-cta.btn-primary:hover,
body:has(.hero-video) .site-header:not(.is-scrolled) .nav-cta.btn-primary:focus-visible {
  background: var(--color-mint-cream);
  border-color: var(--color-mint-cream);
  color: var(--color-oxford-navy);
}
body:has(.hero-video) .site-header:not(.is-scrolled) .nav-toggle-bar {
  background: var(--color-white);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}
.logo-mark {
  flex-shrink: 0;
  object-fit: contain;
}
.logo-wordmark {
  font-family: var(--font-sans);
  font-weight: 800;
  letter-spacing: 0.06em;
  font-size: 1.05rem;
  color: var(--color-oxford-navy);
  white-space: nowrap;
}
.logo-wordmark span { color: var(--color-charcoal-blue); }
.logo-footer .logo-wordmark,
.logo-footer .logo-wordmark span { color: var(--color-white); }

.primary-nav {
  display: flex;
  align-items: center;
  gap: 2rem;
}
.primary-nav ul {
  display: flex;
  gap: 1.75rem;
}
.primary-nav a:not(.btn) {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--color-charcoal-blue);
  position: relative;
  padding-bottom: 4px;
  transition: color var(--transition-base);
}
.primary-nav a:not(.btn):hover,
.primary-nav a:not(.btn):focus-visible {
  color: var(--color-oxford-navy);
}
.primary-nav a:not(.btn)::after {
  content: '';
  position: absolute;
  left: 0; right: 100%;
  bottom: 0;
  height: 2px;
  background: var(--color-icy-blue);
  transition: right var(--transition-base);
}
.primary-nav a:not(.btn):hover::after,
.primary-nav a:not(.btn):focus-visible::after {
  right: 0;
}

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  background: transparent;
  border: none;
  padding: 0;
}
.nav-toggle-bar {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--color-oxford-navy);
  border-radius: 2px;
  transition: transform var(--transition-base), opacity var(--transition-base);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* 6. Buttons ---------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.6rem;
  border-radius: var(--radius-md);
  font-weight: 700;
  font-size: 0.95rem;
  border: 2px solid transparent;
  transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base), transform var(--transition-base);
  white-space: nowrap;
}
.btn-arrow {
  flex-shrink: 0;
  transition: transform 0.2s ease;
}
.btn:hover .btn-arrow,
.btn:focus-visible .btn-arrow {
  transform: translateX(3px);
}
/* Without this, a disabled button (e.g. "Confirming...", a locked "Sent"
   state) is pixel-identical to an active one - same background, same
   opacity, same pointer cursor - since author colour rules override the
   browser's own disabled styling. */
.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.btn:disabled:hover {
  transform: none;
}
/* Without this, .btn's own display:inline-flex (same specificity, later in
   source than the browser default) beats [hidden] and a hidden button
   stays visible - same class of bug as the [hidden] fixes elsewhere in
   this file. */
.btn[hidden] {
  display: none;
}
.btn:hover { transform: translateY(-2px); }

.btn-primary {
  background: var(--color-oxford-navy);
  color: var(--color-white);
  border-color: var(--color-oxford-navy);
  border-radius: var(--radius-sm);
  box-shadow: none;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.btn-primary:hover,
.btn-primary:focus-visible {
  background: #2E3E4B;
  border-color: #2E3E4B;
  color: var(--color-white);
  box-shadow: none;
  transform: translateY(-1px);
}

/* Ghost button for use on the light hero background */
.btn-ghost {
  background: transparent;
  border-color: var(--color-oxford-navy);
  color: var(--color-oxford-navy);
}
.btn-ghost:hover,
.btn-ghost:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}
/* Ghost button variant for use on dark/navy section backgrounds */
.section-dark .btn-ghost {
  border-color: var(--color-white);
  color: var(--color-white);
}
.section-dark .btn-ghost:hover,
.section-dark .btn-ghost:focus-visible {
  background: var(--color-white);
  color: var(--color-oxford-navy);
}

/* Outline button for use on light cards */
.btn-outline {
  background: transparent;
  border-color: var(--color-oxford-navy);
  color: var(--color-oxford-navy);
  margin-top: auto;
}
.btn-outline:hover,
.btn-outline:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}

/* Primary button variant for use on dark/navy card or section backgrounds.
   The pale accent blue doesn't read on the dark-slate section background
   (see palette note above), so this is white with dark text instead, same
   as every other dark-section button already is. */
.btn-primary-inverse {
  background: var(--color-white);
  color: var(--color-oxford-navy);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 6px 18px rgba(59, 78, 94, 0.35);
  margin-top: auto;
}
.btn-primary-inverse:hover,
.btn-primary-inverse:focus-visible {
  background: var(--color-mint-cream);
  color: var(--color-oxford-navy);
  box-shadow: 0 8px 22px rgba(59, 78, 94, 0.4);
}

.nav-cta { padding: 0.55rem 1.1rem; font-size: 0.85rem; }

/* 7. Hero -------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  color: var(--color-text-dark);
  min-height: calc(100vh - var(--header-height));
  min-height: calc(100dvh - var(--header-height));
  display: flex;
  align-items: center;
  padding-block: clamp(1.5rem, 4vh, 2.5rem);
  /* Dot pattern shows while the video loads (and if it ever fails to). */
  background-image: radial-gradient(rgba(59, 78, 94, 0.09) 1px, transparent 1px);
  background-size: 28px 28px;
}
/* The header still reserves its own layout height above .hero, so without
   this the video would only start below the header bar (a visible seam)
   rather than truly filling the whole screen behind it. Pulling .hero up
   by the header's height and re-padding its content by the same amount
   lets the video (position:absolute, inset:0 within .hero) reach all the
   way to the real top of the viewport while the text stays clear of the
   floating nav. */
body:has(.hero-video) .hero {
  margin-top: calc(-1 * var(--header-height));
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: calc(var(--header-height) + clamp(1.5rem, 4vh, 2.5rem));
}
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
/* A dark wash (rather than the old light one) so white hero text stays
   legible over whatever the footage looks like at any given frame, while
   the video still reads through clearly. */
.hero-video-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(28, 38, 46, 0.6);
}
.hero-inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 760px;
  margin-inline: auto;
  text-align: center;
}

.hero-headline {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  font-size: clamp(2.6rem, 6.5vw, 5rem);
  line-height: 0.95;
  color: var(--color-white);
  margin-bottom: 1.25rem;
}
.hero-headline-line1 {
  display: block;
  white-space: nowrap;
}
.hero-headline-break {
  display: block;
  color: var(--color-white);
  white-space: nowrap;
}
.hero-subline {
  font-size: clamp(1.1rem, 2vw, 1.4rem);
  font-weight: 600;
  color: var(--color-white);
  max-width: 480px;
  margin-inline: auto;
  margin-bottom: 2rem;
}
/* Hero sits on the dark video overlay above - the ghost "Back" button and
   scroll-cue circle are styled dark-on-light everywhere else on the site
   (see .btn-ghost, .hero-scroll-cue base rules), so both need inverting
   just here. */
body:has(.hero-video) .hero .btn-ghost {
  border-color: rgba(255, 255, 255, 0.7);
  color: var(--color-white);
}
body:has(.hero-video) .hero .btn-ghost:hover,
body:has(.hero-video) .hero .btn-ghost:focus-visible {
  background: var(--color-white);
  border-color: var(--color-white);
  color: var(--color-oxford-navy);
}
/* .btn-primary is now navy-on-navy against this dark overlay - swap to
   white so the hero's one primary CTA still pops. */
body:has(.hero-video) .hero .btn-primary {
  background: var(--color-white);
  border-color: var(--color-white);
  color: var(--color-oxford-navy);
}
body:has(.hero-video) .hero .btn-primary:hover,
body:has(.hero-video) .hero .btn-primary:focus-visible {
  background: var(--color-mint-cream);
  border-color: var(--color-mint-cream);
  color: var(--color-oxford-navy);
}
.hero-headline .tagline-emphasis {
  color: var(--color-white);
  border-bottom-color: rgba(255, 255, 255, 0.6);
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
}

/* Startup animation: hero content cascades in on page load, staggered
   via transition-delay — timed to start only once the intro overlay
   (1.5s delay + 0.7s exit = 2.2s) has fully lifted away, so the page
   doesn't just "snap" to fully visible the instant the curtain clears. */
.hero-headline.reveal { transition-delay: 2.3s; }
.hero-subline.reveal { transition-delay: 2.45s; }
.hero-actions.reveal { transition-delay: 2.6s; }
.hero-scroll-cue.reveal { transition-delay: 2.75s; }

.hero-scroll-cue {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-top: 2.75rem;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  color: var(--color-white);
  animation: hero-scroll-pulse 2s ease-in-out infinite;
  transition: background var(--transition-base), border-color var(--transition-base);
}
.hero-scroll-cue:hover,
.hero-scroll-cue:focus-visible {
  background: var(--color-white);
  border-color: var(--color-white);
  color: var(--color-oxford-navy);
}
@keyframes hero-scroll-pulse {
  0%, 100% { transform: translateY(0); opacity: 0.6; }
  50% { transform: translateY(7px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-scroll-cue { animation: none; }
}

/* 9. Cards ------------------------------------------------------------------- */
.card {
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.65);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: 2rem;
  transition: box-shadow var(--transition-base), transform var(--transition-base), background var(--transition-base), border-color var(--transition-base);
}
/* .card.reveal:hover repeats the same rule at higher specificity - once a
   card has scrolled in, .reveal.is-visible (section 12) sets its own
   transform at equal specificity to plain .card:hover and, being later in
   the file, would silently cancel this lift on every revealed card.
   hover:hover-scoped so a tap on a touch device never matches a :hover
   selector here at all - if it did, iOS Safari would require a second tap
   to actually register the click on anything inside a .card that has one
   (e.g. .pricing-card, .feature-row). */
@media (hover: hover) {
  .card:hover,
  .card.reveal:hover {
    background: rgba(255, 255, 255, 0.72);
    border-color: rgba(255, 255, 255, 0.85);
    box-shadow: var(--shadow-card-hover);
    transform: translateY(-4px);
  }
}

/* Who We Are: fills one screen, content vertically centred within it */
#who-we-are {
  min-height: calc(100vh - var(--header-height));
  min-height: calc(100dvh - var(--header-height));
  display: flex;
  align-items: center;
}
#who-we-are .container { width: 100%; }

.founders-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem;
}
.founder-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
}
.avatar-photo {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: 1.25rem;
}
.founder-card h3 {
  font-size: 1.25rem;
  margin-bottom: 0.15rem;
}
.founder-card .role {
  font-weight: 600;
  color: var(--color-charcoal-blue);
  margin-bottom: 1rem;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.founder-card .bio {
  color: var(--color-text-dark);
}
.placeholder-copy {
  font-style: italic;
  color: var(--color-charcoal-blue);
}
.section-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 2rem;
}

/* about.html: extended bio rows */
.about-bio {
  display: flex;
  gap: 2rem;
  align-items: flex-start;
  padding: 2rem 0;
  border-bottom: 1px solid rgba(59, 78, 94, 0.12);
}
.about-bio:last-of-type { border-bottom: none; }
.about-bio .avatar-photo {
  width: 120px;
  height: 120px;
  flex-shrink: 0;
  margin-bottom: 0;
}
.about-bio-content h3 {
  font-size: 1.4rem;
  margin-bottom: 0.2rem;
}
.about-bio-content .role {
  font-weight: 600;
  color: var(--color-charcoal-blue);
  margin-bottom: 0.85rem;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.about-bio-content p:not(.role) {
  color: var(--color-text-dark);
  margin-bottom: 0.75rem;
}

/* Key-skill pills */
.about-skills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.25rem;
  margin-bottom: 1rem;
}
.skill-pill {
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  background: var(--color-mint-cream);
  border: 1px solid rgba(59, 78, 94, 0.1);
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--color-oxford-navy);
}

/* Founder social links: circular icon buttons + a branded WhatsApp pill */
.about-socials {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.about-social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  background: var(--color-mint-cream);
  color: var(--color-oxford-navy);
  transition: background var(--transition-base), color var(--transition-base);
}
.about-social-link:hover,
.about-social-link:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}

/* Shared WhatsApp-branded button - real WhatsApp green, reused on about.html
   founder cards and the Direct Connect demo on services.html. */
.whatsapp-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1.4rem;
  border-radius: 999px;
  background: #25D366;
  color: #ffffff;
  font-weight: 700;
  font-size: 0.9rem;
  border: none;
  line-height: 1;
  transition: background var(--transition-base), transform var(--transition-base);
}
.whatsapp-btn svg { flex-shrink: 0; }
.whatsapp-btn:hover,
.whatsapp-btn:focus-visible {
  background: #1ebe5a;
  transform: translateY(-2px);
  color: #ffffff;
}
/* Matches .about-social-link's 38px circle height so the row sits flush */
.whatsapp-btn--sm {
  height: 38px;
  padding: 0 0.9rem;
  font-size: 0.78rem;
  box-sizing: border-box;
}

/* services.html: full-service grid. Six cards embed a genuinely working
   widget (see js/service-demos.js); Websites and Updates and Support list
   what's included instead, since they're foundational/ongoing rather than
   a single testable interaction. */
.services-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
}
/* A grid item's automatic minimum size defaults to its content's
   min-content width, which can push a 1fr track wider than the track
   itself - without this, the card (and the whole grid) overflowed the
   viewport on mobile, forcing a pinch-zoom to see the rest of the page. */
.services-grid > * { min-width: 0; }
.service-card {
  display: flex;
  flex-direction: column;
}
.service-card h3 {
  font-size: 1.35rem;
  margin-bottom: 0.35rem;
}
.service-card-price {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.4rem;
}
.service-card p:not(.service-card-price):not(.demo-note) {
  font-size: 0.92rem;
  color: var(--color-text-dark);
  margin-bottom: 1.25rem;
}
.service-card .demo-widget,
.service-card .service-includes {
  margin-top: auto;
}

/* "What's included" list - reuses the same checkmark language as
   .tier-features on packages.html. */
.service-includes {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.service-includes li {
  position: relative;
  padding-left: 1.6rem;
  font-size: 0.9rem;
  color: var(--color-text-dark);
}
.service-includes li::before {
  content: '';
  position: absolute;
  left: 1px;
  top: 0.35em;
  width: 12px;
  height: 7px;
  border-left: 2px solid var(--color-icy-blue);
  border-bottom: 2px solid var(--color-icy-blue);
  transform: rotate(-45deg);
}

/* Shared demo-widget chrome */
.demo-widget {
  border-top: 1px solid rgba(59, 78, 94, 0.1);
  padding-top: 1.25rem;
}
.demo-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--color-oxford-navy);
  margin-bottom: 0.6rem;
}
.demo-note {
  font-size: 0.78rem;
  font-style: italic;
  color: var(--color-charcoal-blue);
  margin-top: 0.75rem;
  margin-bottom: 0 !important;
}
.demo-input {
  width: 100%;
  padding: 0.65rem 0.85rem;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(59, 78, 94, 0.18);
  background: var(--color-white);
  color: var(--color-oxford-navy);
  font-family: var(--font-sans);
  font-size: 0.9rem;
}
.demo-input:focus-visible {
  outline: 2px solid var(--color-icy-blue);
  outline-offset: 1px;
}

/* Real-time Reviews - fills its card like Smart Booking/AI Concierge do,
   and swipes/slides between reviews (translateX on the track, driven by
   js/service-demos.js) instead of an instant swap. */
.service-card .demo-widget.demo-reviews {
  margin-top: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.demo-reviews-viewport {
  flex: 1;
  overflow: hidden;
  border-radius: var(--radius-sm);
}
.demo-reviews-track {
  display: flex;
  height: 100%;
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .demo-reviews-track { transition: none; }
}
.demo-review {
  flex: 0 0 100%;
  min-width: 100%;
  box-sizing: border-box;
  padding: 1rem;
  background: var(--color-mint-cream);
  border: 1px solid rgba(59, 78, 94, 0.08);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.demo-review-header {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 0.6rem;
}
.demo-review-avatar {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 0.95rem;
  color: var(--color-white);
  background: var(--color-oxford-navy);
}
.demo-review:nth-child(2) .demo-review-avatar { background: var(--color-icy-blue); }
.demo-review:nth-child(3) .demo-review-avatar { background: #b8863f; }
.demo-review-stars {
  color: #d9a441;
  font-size: 1.05rem;
  letter-spacing: 0.12em;
  text-shadow: 0 1px 1px rgba(59, 78, 94, 0.1);
}
.demo-review-text {
  font-size: 0.9rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.35rem !important;
}
.demo-review-author {
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.1rem !important;
}
.demo-reviews-dots {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
}
.demo-reviews-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: none;
  padding: 0;
  background: rgba(59, 78, 94, 0.2);
  transition: background var(--transition-base), transform var(--transition-base);
}
.demo-reviews-dot.is-active {
  background: var(--color-oxford-navy);
  transform: scale(1.25);
}

/* Instant Quote Engine - guided step-by-step Q&A, real submission via
   /api/quote. Fills its card like Smart Booking/Real-time Reviews do. */
.service-card .demo-widget.demo-quote {
  margin-top: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
/* Smooth crossfade+slide between quote-engine steps/result, choreographed
   from JS (js/service-demos.js) via .is-leaving / .is-entering - see
   quoteSwap(). Skipped entirely for prefers-reduced-motion. */
.demo-quote-step,
.demo-quote-result {
  opacity: 1;
  transform: translateX(0) translateY(0);
  transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
.demo-quote-step.is-leaving {
  opacity: 0;
  transform: translateX(-14px);
}
.demo-quote-step.is-entering {
  opacity: 0;
  transform: translateX(14px);
}
.demo-quote-result.is-leaving {
  opacity: 0;
  transform: translateY(-10px);
}
.demo-quote-result.is-entering {
  opacity: 0;
  transform: translateY(10px);
}
.demo-quote-progress {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-charcoal-blue);
  margin-bottom: 0.5rem !important;
}
.demo-quote-question {
  display: block;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-oxford-navy);
  margin-bottom: 0.85rem !important;
}
.demo-quote-mc-grid {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.demo-quote-mc {
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  background: var(--color-white);
  color: var(--color-oxford-navy);
  font-size: 0.83rem;
  font-weight: 600;
  transform: scale(1);
  transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base), transform 0.2s ease;
}
.demo-quote-mc.is-active {
  background: var(--color-oxford-navy);
  border-color: var(--color-oxford-navy);
  color: var(--color-white);
  transform: scale(1.05);
}
.demo-quote-email-row {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.demo-quote-email-row .demo-input { flex: 1; min-width: 160px; }
.demo-quote-error {
  font-size: 0.8rem;
  color: #c0503f;
  margin-top: 0.6rem !important;
}
.demo-quote-result {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  align-items: flex-start;
}
.demo-quote-result[hidden] {
  display: none;
}
.demo-quote-result-figures {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.85rem 1rem;
  background: var(--color-oxford-navy);
  border-radius: var(--radius-sm);
  width: 100%;
  box-sizing: border-box;
}
.demo-quote-total {
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 1.4rem;
  color: var(--color-white);
}
.demo-quote-monthly {
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.75); /* dark-section: avoid icy-blue, see palette note */
}

/* Smart Booking - slot picker. Stretches to fill its card (rather than
   sitting at the bottom with a big empty gap like the other widgets),
   since its grid row is driven by AI Concierge's fixed-height chat log. */
.service-card .demo-widget.demo-booking {
  margin-top: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1rem;
}
.demo-booking-days,
.demo-booking-slots {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.demo-booking-days { margin-bottom: 0.75rem; }
.demo-booking-day,
.demo-booking-slot {
  padding: 0.45rem 0.85rem;
  border-radius: 999px;
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  background: var(--color-white);
  color: var(--color-oxford-navy);
  font-size: 0.85rem;
  font-weight: 600;
  transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base);
}
.demo-booking-day.is-active,
.demo-booking-slot.is-active {
  background: var(--color-oxford-navy);
  border-color: var(--color-oxford-navy);
  color: var(--color-white);
}
.demo-booking-confirm-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.demo-booking-confirm {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--color-oxford-navy);
  margin-top: 0.85rem;
  margin-bottom: 0 !important;
}
.demo-booking-confirm[hidden] { display: none; }

/* AI Concierge - chat. Fixed height (not max-height) so the log always
   scrolls internally instead of growing the card - a growing card here
   used to stretch the whole grid row and shove Smart Booking's slot
   picker down whenever a message was sent. */
.demo-chat-log {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: 140px;
  overflow-y: auto;
  margin-bottom: 0.75rem;
  padding-right: 0.25rem;
}
.demo-chat-msg {
  align-self: flex-start;
  max-width: 85%;
  padding: 0.55rem 0.8rem;
  border-radius: 12px 12px 12px 2px;
  background: var(--color-mint-cream);
  color: var(--color-oxford-navy);
  font-size: 0.85rem;
}
.demo-chat-msg--bot { background: var(--color-mint-cream); }
.demo-chat-msg--user {
  align-self: flex-end;
  background: var(--color-oxford-navy);
  color: var(--color-white);
  border-radius: 12px 12px 2px 12px;
}
.demo-chat-row {
  display: flex;
  gap: 0.5rem;
}
.demo-chat-row .demo-input { flex: 1; }
.demo-chat-send {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1.5px solid var(--color-oxford-navy);
  background: var(--color-white);
  color: var(--color-oxford-navy);
  transition: background var(--transition-base), color var(--transition-base);
}
.demo-chat-send:hover,
.demo-chat-send:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}

/* Elite Graphics - interactive showcase */
.demo-graphics-row {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  padding: 0.5rem 0;
}
.demo-graphics-btn {
  padding: 0.65rem 1.25rem;
  border-radius: 999px;
  border: none;
  background: var(--color-oxford-navy);
  color: var(--color-white);
  font-weight: 700;
  font-size: 0.85rem;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease;
}
.demo-graphics-btn:hover {
  transform: translateY(-3px) scale(1.05);
  box-shadow: 0 12px 24px -8px rgba(59, 78, 94, 0.4);
}
.demo-graphics-card {
  width: 96px;
  height: 64px;
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--color-icy-blue), var(--color-oxford-navy));
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-white);
  font-size: 0.78rem;
  font-weight: 700;
  transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
  transform-style: preserve-3d;
  will-change: transform;
}
.demo-graphics-card:hover,
.demo-graphics-card:focus-visible {
  box-shadow: 0 16px 28px -10px rgba(59, 78, 94, 0.45);
}
.demo-graphics-ripple {
  position: relative;
  overflow: hidden;
  padding: 0.65rem 1.25rem;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--color-oxford-navy);
  background: var(--color-white);
  color: var(--color-oxford-navy);
  font-weight: 700;
  font-size: 0.85rem;
}
.demo-graphics-ripple-effect {
  position: absolute;
  border-radius: 50%;
  background: rgba(167, 200, 232, 0.55);
  transform: scale(0);
  animation: demo-ripple 0.6s ease-out;
  pointer-events: none;
}
@keyframes demo-ripple {
  to { transform: scale(3); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .demo-graphics-btn,
  .demo-graphics-card { transition: none; }
  .demo-graphics-btn:hover { transform: none; }
  .demo-graphics-ripple-effect { animation: none; opacity: 0; }
}

/* Pricing / services */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  align-items: stretch;
}
/* The [hidden] attribute toggles these two views; without this override,
   the class-based `display` above would beat the browser's default
   `[hidden] { display: none }` rule and both views would show at once. */
#packages-view[hidden],
#feature-view[hidden] {
  display: none;
}
.pricing-card {
  display: flex;
  flex-direction: column;
  position: relative;
  cursor: pointer;
  border: 1px solid transparent;
  transition: box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1), transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.4s ease;
}
/* hover:hover only - .pricing-card is a click target (JS selects the
   package on tap, see js/main.js), and a :hover rule that matches it
   makes iOS Safari treat the first tap as a hover preview, requiring a
   second tap to actually register the click. Scoping the whole effect to
   real hover-capable pointers removes that ambiguity at the source. */
@media (hover: hover) {
  .pricing-card:hover,
  .pricing-card.reveal:hover {
    transform: translateY(-10px);
    box-shadow: 0 22px 48px rgba(59, 78, 94, 0.18);
    border-color: rgba(167, 200, 232, 0.7);
  }
  .pricing-card:hover .tier-number {
    color: var(--color-icy-blue);
    transform: translateX(2px);
  }
  .pricing-card--highlight:hover,
  .pricing-card--highlight.reveal:hover {
    box-shadow: 0 26px 56px rgba(59, 78, 94, 0.4);
    border-color: rgba(167, 200, 232, 0.5);
  }
}
.pricing-card.is-selected {
  box-shadow: 0 0 0 2px var(--color-oxford-navy), var(--shadow-card-hover);
}
.pricing-card--highlight.is-selected {
  box-shadow: 0 0 0 2px var(--color-icy-blue), 0 12px 36px rgba(59, 78, 94, 0.28);
}
.tier-number {
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 1.5rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.5rem;
  display: inline-block;
  transition: color 0.3s ease, transform 0.3s ease;
}
.tier-name {
  font-size: 1.4rem;
  margin-bottom: 0.4rem;
}
.tier-price {
  margin-bottom: 1rem;
}
.tier-price-main {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.tier-price-was {
  font-weight: 600;
  font-size: 1rem;
  color: var(--color-charcoal-blue);
  text-decoration: line-through;
  opacity: 0.75;
}
.tier-price-now {
  font-weight: 700;
  font-size: 1.3rem;
  color: var(--color-oxford-navy);
  display: inline-block;
  transition: transform 0.3s ease;
}
.pricing-card:hover .tier-price-now {
  transform: scale(1.06);
}
.tier-price-off {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: var(--color-icy-blue);
  color: var(--color-white);
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
}
.tier-price-monthly {
  font-weight: 500;
  font-size: 0.85rem;
  color: var(--color-charcoal-blue);
  margin-top: 0.3rem;
}
.tier-desc {
  margin-bottom: 1.25rem;
  color: var(--color-text-dark);
}
.tier-features {
  margin-bottom: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.tier-features li {
  position: relative;
  padding-left: 1.6rem;
  font-size: 0.95rem;
}
.tier-features li::before {
  content: '';
  position: absolute;
  left: 1px;
  top: 0.3em;
  width: 12px;
  height: 7px;
  border-left: 2px solid var(--color-icy-blue);
  border-bottom: 2px solid var(--color-icy-blue);
  transform: rotate(-45deg);
}
.tier-good-for {
  font-style: italic;
  font-size: 0.85rem;
  color: var(--color-charcoal-blue);
  margin-bottom: 1.5rem;
}

.pricing-card--highlight {
  background: var(--color-oxford-navy);
  color: var(--color-white);
  box-shadow: 0 12px 36px rgba(59, 78, 94, 0.28);
}
/* .pricing-card--highlight.reveal:hover repeats this at higher specificity
   - .card.reveal:hover (added for the hover-lift fix) would otherwise beat
   plain .pricing-card--highlight:hover once the card has scrolled in and
   carries .reveal, turning it white-on-white on hover. Only needs to
   exist under hover:hover, same as .card:hover above, which is the only
   thing it's correcting for. */
@media (hover: hover) {
  .pricing-card--highlight:hover,
  .pricing-card--highlight.reveal:hover {
    background: var(--color-oxford-navy);
  }
}
.pricing-card--highlight .tier-name,
.pricing-card--highlight .tier-desc,
.pricing-card--highlight .tier-price-now {
  color: var(--color-white);
}
/* dark-section: the default icy-blue tier-number is unreadable on this
   navy card, see palette note */
.pricing-card--highlight .tier-number {
  color: var(--color-white);
  -webkit-text-stroke: 0;
}
.pricing-card--highlight .tier-price-was { color: rgba(255, 255, 255, 0.6); }
.pricing-card--highlight .tier-price-monthly { color: rgba(255, 255, 255, 0.75); }
.pricing-card--highlight .tier-good-for { color: rgba(255, 255, 255, 0.75); }
.badge {
  position: absolute;
  top: -14px;
  right: 2rem;
  background: var(--color-icy-blue);
  color: var(--color-white);
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  box-shadow: 0 4px 10px rgba(59, 78, 94, 0.25);
}

/* Pricing toggle: Packages vs Pay-per-feature, with a sliding navy thumb
   whose position/width is measured in JS so it fits either label exactly. */
.pricing-toggle {
  position: relative;
  display: inline-flex;
  gap: 0.25rem;
  padding: 0.3rem;
  margin-bottom: 2.5rem;
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-radius: 999px;
}
.pricing-toggle-thumb {
  position: absolute;
  top: 0.3rem;
  left: 0;
  height: calc(100% - 0.6rem);
  width: 0;
  background: var(--color-oxford-navy);
  border-radius: 999px;
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), width 0.35s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 0;
}
.pricing-toggle-btn {
  position: relative;
  z-index: 1;
  border: none;
  background: transparent;
  color: var(--color-charcoal-blue);
  font-weight: 700;
  font-size: 0.9rem;
  padding: 0.6rem 1.25rem;
  border-radius: 999px;
  transition: color var(--transition-base);
}
.pricing-toggle-btn.is-active {
  color: var(--color-white);
}

/* Pay-per-feature builder — laid out like the What We Offer grid: a card
   per feature instead of a stacked list. */
.feature-builder {
  max-width: 100%;
}
.feature-list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  margin-bottom: 1.5rem;
}
.feature-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 1.25rem;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: var(--radius-lg);
  position: relative;
  transition: background var(--transition-base), transform var(--transition-base), box-shadow var(--transition-base), border-color var(--transition-base);
}
/* hover:hover only - .feature-row toggles its checkbox on tap (see
   js/main.js), and a :hover rule matching it makes iOS Safari require a
   second tap to actually register the click. */
@media (hover: hover) {
  .feature-row:hover {
    background: rgba(255, 255, 255, 0.75);
    transform: translateY(-4px);
    box-shadow: var(--shadow-card-hover);
  }
}
.feature-row:not(.is-locked) {
  cursor: pointer;
}
.feature-row.is-selected {
  background: rgba(167, 200, 232, 0.35);
  border-color: var(--color-oxford-navy);
}
.feature-row.is-selected:hover {
  background: rgba(167, 200, 232, 0.5);
}
.feature-row label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--color-text-dark);
  pointer-events: none;
}
.feature-row label input {
  pointer-events: auto;
}
.feature-row input[type="checkbox"] {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  accent-color: var(--color-oxford-navy);
}
.feature-row.is-locked label {
  color: var(--color-charcoal-blue);
}
.feature-price {
  font-weight: 700;
  color: var(--color-oxford-navy);
  white-space: nowrap;
}
.feature-desc {
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--color-text-dark);
}
.feature-total {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-start;
  padding: 1.75rem 2rem;
  margin-bottom: 0.75rem;
  background: var(--color-oxford-navy);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 32px rgba(59, 78, 94, 0.28);
  color: var(--color-white);
}
.feature-total-label {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-icy-blue);
}
.feature-total-amount {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.35rem 0.6rem;
  margin: 0;
}
.feature-total-figure {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 2rem;
  line-height: 1;
}
.feature-total-unit {
  font-size: 0.9rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.75);
}
.feature-total-monthly {
  opacity: 0;
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: opacity 0.3s ease, max-width 0.3s ease;
}
.feature-total-monthly.is-visible {
  opacity: 1;
  max-width: 220px;
}
.feature-disclaimer {
  font-style: italic;
  font-size: 0.85rem;
  color: var(--color-charcoal-blue);
  margin-bottom: 1.5rem;
}

/* Sticky selection summary - shown once a package or service is picked on
   packages.html / index.html#pricing, carries the running total to the
   "Continue" step. Reuses .feature-total's navy-card look (via the
   `feature-total` class applied alongside this one) for typography
   consistency; this class only handles fixed positioning + layout. */
.selection-summary-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 250;
  margin: 0;
  width: auto;
  max-width: none;
  border-radius: 0;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 1.25rem;
  box-shadow: 0 -8px 24px rgba(59, 78, 94, 0.25);
}
.selection-summary-bar[hidden] {
  display: none;
}
.selection-summary-info {
  min-width: 0;
}
.selection-summary-name {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-white);
  margin: 0.15rem 0 0.35rem;
}
.selection-summary-bar .feature-total-amount {
  gap: 0.2rem 0.5rem;
}
.selection-summary-bar .feature-total-figure {
  font-size: 1.4rem;
}
.selection-summary-continue {
  flex-shrink: 0;
  margin-top: 0;
}
@media (min-width: 768px) {
  .selection-summary-bar {
    left: auto;
    right: 2rem;
    bottom: 2rem;
    max-width: 320px;
    width: 100%;
    flex-direction: column;
    align-items: flex-start;
    border-radius: var(--radius-lg);
    box-shadow: 0 12px 32px rgba(59, 78, 94, 0.28);
  }
  .selection-summary-bar .feature-total-figure {
    font-size: 1.8rem;
  }
  .selection-summary-continue {
    width: 100%;
    text-align: center;
  }
}

/* What We Offer */
.offer-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}
/* Without this, a grid item's default min-width:auto can let wide content
   inside force the whole column past its 1fr track. */
.offer-grid > * { min-width: 0; }
/* Subtle brand-tinted gradient (image support to follow in a later pass -
   a real photo/screenshot per card will replace this wash then). */
.offer-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 1.25rem;
  padding-bottom: 3.5rem;
  background: rgba(167, 200, 232, 0.14);
  transition: box-shadow var(--transition-base), transform var(--transition-base), background var(--transition-base);
}
/* Beats the base .card:hover's flat light background (same specificity,
   later in source) so the gradient survives on hover. */
.offer-card:hover {
  background: rgba(167, 200, 232, 0.22);
}
.offer-card h3 {
  font-size: 1.3rem;
  margin-bottom: 0.35rem;
}
.offer-card .offer-price {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.4rem;
}
.offer-card p {
  font-size: 0.88rem;
  color: var(--color-text-dark);
}

/* Small "+" expand affordance, fixed bottom-right on every card (Apple-style
   corner control) instead of a full-width "Explore further" button. */
.offer-card-expand {
  position: absolute;
  right: 1.25rem;
  bottom: 1.25rem;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  background: var(--color-white);
  color: var(--color-oxford-navy);
  font-size: 1.4rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-base), color var(--transition-base), transform var(--transition-base);
}
.offer-card-expand:hover,
.offer-card-expand:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
  transform: scale(1.08);
}

/* Offer modal: a centered popup (one per card, see index.html) rather
   than an inline expand - opened/closed via js/main.js. */
.offer-modal {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.offer-modal[hidden] {
  display: none;
}
body.offer-modal-open {
  overflow: hidden;
}
.offer-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.6);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.offer-modal-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 520px;
  max-height: 85vh;
  overflow-y: auto;
  background: var(--color-white);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 64px rgba(59, 78, 94, 0.35);
  padding: 2.25rem;
  animation: offer-modal-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes offer-modal-in {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .offer-modal-panel { animation: none; }
}
.offer-modal-close {
  position: absolute;
  top: 1.1rem;
  right: 1.1rem;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  background: var(--color-mint-cream);
  color: var(--color-oxford-navy);
  font-size: 1.3rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-base), color var(--transition-base);
}
.offer-modal-close:hover,
.offer-modal-close:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}
.offer-modal-panel h3 { font-size: 1.5rem; margin-bottom: 0.4rem; }
.offer-modal-panel .offer-price {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.75rem;
}
.offer-modal-panel > p:not(.offer-price) {
  font-size: 0.95rem;
  color: var(--color-text-dark);
  margin-bottom: 1.25rem;
}
.offer-modal-cta {
  display: inline-flex;
  margin-top: 1.5rem;
}
/* ==========================================================================
   Offer preview cards ("pfa-browser") — a mini browser-chrome mockup per
   service, used inside each What We Offer modal. Purely percentage/
   aspect-ratio sized (no fixed-pixel JS scaling needed, unlike the old
   .offer-anim system this replaces).
   ========================================================================== */
.pfa-browser {
  width: 100%;
  max-width: 380px;
  aspect-ratio: 380 / 220;
  background: #FFFFFF;
  border: 1px solid rgba(59, 78, 94, 0.14);
  border-radius: 12px;
  box-shadow: 0 16px 32px -16px rgba(59, 78, 94, 0.28), 0 2px 8px rgba(59, 78, 94, 0.06);
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  font-family: var(--font-sans);
  margin-top: 0.5rem;
}
.pfa-bbar {
  height: 13%;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 3.5%;
  border-bottom: 1px solid rgba(59, 78, 94, 0.12);
  background: #FBFCFE;
  box-sizing: border-box;
}
.pfa-bdot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.pfa-bdot:nth-child(1) { background: #ED6A5E; }
.pfa-bdot:nth-child(2) { background: #F4BF4F; }
.pfa-bdot:nth-child(3) { background: #61C454; }
.pfa-baddr {
  flex: 1;
  height: 40%;
  margin-left: 3%;
  background: #F3F6FA;
  border: 1px solid rgba(59, 78, 94, 0.08);
  border-radius: 20px;
}
.pfa-stage {
  position: relative;
  width: 100%;
  height: 87%;
  overflow: hidden;
}
@keyframes pfa-fadeUp { 0% { opacity: 0; transform: translateY(8px); } 12%, 88% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-4px); } }
@keyframes pfa-fadeIn { 0% { opacity: 0; } 15%, 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes pfa-pulseRing { 0% { transform: scale(0.6); opacity: 0.8; } 70% { transform: scale(1.9); opacity: 0; } 100% { opacity: 0; } }
@keyframes pfa-popIn { 0% { transform: scale(0); opacity: 0; } 55% { transform: scale(1.15); opacity: 1; } 70% { transform: scale(1); } 92% { opacity: 1; } 100% { opacity: 0; transform: scale(0.9); } }
@keyframes pfa-ringDraw { 0% { stroke-dashoffset: 220; } 60%, 85% { stroke-dashoffset: 0; } 100% { stroke-dashoffset: 0; opacity: 0; } }
@keyframes pfa-barLoad { 0% { width: 0%; } 45% { width: 100%; } 60%, 100% { width: 100%; } }
@keyframes pfa-bounceDot { 0%, 60%, 100% { transform: translateY(0); opacity: 0.35; } 30% { transform: translateY(-4px); opacity: 1; } }
@keyframes pfa-starFill { 0%, 100% { fill: #E4EDF6; } 25%, 90% { fill: #A7C8E8; } }
@keyframes pfa-cellFill { 0%, 100% { background: transparent; } 40%, 75% { background: #A7C8E8; } }
@keyframes pfa-toastIn { 0%, 8% { transform: translateY(-30px); opacity: 0; } 20%, 78% { transform: translateY(0); opacity: 1; } 92%, 100% { transform: translateY(-30px); opacity: 0; } }
@keyframes pfa-dotPulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(120, 190, 120, 0.5); } 50% { box-shadow: 0 0 0 6px rgba(120, 190, 120, 0); } }
@keyframes pfa-growUp { 0% { transform: scaleY(0); } 50%, 100% { transform: scaleY(1); } }
@keyframes pfa-swingWidget { 0%, 30% { transform: scale(0); opacity: 0; } 45%, 85% { transform: scale(1); opacity: 1; } 100% { transform: scale(0); opacity: 0; } }

/* How This Helps */
.benefits-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}
.benefit-title {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  font-size: 1.4rem;
  color: var(--color-oxford-navy);
  margin-bottom: 0.5rem;
}
.benefit-card p {
  color: var(--color-text-dark);
}

/* The Process - each step sits in its own .card (glass background/border/
   shadow) rather than floating directly on the section background, since
   plain numbered text with no containment blended into the page. */
.process-steps {
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1.5rem;
}
/* success.html reuses the same component with only 3 steps, no .card/icon
   treatment - it's a simpler summary list on its own dedicated page, kept
   in its original circle-badge-number style. */
#success-steps {
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  margin-top: 2rem;
  margin-bottom: 2.5rem;
}
/* success.html keeps the original circle-badge number look - position:
   static overrides the base .process-number's top-right placement below,
   since it's not part of the icon-in-circle redesign on index.html. */
#success-steps .process-number {
  position: static;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--color-mint-cream);
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  font-size: 1.1rem;
  color: var(--color-oxford-navy);
  margin-bottom: 1.25rem;
}
.process-step { position: relative; display: flex; flex-direction: column; }
/* index.html: the circle now holds a step icon, and the number becomes a
   small top-right marker instead of the circle's content. */
.process-number {
  position: absolute;
  top: 1.5rem;
  right: 1.5rem;
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 1.5rem;
  color: var(--color-charcoal-blue);
}
.process-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--color-mint-cream);
  border: 1.5px solid rgba(59, 78, 94, 0.15);
  color: var(--color-oxford-navy);
  margin-bottom: 0.85rem;
}
.process-icon svg {
  width: 28px;
  height: 28px;
}
.process-step h3 {
  font-size: 1.15rem;
  margin-bottom: 0.5rem;
}
.process-step p {
  color: var(--color-text-dark);
  font-size: 0.95rem;
}

/* Example-stat reveal, shared by How This Helps and The Process.
   Numbers count up from 0 via JS when the card scrolls into view. */
.stat {
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(59, 78, 94, 0.12);
}
.stat-number {
  font-family: var(--font-display);
  font-size: 2rem;
  color: var(--color-oxford-navy);
  line-height: 1;
  margin-bottom: 0.35rem;
}
.stat-label {
  font-size: 0.85rem;
  color: var(--color-charcoal-blue);
}
/* "Built for" trades carousel - auto-advancing marquee driven from JS
   (js/main.js) via scrollLeft on a rAF loop, rather than a CSS transform
   animation, specifically so it's also a real native-scrollable element:
   dragging/swiping/wheeling it moves it like any horizontal scroller, and
   the auto-advance just pauses while the visitor is interacting and
   resumes shortly after, instead of stopping for good. The chip list is
   rendered twice back-to-back in index.html; once scrollLeft passes the
   width of one copy, JS silently subtracts it back off for a seamless
   loop in either scroll direction. Falls back to a plain manually-
   scrollable row with only one copy shown for prefers-reduced-motion. */
.trades-carousel-wrap {
  margin-top: 2.5rem;
}
.trades-carousel-label {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-charcoal-blue);
  margin-bottom: 0.85rem;
}
.trades-carousel {
  overflow-x: auto;
  padding: 0.25rem 0 0.6rem;
  mask-image: linear-gradient(90deg, transparent, #000 24px, #000 calc(100% - 24px), transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 24px, #000 calc(100% - 24px), transparent);
  scrollbar-width: none;
}
.trades-carousel::-webkit-scrollbar {
  display: none;
}
.trades-carousel-track {
  display: flex;
  gap: 0.85rem;
  width: max-content;
}
.trades-carousel-set {
  display: contents;
}
@media (prefers-reduced-motion: reduce) {
  .trades-carousel-set[aria-hidden="true"] { display: none; }
}
.trade-chip {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.55rem 1.15rem 0.55rem 0.55rem;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.65);
  border-radius: 999px;
  white-space: nowrap;
  transition: background var(--transition-base), border-color var(--transition-base);
}
.trade-chip:hover {
  background: rgba(255, 255, 255, 0.78);
  border-color: rgba(255, 255, 255, 0.9);
}
.trade-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: rgba(167, 200, 232, 0.25);
  color: var(--color-oxford-navy);
}
.trade-icon svg { width: 20px; height: 20px; }
.trade-chip span {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--color-text-dark);
}

/* Projects */
/* What We've Made: a fixed 2x2 grid of case-study tiles (1 column on
   mobile) - no scrolling, all four always visible/reachable without any
   interaction. Each tile shows a static preview image; the pop-out button
   still opens the real live site in a modal iframe. */
.projects-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.75rem;
}
/* A grid item's automatic minimum size defaults to its content's
   min-content width, which can force a track wider than its 1fr share. */
.projects-grid > * { min-width: 0; }
.project-card {
  padding: 0;
  overflow: hidden;
  border-radius: var(--radius-lg);
  transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.project-card:hover,
.project-card.reveal:hover {
  transform: translateY(-8px);
  box-shadow: 0 22px 48px rgba(59, 78, 94, 0.22);
}
.project-thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: 0;
  margin-bottom: 0;
  overflow: hidden;
  background: var(--color-mint-cream);
  border: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.project-thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* 4th tile: no live site to show yet, just a quiet placeholder. */
.project-thumb-placeholder {
  flex-direction: column;
  gap: 0.6rem;
  background: repeating-linear-gradient(
    135deg,
    var(--color-mint-cream),
    var(--color-mint-cream) 12px,
    #e9e4d8 12px,
    #e9e4d8 24px
  );
}
.project-placeholder-pulse {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-oxford-navy);
  background: rgba(167, 200, 232, 0.4);
  animation: project-placeholder-pulse 2.2s ease-in-out infinite;
}
@keyframes project-placeholder-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(167, 200, 232, 0.45); }
  50% { transform: scale(1.12); box-shadow: 0 0 0 12px rgba(167, 200, 232, 0); }
}
.project-placeholder-label {
  font-weight: 700;
  color: var(--color-oxford-navy);
  font-size: 0.95rem;
}
.project-placeholder-sub {
  font-size: 0.82rem;
  font-style: italic;
  color: var(--color-charcoal-blue);
}
/* Compact glass badge floating over the live preview, sized to its own
   content rather than a full-width panel below the site. */
.project-overlay-info {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  right: 4.5rem;
  width: fit-content;
  max-width: calc(100% - 5.5rem);
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: 0 8px 24px rgba(59, 78, 94, 0.18);
}
.tag {
  background: var(--color-icy-blue);
  color: var(--color-white);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
}
/* What We've Made pill: navy instead of the default icy-blue tag */
.project-overlay-info .tag {
  background: var(--color-oxford-navy);
  color: var(--color-white);
  display: inline-block;
  margin-bottom: 0.4rem;
}
.project-overlay-info h3 {
  font-size: 1.05rem;
  margin-bottom: 0;
}
/* Pop-out preview trigger, fixed bottom-right of every real project's
   thumbnail (placeholder cards have no real site, so no button). */
.project-popout-btn {
  position: absolute;
  right: 1rem;
  bottom: 1rem;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.7);
  color: var(--color-oxford-navy);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 20px rgba(59, 78, 94, 0.18);
  transition: background var(--transition-base), color var(--transition-base), transform var(--transition-base);
}
.project-popout-btn:hover,
.project-popout-btn:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
  transform: scale(1.06);
}

/* Project pop-out modal: a larger lightbox for viewing the live preview,
   opened/closed via js/main.js (same data-attribute pattern as
   .offer-modal). */
.project-modal {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.project-modal[hidden] {
  display: none;
}
body.project-modal-open {
  overflow: hidden;
}
.project-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.project-modal-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1100px;
  height: 78vh;
  background: var(--color-white);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 24px 64px rgba(59, 78, 94, 0.4);
  animation: offer-modal-in 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .project-modal-panel { animation: none; }
}
.project-modal-frame {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
/* A sibling of .project-modal-panel (not nested inside it) positioned in
   the backdrop margin above it, not over the top corner of the panel -
   the embedded site's own header often has a menu/nav button in exactly
   that top-right corner, which this used to sit on top of and cover on
   narrow screens. */
.project-modal-close {
  position: absolute;
  top: 0.75rem;
  right: 1.5rem;
  z-index: 2;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba(59, 78, 94, 0.15);
  color: var(--color-oxford-navy);
  font-size: 1.3rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-base), color var(--transition-base);
}
.project-modal-close:hover,
.project-modal-close:focus-visible {
  background: var(--color-oxford-navy);
  color: var(--color-white);
}

/* 10. Contact ----------------------------------------------------------------- */
.contact-split {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 2rem;
}
.contact-path {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 2.25rem;
  background: #4A5D6D;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--radius-lg);
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), background var(--transition-base), box-shadow var(--transition-base);
}
.contact-path:hover,
.contact-path.reveal:hover {
  transform: translateY(-6px);
  background: #59707F;
  box-shadow: 0 16px 40px rgba(59, 78, 94, 0.35);
}
.contact-path-number {
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 1.3rem;
  color: var(--color-white); /* dark-section: avoid icy-blue, see palette note */
  margin-bottom: 0.75rem;
}
.contact-path h3 {
  color: var(--color-white);
  font-size: 1.3rem;
  margin-bottom: 0.5rem;
}
.contact-path p {
  color: rgba(255, 255, 255, 0.8);
  margin-bottom: 1.5rem;
}
.contact-path .btn { margin-bottom: 0.85rem; }
.contact-path-note {
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.85); /* dark-section: avoid icy-blue, see palette note */
  font-weight: 600;
}
/* Used on both dark sections (submit-your-details.html, additional-
   details.html, index.html#contact) and one light one (review.html's
   error state) - default styling here is for the dark case since it's
   the majority; review.html gets .contact-email-note--light below. */
.contact-email-note {
  margin-top: 2rem;
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.95rem;
}
.contact-email-note a {
  color: var(--color-white);
  font-weight: 600;
  border-bottom: 1px solid rgba(255, 255, 255, 0.4);
}
.contact-email-note a:hover,
.contact-email-note a:focus-visible {
  border-color: var(--color-white);
}
.contact-email-note--light {
  color: var(--color-charcoal-blue);
}
.contact-email-note--light a {
  color: var(--color-charcoal-blue);
  border-bottom-color: rgba(59, 78, 94, 0.4);
}
.contact-email-note--light a:hover,
.contact-email-note--light a:focus-visible {
  border-color: var(--color-charcoal-blue);
}
.copy-email-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-left: 0.45rem;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.4);
  background: transparent;
  color: rgba(255, 255, 255, 0.85); /* dark-section: avoid icy-blue, see palette note */
  vertical-align: middle;
  transition: background var(--transition-base), border-color var(--transition-base), color var(--transition-base);
}
.copy-email-btn:hover,
.copy-email-btn:focus-visible {
  background: rgba(255, 255, 255, 0.15);
  border-color: var(--color-white);
  color: var(--color-white);
}
.copy-email-btn.is-copied {
  border-color: #7fd9a0;
  color: #7fd9a0;
}
.contact-email-note--light .copy-email-btn {
  border-color: rgba(59, 78, 94, 0.4);
  color: var(--color-charcoal-blue);
}
.contact-email-note--light .copy-email-btn:hover,
.contact-email-note--light .copy-email-btn:focus-visible {
  background: rgba(59, 78, 94, 0.1);
  border-color: var(--color-charcoal-blue);
}

/* Cross-journey progress indicator (Select -> Details -> Free build ->
   Approve & pay). Hand-placed per static page as a small constant, not
   JS-computed - matches the site's existing convention of duplicating
   header/footer markup per page rather than templating, and keeps working
   even if JS never loads. */
.journey-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  list-style: none;
  padding: 0;
  margin: 0 0 2rem;
}
.journey-steps li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-charcoal-blue);
}
.journey-step-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1.5px solid rgba(59, 78, 94, 0.25);
  font-family: var(--font-serif);
  font-weight: 800;
  font-size: 0.8rem;
  color: var(--color-charcoal-blue);
}
.journey-steps li.is-done .journey-step-number {
  background: var(--color-oxford-navy);
  border-color: var(--color-oxford-navy);
  color: var(--color-white);
}
.journey-steps li.is-current {
  color: var(--color-oxford-navy);
}
.journey-steps li.is-current .journey-step-number {
  border-color: var(--color-oxford-navy);
  color: var(--color-oxford-navy);
}
/* Light variant for use on .section-dark backgrounds */
.journey-steps--light li {
  color: rgba(255, 255, 255, 0.6);
}
.journey-steps--light .journey-step-number {
  border-color: rgba(255, 255, 255, 0.3);
  color: rgba(255, 255, 255, 0.6);
}
.journey-steps--light li.is-done .journey-step-number {
  background: var(--color-icy-blue);
  border-color: var(--color-icy-blue);
  color: var(--color-white);
}
.journey-steps--light li.is-current {
  color: var(--color-white);
}
.journey-steps--light li.is-current .journey-step-number {
  border-color: var(--color-white); /* dark-section: avoid icy-blue, see palette note */
  color: var(--color-white);
}

/* Shared lead-capture form (submit-your-details.html) - glass-on-navy
   treatment matching .contact-path, since this always lives inside a
   .section-dark section. */
.lead-form-wrap {
  margin-top: 2rem;
}
.lead-form {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  max-width: 480px;
}
.lead-form[hidden] {
  display: none;
}
.lead-form-intro {
  color: rgba(255, 255, 255, 0.85);
  margin: 0 0 1.25rem;
}
.lead-form-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.lead-form-field label {
  font-size: 0.85rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.85); /* dark-section: avoid icy-blue, see palette note */
}
.lead-form-field input,
.lead-form-field textarea {
  padding: 0.75rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: #4A5D6D;
  color: var(--color-white);
  font-family: var(--font-sans);
  font-size: 0.95rem;
}
.lead-form-field textarea {
  width: 100%;
  resize: vertical;
}
.lead-form-field input::placeholder,
.lead-form-field textarea::placeholder {
  color: rgba(255, 255, 255, 0.45);
}
.lead-form-field input.is-invalid {
  border-color: #e0847e;
}
.lead-form-error {
  font-size: 0.8rem;
  color: #f5b8b2;
  margin: 0;
}
/* Visually hidden from sighted users, but present in the DOM for bots that
   fill in every field - kept out of the tab order and off assistive tech. */
.lead-form-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.lead-form-consent {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.8);
}
.lead-form-consent input {
  margin-top: 0.2rem;
  accent-color: var(--color-white); /* dark-section: avoid icy-blue, see palette note */
}
.lead-form-consent a {
  color: var(--color-white); /* dark-section: avoid icy-blue, see palette note */
  text-decoration: underline;
}
.lead-form-reassurance {
  font-size: 0.85rem;
  font-style: italic;
  color: rgba(255, 255, 255, 0.75); /* dark-section: avoid icy-blue, see palette note */
  margin: 0;
}
.lead-form-field-note {
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.65); /* dark-section: avoid icy-blue, see palette note */
  margin-top: 0.5rem !important;
}
.lead-form-field-note a {
  color: rgba(255, 255, 255, 0.9);
  font-weight: 600;
}
.lead-form-status {
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.85);
  min-height: 1.2em;
  margin: 0;
}
.lead-form-status.is-error {
  color: #f5b8b2;
}
.lead-form-confirmation h3 {
  color: var(--color-white);
  margin-bottom: 0.5rem;
}
.lead-form-confirmation p {
  color: rgba(255, 255, 255, 0.8);
  max-width: 480px;
}
/* "Book a call" card: a site-styled frame around an inline Calendly embed
   (rather than a bare iframe dropped straight on the page) - the header
   row above the embed carries the site's own icon/copy, and the embed
   itself is colour-tinted via Calendly's background_color/text_color/
   primary_color URL params (see the data-url on each .calendly-inline-
   widget) so its internals roughly match rather than clashing. Calendly's
   own iframe content can't be pixel-matched to the site's design beyond
   that - a real embedding limit, not an oversight. */
.book-call-lede {
  color: var(--color-text-dark);
  margin-bottom: 0.75rem;
}
.details-intro {
  margin-bottom: 2rem;
}
.book-call-lede--last {
  margin-bottom: 2rem;
}
.book-call-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1rem;
  margin-bottom: 1.5rem;
  max-width: 480px;
  padding: 1.75rem;
  background: #4A5D6D;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--radius-lg);
}
.book-call-card[hidden] {
  display: none;
}
.book-call-header {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
}
.book-call-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  /* dark-section default: a blue tint this faint is nearly the same dark
     as the card itself, so both the circle and the icon need to be light
     instead - see palette note at the top of this file. */
  background: rgba(255, 255, 255, 0.12);
  color: var(--color-white);
}
.book-call-copy h3 {
  color: var(--color-white);
  font-size: 1.1rem;
  margin-bottom: 0.3rem;
}
.book-call-copy p {
  color: rgba(255, 255, 255, 0.75);
  font-size: 0.92rem;
  margin: 0;
}
.calendly-embed-wrap {
  border-radius: var(--radius-md);
  overflow: hidden;
}
/* Calendly renders its date-picker and time-slots side by side once the
   embed is wide enough, and stacked otherwise - the card's default 480px
   cap kept it stacked ("vertical") even on desktop. Widening just the
   cards that hold a Calendly embed lets it go horizontal on desktop,
   while it naturally stays narrow (and so vertical) on mobile since
   max-width is only ever an upper bound. */
.book-call-card:has(.calendly-embed-wrap) {
  max-width: 760px;
}

/* Light-background variant of the shared lead-capture form, for use
   outside .section-dark (e.g. book-your-call.html) - every color below
   mirrors the dark-mode rules above it, just inverted for contrast. */
.lead-form-wrap--light .lead-form-intro,
.lead-form-wrap--light .lead-form-consent,
.lead-form-wrap--light .lead-form-status,
.lead-form-wrap--light .lead-form-confirmation p {
  color: var(--color-charcoal-blue);
}
.lead-form-wrap--light .lead-form-field label {
  color: var(--color-oxford-navy);
}
.lead-form-wrap--light .lead-form-field input {
  border-color: rgba(59, 78, 94, 0.2);
  background: var(--color-white);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--color-text-dark);
}
.lead-form-wrap--light .lead-form-field input::placeholder {
  color: rgba(31, 41, 55, 0.4);
}
.lead-form-wrap--light .lead-form-reassurance {
  color: var(--color-charcoal-blue);
}
.lead-form-wrap--light .lead-form-error,
.lead-form-wrap--light .lead-form-status.is-error {
  color: #b3261e;
}
.lead-form-wrap--light .lead-form-confirmation h3 {
  color: var(--color-oxford-navy);
}
/* Variant for use on light (non section-dark) backgrounds, e.g.
   book-your-call.html - the default tint above is only visible against a
   dark section. */
.book-call-card--light {
  background: var(--color-white);
  border-color: rgba(59, 78, 94, 0.12);
}
.book-call-card--light .book-call-copy h3 {
  color: var(--color-oxford-navy);
}
.book-call-card--light .book-call-copy p {
  color: var(--color-charcoal-blue);
}
.book-call-card--light .book-call-icon {
  background: rgba(167, 200, 232, 0.3);
  color: var(--color-oxford-navy);
}

/* review.html: approve/pay screen */
.review-greeting {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--color-oxford-navy);
  margin-bottom: 1.5rem;
}
.review-summary-card {
  max-width: 560px;
  padding: 1.75rem 2rem;
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.25rem;
}
.review-summary-card .feature-total-label {
  color: var(--color-charcoal-blue);
}
.review-selection-name {
  font-weight: 700;
  margin: 0.35rem 0 0.75rem;
  color: var(--color-oxford-navy);
}
.review-summary-amount {
  color: var(--color-oxford-navy);
}
.review-summary-unit {
  color: var(--color-charcoal-blue);
}
.review-preview-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
  flex-shrink: 0;
}
@media (min-width: 640px) {
  .review-summary-card {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}
.review-actions {
  align-items: center;
}
.review-security-note {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  font-style: italic;
  color: var(--color-charcoal-blue);
  margin-top: 0.75rem;
}
.review-lock-icon {
  flex-shrink: 0;
  color: var(--color-charcoal-blue);
}
.review-confirmed-note {
  max-width: 480px;
  padding: 1.25rem 1.5rem;
  margin-top: 0.75rem;
  background: rgba(167, 200, 232, 0.25);
  border: 1px solid rgba(59, 78, 94, 0.15);
  border-radius: var(--radius-lg);
  color: var(--color-text-dark);
}
.review-confirmed-note p {
  margin: 0 0 1rem;
}
.review-status {
  color: var(--color-charcoal-blue);
}
.review-status.is-error {
  color: #b3261e;
}

/* 11. Footer ------------------------------------------------------------------- */
.site-footer {
  background: var(--color-oxford-navy);
  color: var(--color-white);
  padding-top: 3rem;
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}
.footer-tagline {
  margin-top: 0.6rem;
  color: rgba(255, 255, 255, 0.8); /* dark-section: avoid icy-blue, see palette note */
  font-weight: 600;
  font-size: 0.95rem;
}
.footer-nav ul {
  display: flex;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.footer-nav a {
  font-weight: 600;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.85);
  transition: color var(--transition-base);
}
.footer-nav a:hover,
.footer-nav a:focus-visible { color: var(--color-white); }

.footer-bottom {
  padding-block: 1.5rem 2rem;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.7);
}
.footer-bottom p { margin-bottom: 0.5rem; }
.footer-bottom p:last-child { margin-bottom: 0; }
.footer-legal-links a {
  color: rgba(255, 255, 255, 0.7);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.footer-legal-links a:hover,
.footer-legal-links a:focus-visible { color: var(--color-white); }

/* Side scroll-spy nav (index.html) - one dot per section, active state +
   label tracked in js/main.js. Desktop-only; a long dot rail crowds a
   narrow viewport that already has more pressing uses for the space. */
.section-nav {
  position: fixed;
  right: 1.5rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 150;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
}
.section-nav-dot {
  position: relative;
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(59, 78, 94, 0.25);
  transition: background var(--transition-base), transform var(--transition-base);
}
.section-nav-dot:hover,
.section-nav-dot:focus-visible {
  background: rgba(59, 78, 94, 0.6);
}
.section-nav-dot.is-active {
  background: var(--color-oxford-navy);
  transform: scale(1.45);
}
.section-nav-dot::after {
  content: attr(data-label);
  position: absolute;
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  margin-right: 0.75rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  background: var(--color-oxford-navy);
  color: var(--color-white);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-base), transform var(--transition-base);
}
.section-nav-dot:hover::after,
.section-nav-dot:focus-visible::after {
  opacity: 1;
  transform: translateY(-50%) translateX(-4px);
}
@media (max-width: 900px) {
  .section-nav { display: none; }
}

/* 12. Scroll-reveal -------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.32s cubic-bezier(0.16, 1, 0.3, 1), transform 0.32s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* 13. Responsive ------------------------------------------------------------------ */
@media (max-width: 900px) {
  .pricing-grid { grid-template-columns: 1fr; }
  .pricing-card--highlight { order: -1; }
  .contact-split { grid-template-columns: 1fr; }

  .offer-grid { grid-template-columns: repeat(2, 1fr); }
  .benefits-grid { grid-template-columns: 1fr; }
  .process-steps { grid-template-columns: repeat(3, 1fr); row-gap: 1.5rem; }
  .feature-list { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 768px) {
  .founders-grid { grid-template-columns: 1fr; }
  /* The image fills the tile edge-to-edge on mobile instead of sitting
     under a floating glass badge - the pill/title and pop-out button move
     into a plain row underneath instead of overlapping the picture. */
  .project-card:not(.project-card-placeholder) .project-thumb {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas: "image image" "info button";
    align-items: center;
    aspect-ratio: auto;
  }
  .project-card:not(.project-card-placeholder) .project-thumb-img {
    grid-area: image;
    aspect-ratio: 16 / 9;
    height: auto;
  }
  .project-card:not(.project-card-placeholder) .project-overlay-info {
    grid-area: info;
    position: static;
    width: auto;
    max-width: none;
    padding: 0.85rem 0.25rem 0.85rem 1rem;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 0;
    box-shadow: none;
  }
  .project-card:not(.project-card-placeholder) .project-popout-btn {
    grid-area: button;
    position: static;
    margin-right: 1rem;
  }
  .projects-grid { grid-template-columns: 1fr; }
  .offer-grid { grid-template-columns: 1fr; }
  .feature-list { grid-template-columns: 1fr; }
  .process-steps { grid-template-columns: 1fr; }
  .about-bio { flex-direction: column; gap: 1.25rem; }
  .services-grid { grid-template-columns: 1fr; }

  .nav-toggle { display: flex; }

  .primary-nav {
    position: absolute;
    top: var(--header-height);
    left: 0;
    right: 0;
    background: var(--color-mint-cream);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 1.5rem;
    box-shadow: 0 12px 24px rgba(59, 78, 94, 0.12);
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--transition-base), transform var(--transition-base), visibility var(--transition-base);
  }
  .primary-nav.is-open {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }
  .primary-nav ul {
    flex-direction: column;
    gap: 0;
  }
  .primary-nav ul li a {
    display: block;
    padding: 0.85rem 0;
    border-bottom: 1px solid rgba(59, 78, 94, 0.08);
  }
  .nav-cta {
    margin-top: 1.25rem;
    text-align: center;
    justify-content: center;
  }
}

@media (max-width: 480px) {
  .card { padding: 1.5rem; }
  /* .card's shorthand padding above would otherwise collapse the extra
     bottom clearance .offer-card reserves for its absolutely-positioned
     "+" button, letting longer descriptions run under it on narrow
     screens - reassert it here. */
  .offer-card { padding: 1.5rem; padding-bottom: 3.5rem; }
  .hero-actions { flex-direction: column; align-items: stretch; }
}

/* admin.html - internal, password-gated preview-delivery tool. */
.admin-wrap {
  max-width: 720px;
}
.admin-intro {
  color: var(--color-charcoal-blue);
  max-width: 60ch;
}
.admin-refresh-btn {
  margin-block: 1rem 1.5rem;
}
.admin-section-heading {
  margin-top: 2.5rem;
  margin-bottom: 0.5rem;
}
.admin-intro--small {
  font-size: 0.9rem;
  margin-bottom: 1rem;
}
.admin-status {
  color: var(--color-charcoal-blue);
}
#admin-error {
  color: #b3261e;
}
.admin-leads {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.admin-lead-card {
  background: var(--color-white);
  border: 1px solid rgba(59, 78, 94, 0.12);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
}
.admin-lead-card.is-done {
  opacity: 0.6;
}
/* The lead itself still updated fine here - only the email failed to
   send - so this must stay fully visible rather than fading away like a
   clean success, or it reads as "done" when it actually needs a manual
   follow-up (e.g. sharing the link with the customer directly). */
.admin-lead-card.is-done.is-warning {
  opacity: 1;
  border-color: #d99a3d;
  background: #fdf6ec;
}
.admin-lead-badge {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--color-mint-cream);
  color: var(--color-oxford-navy);
  margin-bottom: 0.6rem;
}
.admin-lead-badge.is-changes {
  background: #fbe3c9;
  color: #7a4a12;
}
.admin-lead-card h3 {
  margin-bottom: 0.25rem;
}
.admin-lead-meta,
.admin-lead-summary,
.admin-lead-brief {
  margin: 0.2rem 0;
  color: var(--color-charcoal-blue);
  font-size: 0.9rem;
}
.admin-lead-summary {
  font-weight: 600;
  color: var(--color-oxford-navy);
}
.admin-lead-brief {
  font-style: italic;
}
.admin-lead-form {
  display: flex;
  gap: 0.75rem;
  margin-top: 1rem;
  flex-wrap: wrap;
}
/* Same [hidden]-vs-display specificity issue fixed elsewhere in this file:
   without this, .admin-lead-form's own display:flex beats the browser's
   default [hidden] { display: none } rule. */
.admin-lead-form[hidden] {
  display: none;
}
.admin-lead-input {
  flex: 1 1 260px;
  padding: 0.7rem 1rem;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(59, 78, 94, 0.25);
  font-family: var(--font-sans);
  font-size: 0.9rem;
}
.admin-lead-status {
  margin: 0.6rem 0 0;
  font-size: 0.85rem;
  color: var(--color-charcoal-blue);
  min-height: 1.2em;
}
.admin-lead-status.is-error {
  color: #b3261e;
}
.admin-lead-status.is-warning {
  color: #7a4a12;
  font-weight: 600;
}
.admin-lead-delete-zone {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(59, 78, 94, 0.1);
}
.admin-lead-delete-btn {
  background: none;
  border: none;
  padding: 0;
  font-size: 0.8rem;
  color: rgba(59, 78, 94, 0.5);
  text-decoration: underline;
  cursor: pointer;
}
.admin-lead-delete-btn:hover {
  color: #b3261e;
}
.admin-lead-delete-confirm {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  font-size: 0.85rem;
  color: #b3261e;
}
/* Same [hidden]-vs-display specificity issue fixed elsewhere in this file. */
.admin-lead-delete-confirm[hidden] {
  display: none;
}
.admin-lead-delete-confirm-btn {
  border-color: #b3261e;
  color: #b3261e;
  padding: 0.4rem 1rem;
  font-size: 0.85rem;
}
.admin-lead-delete-confirm-btn:hover,
.admin-lead-delete-confirm-btn:focus-visible {
  background: #b3261e;
  color: var(--color-white);
}
.admin-lead-delete-cancel-btn {
  background: none;
  border: none;
  padding: 0;
  font-size: 0.85rem;
  color: var(--color-charcoal-blue);
  text-decoration: underline;
  cursor: pointer;
}

/* Touch/coarse-pointer devices have no real mouseout - a tap can leave a
   :hover-triggered lift/scale visually "stuck" until the user taps
   somewhere else, which reads as broken rather than animated. .card and
   .pricing-card's own hover rules are scoped to @media (hover: hover) at
   their source instead (see above) since those are real JS click targets
   where iOS Safari would otherwise require a second tap; this covers the
   rest, which are plain decorative lifts. */
@media (hover: none), (pointer: coarse) {
  .project-card:hover,
  .project-card.reveal:hover,
  .contact-path:hover,
  .contact-path.reveal:hover,
  .offer-card-expand:hover,
  .offer-card-expand:focus-visible,
  .btn:hover,
  .projects-nav-btn:hover:not(:disabled),
  .demo-quote-mc:hover {
    transform: none;
  }
}

/* Sitewide floating WhatsApp button - fixed bottom-right, above regular
   content but below modals/overlays (z-index 500). */
.whatsapp-float {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 400;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: #25D366;
  color: var(--color-white);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 10px 28px rgba(59, 78, 94, 0.35);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.whatsapp-float:hover,
.whatsapp-float:focus-visible {
  transform: translateY(-3px) scale(1.06);
  box-shadow: 0 14px 34px rgba(59, 78, 94, 0.45);
}
/* Clears packages.html / index.html#pricing's sticky selection summary bar
   (also fixed to the bottom edge) once it's shown, instead of overlapping
   its Continue button. */
body:has(.selection-summary-bar:not([hidden])) .whatsapp-float {
  bottom: 6.5rem;
}
@media (max-width: 480px) {
  .whatsapp-float {
    width: 52px;
    height: 52px;
    right: 1rem;
    bottom: 1rem;
  }
  body:has(.selection-summary-bar:not([hidden])) .whatsapp-float {
    bottom: 6rem;
  }
}
@media (hover: none), (pointer: coarse) {
  .whatsapp-float:hover {
    transform: none;
  }
}
