/* DataPace brand overrides for the Vuexy front-page template.
   Loaded after core.css - re-themes the template's default violet
   to a navy-and-amber B2B palette via CSS custom properties. */

/* Self-hosted Wix Madefor Text (variable font, weights 400-800) - no request
   to Google's fonts.gstatic.com, so no GDPR consent question for it. */
@font-face {
  font-family: 'Wix Madefor Text';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/vendor/fonts/wix-madefor-text/WixMadeforText-Variable.woff2') format('woff2-variations'),
       url('/assets/vendor/fonts/wix-madefor-text/WixMadeforText-Variable.woff2') format('woff2');
}
@font-face {
  font-family: 'Wix Madefor Text';
  font-style: italic;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/vendor/fonts/wix-madefor-text/WixMadeforText-Italic-Variable.woff2') format('woff2-variations'),
       url('/assets/vendor/fonts/wix-madefor-text/WixMadeforText-Italic-Variable.woff2') format('woff2');
}

:root,
[data-bs-theme='light'] {
  /* Blue: headings, icons, borders, badges - the "information" colour */
  --bs-primary: #166aea;
  --bs-primary-rgb: 22, 106, 234;
  --bs-primary-bg-subtle: #dbeafe;
  --bs-primary-border-subtle: #93c5fd;
  --bs-primary-text-emphasis: #0e3d8c;

  /* Orange: reserved for primary call-to-action buttons only */
  --dp-accent: #faa85e;
  --dp-accent-hover: #f7913f;
  --dp-accent-active: #e87f2c;
  --dp-accent-text: #1f2937;
}

body {
  font-family: 'Wix Madefor Text', -apple-system, BlinkMacSystemFont, sans-serif;
}

/* Warm accent on solid CTA buttons only - blue stays the informational colour elsewhere.
   Text is dark, not white: #faa85e is light enough that white text fails contrast. */
.btn-primary {
  --bs-btn-color: var(--dp-accent-text);
  --bs-btn-bg: var(--dp-accent);
  --bs-btn-border-color: var(--dp-accent);
  --bs-btn-hover-color: var(--dp-accent-text);
  --bs-btn-hover-bg: var(--dp-accent-hover);
  --bs-btn-hover-border-color: var(--dp-accent-active);
  --bs-btn-focus-shadow-rgb: 250, 168, 94;
  --bs-btn-active-color: var(--dp-accent-text);
  --bs-btn-active-bg: var(--dp-accent-hover);
  --bs-btn-active-border-color: var(--dp-accent-active);
  --bs-btn-active-shadow: none;
  --bs-btn-disabled-color: var(--dp-accent-text);
  --bs-btn-disabled-bg: var(--dp-accent);
  --bs-btn-disabled-border-color: var(--dp-accent);
}

/* Sticky header */
nav.layout-navbar {
  position: sticky;
  top: 0;
  z-index: 1030;
}

/* Brand mark: a plain circle behind the logo's plug icon, in the
   informational blue rather than the CTA-only orange - this is the
   identity mark, not a button, so it stays in the "information" colour. */
.brand-mark {
  background-color: var(--bs-primary);
  border-radius: 50%;
}

/* Gap between the last nav link and the CTA button, matching the gap
   between nav items themselves (0.625rem, set in front-page.css) - both
   navbar-nav lists use ms-auto to sit flush right, which otherwise leaves
   zero space between them. */
.landing-navbar-cta {
  margin-inline-start: 0.625rem;
}

/* Tinted sections are opaque flat fills now - see the parallax stack below,
   where each section covering the last does the job the old fade-to-transparent
   edges used to do. Only the section right before the (non-stacked) footer
   keeps a fade, since that boundary is a normal scroll, not a stack-cover. */
.section-tint {
  --dp-tint: #f8f7fa;
}
.section-tint-both,
.section-tint-top,
.section-tint-bottom,
.section-tint-footer {
  background: var(--dp-tint);
}

