/* ==========================================================================
   9dots - Design System Tokens
   --------------------------------------------------------------------------
   Single source of truth for spacing, sizing, radius, shadow and motion.
   Load BEFORE nd-overhaul.css, or paste this block at the top of it.

   Rule: no spacing or sizing value is written anywhere else in the project.
   If you need a number that isn't here, either it belongs here or the
   design is wrong.
   ========================================================================== */

:root {

  /* --- Colour bridge ------------------------------------------------------
     Colours live in Elementor Site Settings. These aliases let CSS reference
     them without hardcoding hex. Confirm the global IDs on your kit - custom
     colours use a hashed ID, not a readable name.                          */
  --nd-c-primary:   var(--e-global-color-primary,   #1c2b39);
  --nd-c-secondary: var(--e-global-color-secondary, #4a5a6a);
  --nd-c-text:      var(--e-global-color-text,      #33404d);
  --nd-c-accent:    var(--e-global-color-accent,    #0a7cba);
  --nd-c-surface:   #ffffff;
  --nd-c-surface-2: #f5f7f9;
  --nd-c-line:      rgba(28, 43, 57, .12);

  /* Muted body copy. Deliberately NOT --nd-c-secondary: the kit's Secondary
     is #C4C4C4, a light grey for dividers - unreadable as text on white.
     Maps to the kit's own #66758A (custom colour f482d3f) instead.        */
  --nd-c-muted:         var(--e-global-color-f482d3f, #66758A);

  /* Button hover. No Elementor button widget on this site sets a hover
     colour, so there is no global to bridge to - this is the value the
     contact form submit has always used (see nd-overhaul.css).            */
  --nd-c-primary-hover: #305994;

  /* --- Form controls ------------------------------------------------------
     Field height is not on the 8pt spacing scale on purpose: 60 / 56 is what
     the contact form has always used (nd-overhaul.css, wpcf7 block), and the
     search bar is the same species of control. Radius likewise matches the
     form, not the 8px card radius.                                        */
  --nd-field-h:      60px;
  --nd-field-h-sm:   56px;   /* <=767px */
  --nd-field-radius: 5px;

  /* --- Spacing scale ------------------------------------------------------
     Base 8, with 4 and 12 for tight interior work. Numeric names on purpose:
     nobody argues about whether something is "large" or "xl".              */
  --nd-space-1:  0.25rem;   /*   4px */
  --nd-space-2:  0.5rem;    /*   8px */
  --nd-space-3:  0.75rem;   /*  12px */
  --nd-space-4:  1rem;      /*  16px */
  --nd-space-5:  1.5rem;    /*  24px */
  --nd-space-6:  2rem;      /*  32px */
  --nd-space-7:  3rem;      /*  48px */
  --nd-space-8:  4rem;      /*  64px */
  --nd-space-9:  5rem;      /*  80px */
  --nd-space-10: 6rem;      /*  96px */
  --nd-space-11: 8rem;      /* 128px */

  /* --- Section rhythm -----------------------------------------------------
     Fluid, so you need far fewer responsive overrides. Three variants only. */
  --nd-sec-y-tight: clamp(2.5rem, 6vw,  4rem);   /*  40 -  64 */
  --nd-sec-y:       clamp(3.5rem, 8vw,  6rem);   /*  56 -  96 */
  --nd-sec-y-loose: clamp(4.5rem, 10vw, 8rem);   /*  72 - 128 */

  /* --- Layout ------------------------------------------------------------ */
  /* --nd-width is a cap for OPTIONAL boxed content. It is deliberately NOT
     applied to .nd-container - the Elementor pages are not boxed at all.
     See --nd-gutter-page below and the .nd-container rule.                  */
  --nd-width:        1200px;
  --nd-width-narrow: 880px;
  --nd-gutter:       clamp(1.25rem, 4vw, 1.5rem);

  /* Page side gutter. 95px is the padding-inline carried by the section
     containers on 34 of the 37 published Elementor pages, and by the header
     rows - it is what makes a coded template's left edge line up with the nav
     sitting above it. If it ever moves, change it here and in Elementor
     together. Mobile matches the pages' own padding_mobile.                 */
  --nd-gutter-page:        95px;
  --nd-gutter-page-mobile: 20px;
  --nd-measure:      68ch;     /* max line length for body copy              */

  /* --- Gaps -------------------------------------------------------------- */
  --nd-gap-col:       var(--nd-space-6);  /* between columns in a row        */
  --nd-gap-grid:      var(--nd-space-5);  /* between cards in a grid         */
  --nd-gap-stack-sm:  var(--nd-space-3);
  --nd-gap-stack-md:  var(--nd-space-4);
  --nd-gap-stack-lg:  var(--nd-space-5);

  /* --- Interior spacing -------------------------------------------------- */
  --nd-card-pad:    var(--nd-space-6);
  --nd-card-pad-sm: var(--nd-space-5);
  --nd-btn-pad-y:   var(--nd-space-3);
  --nd-btn-pad-x:   var(--nd-space-6);
  --nd-gap-eyebrow: var(--nd-space-2);   /* eyebrow to heading  */
  --nd-gap-lede:    var(--nd-space-4);   /* heading to body     */

  /* --- Radius ------------------------------------------------------------ */
  --nd-radius-sm:   4px;
  --nd-radius-md:   8px;
  --nd-radius-lg:   16px;
  --nd-radius-pill: 999px;

  /* --- Border and shadow --------------------------------------------------
     Two shadow levels. Not five.                                            */
  --nd-border-w: 1px;
  --nd-border:   var(--nd-border-w) solid var(--nd-c-line);
  --nd-shadow-1: 0 1px 2px rgba(28, 43, 57, .06), 0 2px 8px rgba(28, 43, 57, .06);
  --nd-shadow-2: 0 8px 28px rgba(28, 43, 57, .12);

  /* --- Icons ------------------------------------------------------------- */
  --nd-icon-sm: 20px;
  --nd-icon-md: 24px;
  --nd-icon-lg: 32px;
  --nd-icon-xl: 48px;

  /* --- Motion ------------------------------------------------------------ */
  --nd-dur:    200ms;
  --nd-ease:   cubic-bezier(.2, .6, .2, 1);
  --nd-lift-y: -4px;

  /* --- Sticky header ------------------------------------------------------
     Two states only: rest and scrolled. The rest values are NOT declared
     here - they stay in Elementor so the header is still editable in the
     builder. Only the scrolled state is owned by CSS.

     Tune the shrink here; nothing below needs touching.                    */
  --nd-header-z:            100;
  --nd-header-dur:          260ms;   /* slower than --nd-dur on purpose:
                                        a large block moving needs longer  */

  /* Top row (logo + search + language) - desktop/tablet only since the
     mobile redesign; the mobile row is a separate element. */
  --nd-header-top-y:        14px;    /* rest is 70 / 10 in Elementor       */

  /* Mobile row. Height is driven by the logo box, not the row itself -
     the row has no padding of its own. */
  --nd-header-mob-box-h:    56px;    /* rest is 80px min-height            */
  --nd-header-mob-box-y:    10px;    /* rest is 20px padding              */

  /* Nav row */
  --nd-header-nav-h:        40px;    /* rest is 58px min-height            */
  --nd-header-nav-item-y:   6px;     /* rest is 12px menu item padding     */

  /* Logo
     Percentages of the logo's own container, matching how Elementor sizes it.
     At a 1440 viewport: 38% = 247px wide, 32% = 208px. Halving the shrink
     rather than deepening it - at 26% the logo read as smaller than the nav
     text beside it once the top row padding tightened. */
  --nd-header-logo-w:       32%;     /* rest is 38%  -> 84% of original.
                                        Desktop row only - the mobile logo is
                                        width:auto and is left at its design
                                        size; the mobile box shrinks instead. */
}

/* --------------------------------------------------------------------------
   Colour bridge, part 2 - REQUIRED, do not remove.

   Elementor declares its --e-global-color-* variables on .elementor-kit-6,
   which is a class on <body> - not on :root. A var() lookup resolves against
   the element where the property is DECLARED, so the aliases above compute at
   :root (<html>), find no --e-global-color-* there, and silently resolve to
   their fallback hexes. The fallbacks then inherit down to the whole document
   and the bridge does nothing at all - no error, no warning, just the wrong
   colours everywhere.

   Re-declaring the kit-dependent aliases on body makes them resolve where the
   kit variables actually live. Values inherit from there as normal. The :root
   block above is kept as the safety net for contexts with no Elementor kit
   CSS (login, some REST/admin views, kit CSS not yet regenerated).

   Verified 2026-09-02 against post-6.css: primary #004282, secondary #C4C4C4,
   text #000000, accent #004282. If the kit is ever rebuilt under a new ID the
   class name changes but this selector does not - it targets body, not the
   kit class, so it keeps working.
   -------------------------------------------------------------------------- */
body {
  --nd-c-primary:   var(--e-global-color-primary,   #1c2b39);
  --nd-c-secondary: var(--e-global-color-secondary, #4a5a6a);
  --nd-c-text:      var(--e-global-color-text,      #33404d);
  --nd-c-accent:    var(--e-global-color-accent,    #0a7cba);
  --nd-c-muted:     var(--e-global-color-f482d3f,   #66758A);
}


/* ==========================================================================
   Utilities
   --------------------------------------------------------------------------
   Applied through Elementor's class fields:
     containers -> css_classes      (no underscore)
     widgets    -> _css_classes     (with underscore)

   The .elementor-element variants set Elementor's own container custom
   properties rather than fighting its generated CSS. An explicit value set
   in the Style tab still wins, which is the behaviour you want - but leave
   padding and gap EMPTY in the editor so these classes are what applies.

   Verify the custom property names against a compiled post-{ID}.css on your
   4.2.1 install before relying on them; the fallback declarations below
   cover you either way.
   ========================================================================== */

/* --- Section rhythm ----------------------------------------------------- */
.nd-sec               { padding-block: var(--nd-sec-y); }
.nd-sec--tight        { padding-block: var(--nd-sec-y-tight); }
.nd-sec--loose        { padding-block: var(--nd-sec-y-loose); }
.nd-sec--flush-top    { padding-block-start: 0; }
.nd-sec--flush-bottom { padding-block-end: 0; }

.elementor-element.nd-sec {
  --padding-top: var(--nd-sec-y);
  --padding-bottom: var(--nd-sec-y);
}
.elementor-element.nd-sec--tight {
  --padding-top: var(--nd-sec-y-tight);
  --padding-bottom: var(--nd-sec-y-tight);
}
.elementor-element.nd-sec--loose {
  --padding-top: var(--nd-sec-y-loose);
  --padding-bottom: var(--nd-sec-y-loose);
}
.elementor-element.nd-sec--flush-top    { --padding-top: 0px; }
.elementor-element.nd-sec--flush-bottom { --padding-bottom: 0px; }

/* --- Widths ------------------------------------------------------------- */
.nd-narrow  { max-width: var(--nd-width-narrow); margin-inline: auto; }
.nd-measure { max-width: var(--nd-measure); }
.elementor-element.nd-narrow { --content-width: var(--nd-width-narrow); }

/* Full page-width wrapper for coded (non-Elementor) templates only -
   template-parts/search.php, 404, etc.

   Matched to how the Elementor pages ACTUALLY lay out, which is not a boxed
   max-width: every section container on the site is content_width:"full" /
   width:100% with padding-inline:95px, so the content band is the viewport
   minus 190px and is never capped. Verified across 34 of 37 published pages.
   Site Settings > Layout reads 1440px, but nothing on the site is boxed, so
   that number never applies to anything.

   Capping this at --nd-width put the search page's left edge ~175px inside
   every other page's at 1680px wide, and further in on larger screens - that
   was the visible mismatch. Do not reintroduce a max-width here without
   changing the Elementor containers to match. */
.nd-container { padding-inline: var(--nd-gutter-page); }

/* Hello Elementor's theme.css caps main.site-main at 1140px (and lower at the
   smaller breakpoints). The Elementor pages never meet that cap: they use the
   elementor_header_footer page template, which renders no .site-main at all,
   so their content is full-bleed. A coded template goes through index.php and
   DOES get the cap - that is the other half of this mismatch, and the half
   that gutter padding alone cannot fix. Released only where .nd-container is
   already taking responsibility for the gutter.

   SPECIFICITY - the theme's rule is:
     body:not([class*="elementor-page-"]) .site-main   ->  0-2-1
   (:not() carries its argument's specificity, and body adds the element.)
   A bare .site-main:has(.nd-container) is only 0-2-0 and loses. The html
   prefix takes this to 0-2-2 so it wins outright rather than on load order.
   Do not trim the leading html/body. */
html body .site-main:has(.nd-container) { max-width: none; }

@media (max-width: 767px) {
    .nd-container { padding-inline: var(--nd-gutter-page-mobile); }
}

/* --- Stack gaps --------------------------------------------------------- */
.nd-stack-sm { gap: var(--nd-gap-stack-sm); }
.nd-stack-md { gap: var(--nd-gap-stack-md); }
.nd-stack-lg { gap: var(--nd-gap-stack-lg); }
.elementor-element.nd-stack-sm { --gap: var(--nd-gap-stack-sm); --row-gap: var(--nd-gap-stack-sm); }
.elementor-element.nd-stack-md { --gap: var(--nd-gap-stack-md); --row-gap: var(--nd-gap-stack-md); }
.elementor-element.nd-stack-lg { --gap: var(--nd-gap-stack-lg); --row-gap: var(--nd-gap-stack-lg); }

/* --- Card grids ---------------------------------------------------------
   3 / 2 / 1 across the three breakpoints. Use these instead of building
   column containers by hand - it is one class instead of nine settings.   */
.nd-grid-2,
.nd-grid-3,
.nd-grid-4 {
  display: grid;
  gap: var(--nd-gap-grid);
}
.nd-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.nd-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.nd-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 1024px) {
  .nd-grid-3, .nd-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .nd-grid-2, .nd-grid-3, .nd-grid-4 { grid-template-columns: minmax(0, 1fr); }
}

/* --- Card --------------------------------------------------------------- */
.nd-card {
  padding: var(--nd-card-pad);
  background: var(--nd-c-surface);
  border: var(--nd-border);
  border-radius: var(--nd-radius-md);
}
.nd-card--sm    { padding: var(--nd-card-pad-sm); }
.nd-card--flat  { border: 0; background: var(--nd-c-surface-2); }
.nd-card--raised{ border: 0; box-shadow: var(--nd-shadow-1); }

/* --- Media ratios -------------------------------------------------------
   The standard non-designers collide with most. Keeps the site tidy when
   the client adds content later.                                          */
.nd-ratio-hero img,  .nd-ratio-hero  { aspect-ratio: 16 / 9; object-fit: cover; }
.nd-ratio-card img,  .nd-ratio-card  { aspect-ratio: 4 / 3;  object-fit: cover; }
.nd-ratio-square img,.nd-ratio-square{ aspect-ratio: 1 / 1;  object-fit: cover; }
.nd-ratio-logo img,  .nd-ratio-logo  { aspect-ratio: 3 / 2;  object-fit: contain; }

/* --- Icons -------------------------------------------------------------- */
.nd-icon-sm svg, .nd-icon-sm i { font-size: var(--nd-icon-sm); width: var(--nd-icon-sm); height: var(--nd-icon-sm); }
.nd-icon-md svg, .nd-icon-md i { font-size: var(--nd-icon-md); width: var(--nd-icon-md); height: var(--nd-icon-md); }
.nd-icon-lg svg, .nd-icon-lg i { font-size: var(--nd-icon-lg); width: var(--nd-icon-lg); height: var(--nd-icon-lg); }
.nd-icon-xl svg, .nd-icon-xl i { font-size: var(--nd-icon-xl); width: var(--nd-icon-xl); height: var(--nd-icon-xl); }

/* --- Motion -------------------------------------------------------------
   nd-lift needs a base transform present or the transition has nothing to
   interpolate from. That base is declared here, not per element.          */
.nd-lift {
  transform: translateY(0);
  transition: transform var(--nd-dur) var(--nd-ease),
              box-shadow var(--nd-dur) var(--nd-ease);
}
.nd-lift:hover,
.nd-lift:focus-within {
  transform: translateY(var(--nd-lift-y));
  box-shadow: var(--nd-shadow-2);
}

@media (prefers-reduced-motion: reduce) {
  .nd-lift { transition: none; }
  .nd-lift:hover, .nd-lift:focus-within { transform: translateY(0); }
}