/* Parallax stack: each section sits in normal document flow until scrolled
   to, then sticks under the nav and holds there while the next section
   (next in DOM, higher in this list) scrolls up and covers it. Every
   section needs an opaque background for the cover to actually read as a
   cover - the white ones get it here since .section-tint already covers
   the tinted ones. Footer is deliberately left out: it just scrolls in
   normally after the last stacked section lets go.

   A sticky element doesn't reveal overflow by scrolling internally - it
   just holds the same view for its whole height's worth of scrolling. So
   the actual pinning (position: sticky, below) only applies per-section
   once site.js has confirmed (measuring live, not a one-off check) that
   the section's actual rendered height fits within the viewport below the
   nav - the .parallax-fit class is added/removed by JS on load, resize and
   font-load. Sections that don't fit are left in normal flow instead of
   frozen mid-content.

   Every section below still gets position:relative and an explicit
   z-index UNCONDITIONALLY, whether or not it currently has .parallax-fit.
   This isn't optional polish: position:sticky keeps an element "positioned"
   (participating in z-index stacking, painted above any position:static
   sibling) even once it has scrolled past its own pinned phase - it doesn't
   revert to acting like position:static just because it's no longer stuck.
   Without a z-index of its own, a section that currently doesn't fit (so
   it's plain position:static) can end up invisibly hidden under an earlier
   section that still outranks it in stacking order, even though that
   earlier section has already scrolled out of its hold phase. This is
   exactly what happened to "Working Together" (sandwiched between the
   fitting #about and #faq) and the contact form (right after #faq) - both
   silently covered, not removed, so nothing in the markup or a basic
   render check showed anything wrong.

   #faq is deliberately left out of the JS fit-check group below (see
   PARALLAX_IDS in site.js) - its accordion changes height at runtime as
   questions open and close, so a one-off "does it fit" measurement goes
   stale the moment a visitor clicks a question. It gets its own permanent
   sticky rule instead, further down. */
#hero-animation, #services, #work, #about, #engagements, #faq, #contact {
  position: relative;
}
#hero-animation { z-index: 1; background: var(--bs-paper-bg); }
#services       { z-index: 2; }
#work           { z-index: 3; }
#about          { z-index: 4; background: var(--bs-paper-bg); }
#engagements    { z-index: 5; }
#faq            { z-index: 6; }
#contact        { z-index: 7; }

#hero-animation.parallax-fit,
#services.parallax-fit,
#work.parallax-fit,
#about.parallax-fit,
#engagements.parallax-fit {
  position: sticky;
  top: var(--nav-h, 4.5rem);
  /* A sticky element's box is only as tall as its own content - if that's
     shorter than the viewport, the gap below it isn't painted with this
     section's background at all, so the next section (already sitting in
     normal flow right behind it, waiting its turn) shows through at the
     bottom of the screen. Stretching every pinned section to fill the full
     available height closes that gap regardless of how short its content is. */
  min-height: calc(100vh - var(--nav-h, 4.5rem));
  min-height: calc(100dvh - var(--nav-h, 4.5rem));
}

/* FAQ: its own sticky section, pinned unconditionally (not gated by the
   JS fit-check the other sections use - see the comment above) at the same
   >=992px breakpoint the rest of the stack requires. */
@media (min-width: 992px) {
  #faq {
    position: sticky;
    top: var(--nav-h, 4.5rem);
    min-height: calc(100vh - var(--nav-h, 4.5rem));
    min-height: calc(100dvh - var(--nav-h, 4.5rem));
  }
}

/* The a11y widget's text-size options scale the page with CSS zoom, not a
   viewport resize, so site.js's fit-check (which only re-runs on resize,
   orientationchange or font load) never re-measures against the now-larger
   rendered content. A section already marked .parallax-fit at 1x zoom can
   end up taller than the viewport slot it's pinned into once zoomed - and
   because it's stuck in place for that slot's whole scroll range, whatever
   overflows below it is never scrolled into view before the next section
   covers it. Simplest fix: drop the sticky pinning entirely while either
   zoom level is active, so every section just sits in normal flow instead. */
html.a11y-text-large #hero-animation.parallax-fit,
html.a11y-text-large #services.parallax-fit,
html.a11y-text-large #work.parallax-fit,
html.a11y-text-large #about.parallax-fit,
html.a11y-text-large #engagements.parallax-fit,
html.a11y-text-large #faq,
html.a11y-text-larger #hero-animation.parallax-fit,
html.a11y-text-larger #services.parallax-fit,
html.a11y-text-larger #work.parallax-fit,
html.a11y-text-larger #about.parallax-fit,
html.a11y-text-larger #engagements.parallax-fit,
html.a11y-text-larger #faq {
  position: relative;
  min-height: 0;
}

/* Footer: #contact is a positioned element with z-index:7 (see above), which
   puts it in its own stacking layer that paints above every plain, unpositioned
   in-flow element in the page - including the footer that comes after it in
   the DOM. Without its own position+z-index the footer was invisible, painted
   underneath #contact regardless of DOM order. */
.landing-footer {
  position: relative;
  z-index: 8;
}

/* Hero fills the screen below the sticky nav on every breakpoint.
   --nav-h is measured and set by site.js; 4.5rem is the pre-JS fallback. */
#hero-animation {
  display: flex;
  align-items: center;
  min-height: calc(100vh - var(--nav-h, 4.5rem));
  min-height: calc(100dvh - var(--nav-h, 4.5rem));
}
#hero-animation .landing-hero {
  width: 100%;
}

.landing-hero {
  --bs-hero-bg: var(--bs-paper-bg);
  /* Big blocks of colour top and bottom felt like dead air - trim it */
  padding-block: 3.5rem 2rem !important;
}
@media (min-width: 1200px) {
  .landing-hero {
    padding-block: 4.5rem 2.5rem !important;
  }
}

.landing-hero .hero-title {
  /* Large text in a fully saturated brand colour reads as loud, not premium -
     colour is for small, high-emphasis elements (icons, badges, buttons);
     big headlines stay in the neutral ink colour. */
  animation: none;
  background: none;
  background-clip: initial;
  -webkit-background-clip: initial;
  -webkit-text-fill-color: currentColor;
  color: var(--bs-heading-color);
}

/* CTA + Contact: one bold, fully-saturated colour block instead of another
   pale-tint section - the page has plenty of white/near-white already, and
   the contact form now lives inside this block too (its own white card
   still reads clearly against the navy). Full-bleed, not an inset rounded
   card, since #contact is tall enough that it's excluded from the parallax
   stack anyway and needs to cover edge-to-edge in normal scroll. */
.landing-cta-block {
  background: linear-gradient(155deg, #0f2a52 0%, #123566 55%, #166aea 130%);
}
.landing-cta-block .cta-title {
  color: #ffffff;
}
.landing-cta-block .section-eyebrow {
  color: #c3d7f5;
}
/* Scoped to specific elements sitting directly on the navy background -
   not a blanket "p" rule, since the contact form's white card (and its
   alerts, labels, helper text) needs to stay dark-on-white regardless of
   what section it's embedded in. */
.landing-cta-block .cta-text-light {
  color: #c3d7f5;
}

/* Plain, uncoloured section label - no pill badge */
.section-eyebrow {
  display: inline-block;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bs-primary);
}

/* Integration diagram visual in the hero */
.integration-diagram {
  border-radius: 1.25rem;
}
.integration-diagram .flow-node {
  border-radius: 0.75rem;
  background: var(--bs-paper-bg);
  border: 1px solid var(--bs-border-color);
}
.integration-diagram .flow-arrow {
  color: var(--bs-primary);
  opacity: 0.6;
}
.integration-diagram .flow-node i.icon-lg {
  /* icon-lg reads --bs-icon-size-lg (1.5rem default) - size these up */
  --bs-icon-size-lg: 2.25rem;
}

/* Checkmark badges: fixed square box, stays square as a flex child */
.badge-center {
  flex-shrink: 0;
}

/* Working Together: Discovery Call sits as a single centred "trunk" card
   above Build and Retainer, which line up level with each other below it.
   The connecting pill is absolutely positioned over the row, so the row
   needs position:relative to anchor it. */
.engagement-stem {
  width: 2px;
  height: 2.5rem;
  background: var(--bs-border-color);
  margin: 0 auto;
}
.engagement-row {
  position: relative;
}
.engagement-connector {
  position: absolute;
  top: 1%;
  left: 50%;
  /* Bootstrap's .row > * sets an explicit width:100% so every row child
     behaves like a column by default - position:absolute doesn't cancel
     that, it just changes what the width resolves against, so without
     this override the pill stretches to the row's full width instead of
     shrink-wrapping its own text. */
  width: max-content;
  transform: translate(-50%, -50%);
  background: var(--bs-paper-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 20px;
  padding: 0.35rem 0.9rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--bs-secondary-color);
  white-space: nowrap;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 4px 12px rgba(0, 0, 0, 0.06);
  z-index: 2;
}

/* Working Together cards end in a checklist, not a button, on two of the
   three cards - the default card-body padding leaves a big empty gap
   under the last checklist item. */
#engagements .card-body {
  padding-bottom: 0.75rem;
}

/* Working Together card headers: left-aligned icon, heading and subtitle
   (not centred), with a smaller icon sized through the standard icon-size
   token instead of a one-off inline font-size. */
#engagements .card-header .icon-base {
  --bs-icon-size: 1.75rem;
}

/* Scroll reveal */
[data-animate] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
[data-animate].in-view {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  [data-animate] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ============================================================
   Accessibility widget: a floating control panel for text size, line
   spacing, contrast, a dyslexia-friendly font and reduced motion.
   Preferences live in the visitor's own browser (localStorage) and are
   applied as classes on <html> - see the pre-paint script in index.php's
   <head> and assets/js/accessibility.js. Markup: partials/accessibility-widget.php.
   ============================================================ */
@font-face {
  font-family: 'OpenDyslexic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/vendor/fonts/opendyslexic/OpenDyslexic-Regular.woff2') format('woff2');
}
@font-face {
  font-family: 'OpenDyslexic';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/vendor/fonts/opendyslexic/OpenDyslexic-Bold.woff2') format('woff2');
}

/* Skip link: visually hidden until it receives keyboard focus */
.skip-link {
  position: fixed;
  top: -3rem;
  left: 0.75rem;
  z-index: 1100;
  background: var(--bs-primary);
  color: #fff;
  padding: 0.6rem 1rem;
  border-radius: 0.375rem;
  font-weight: 600;
  text-decoration: none;
  transition: top 0.15s ease;
}
.skip-link:focus {
  top: 0.75rem;
}

.a11y-trigger {
  position: fixed;
  left: 1.25rem;
  /* Shifts up out of the way while the cookie banner is showing - see
     assets/js/cookie-consent.js, which measures the banner's real height
     (it wraps to two lines on narrow screens) into this custom property. */
  bottom: calc(1.25rem + var(--cookie-banner-h, 0px));
  z-index: 1040;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  border: none;
  background: var(--bs-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.25);
}
.a11y-trigger:hover {
  background: var(--bs-primary-text-emphasis);
}

.a11y-scrim {
  position: fixed;
  inset: 0;
  z-index: 1050;
  background: rgba(15, 23, 42, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.a11y-scrim[hidden] {
  display: none;
}

.a11y-popup {
  width: 100%;
  max-width: 26rem;
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
  background: var(--bs-paper-bg);
  border-radius: 0.75rem;
  box-shadow: 0 1.5rem 4rem rgba(0, 0, 0, 0.35);
}
.a11y-popup:focus {
  outline: none;
}

.a11y-popup-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--bs-border-color);
}
.a11y-popup-close {
  border: none;
  background: transparent;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--bs-body-color);
  padding: 0.25rem 0.5rem;
}

.a11y-popup-body {
  padding: 1rem 1.25rem 1.25rem;
}

.a11y-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px dashed var(--bs-border-color);
}
.a11y-row:last-of-type {
  border-bottom: none;
}
.a11y-row-label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--bs-heading-color);
}
.a11y-row-hint {
  font-size: 0.75rem;
  color: var(--bs-secondary-color);
  margin-top: 0.125rem;
}

.a11y-seg {
  display: flex;
  gap: 0.125rem;
  background: var(--bs-secondary-bg, #f1f2f4);
  padding: 0.1875rem;
  border-radius: 0.375rem;
  flex-shrink: 0;
}
.a11y-seg button {
  border: none;
  background: transparent;
  padding: 0.35rem 0.6rem;
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  border-radius: 0.25rem;
  color: var(--bs-secondary-color);
}
.a11y-seg button[aria-checked="true"] {
  background: var(--bs-primary);
  color: #fff;
}

.a11y-toggle {
  flex-shrink: 0;
  width: 2.5rem;
  height: 1.375rem;
  border-radius: 0.6875rem;
  background: var(--bs-secondary-bg, #d7dbe0);
  border: none;
  position: relative;
}
.a11y-toggle::after {
  content: '';
  position: absolute;
  top: 0.125rem;
  left: 0.125rem;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background: #fff;
  transition: left 0.15s ease;
}
.a11y-toggle[aria-checked="true"] {
  background: var(--bs-primary);
}
.a11y-toggle[aria-checked="true"]::after {
  left: 1.25rem;
}

.a11y-popup-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1rem;
  flex-wrap: wrap;
}
.a11y-popup-footer a {
  font-size: 0.8125rem;
  font-weight: 600;
}

/* Effect classes - applied to <html> by the pre-paint script and by
   assets/js/accessibility.js on every change. Keep in sync with
   ALL_CLASSES there. */
html.a11y-text-large { zoom: 1.15; }
html.a11y-text-larger { zoom: 1.3; }

html.a11y-spacing-wide :where(p, li, dd) { line-height: 1.85 !important; }
html.a11y-spacing-wider :where(p, li, dd) { line-height: 2.1 !important; }

html.a11y-reduce-motion *,
html.a11y-reduce-motion *::before,
html.a11y-reduce-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}

html.a11y-dyslexia,
html.a11y-dyslexia * {
  font-family: 'OpenDyslexic', 'Comic Sans MS', Verdana, sans-serif !important;
  letter-spacing: 0.01em;
}

/* High contrast: a blunt, universal black-on-white override plus targeted
   exemptions, rather than trying to individually re-theme every component -
   the widget's own chrome (scrim, popup) needs an explicit background kept
   or it goes transparent against the page and becomes unreadable. */
html.a11y-high-contrast,
html.a11y-high-contrast body {
  background: #fff !important;
  color: #000 !important;
}
html.a11y-high-contrast * {
  background-color: transparent !important;
  color: #000 !important;
  border-color: #000 !important;
}
html.a11y-high-contrast :where(h1, h2, h3, h4, h5, h6) { color: #000 !important; }
html.a11y-high-contrast :where(a) { color: #0000ee !important; text-decoration: underline !important; }
html.a11y-high-contrast :where(a:visited) { color: #551a8b !important; }
html.a11y-high-contrast :where(button, .btn, [role="button"]) {
  background: #000 !important;
  color: #fff !important;
}
html.a11y-high-contrast :where(*:focus-visible) {
  outline: 3px solid var(--dp-accent) !important;
  outline-offset: 2px !important;
  box-shadow: none !important;
}
html.a11y-high-contrast .a11y-scrim {
  background-color: rgba(0, 0, 0, 0.85) !important;
}
html.a11y-high-contrast .a11y-popup {
  background-color: #fff !important;
  border: 2px solid #000 !important;
}
html.a11y-high-contrast .a11y-toggle[aria-checked="true"] {
  background: #000 !important;
}
html.a11y-high-contrast .a11y-trigger {
  background: #000 !important;
  color: #fff !important;
}

/* Legal page chrome: minimal top header (logo only) + bottom "Return
   home" CTA, used on stand-alone pages (Privacy, Accessibility) that
   don't render the main nav/footer. See partials/legal-header.php and
   partials/legal-footer.php. */
.legal-chrome-top {
  background: var(--bs-paper-bg);
  border-bottom: 1px solid var(--bs-border-color);
  padding: 1rem 0;
}
.legal-chrome-return {
  padding: 2rem 0 4rem;
  display: flex;
  justify-content: center;
  border-top: 1px solid var(--bs-border-color);
  background: var(--bs-paper-bg);
}

/* Cookie consent banner - see partials/cookie-consent-banner.php and
   assets/js/cookie-consent.js. Sits above the a11y widget's trigger, which
   shifts up out of the way (see .a11y-trigger's bottom calc above) while
   this is visible. */
.cookie-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1060;
  background: var(--bs-paper-bg);
  border-top: 1px solid var(--bs-border-color);
  box-shadow: 0 -0.5rem 1.5rem rgba(0, 0, 0, 0.12);
}
.cookie-banner[hidden] {
  display: none;
}
.cookie-banner-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 1rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.cookie-banner-title {
  font-weight: 700;
  margin-bottom: 0.125rem;
}
.cookie-banner-body {
  font-size: 0.875rem;
  color: var(--bs-secondary-color);
  margin-bottom: 0;
}
.cookie-banner-actions {
  display: flex;
  gap: 0.75rem;
  flex-shrink: 0;
}
@media (max-width: 575.98px) {
  .cookie-banner-inner {
    flex-direction: column;
    align-items: stretch;
  }
  .cookie-banner-actions {
    justify-content: flex-end;
  }
}
