@charset "UTF-8";
/* ==========================================================================
   Invelo Agency — Global Design System
   Sprint 00 · v0.1.0 · slug invelo-global-kit

   System-level CSS only. Nothing in this file is page-specific, and nothing
   here animates: motion belongs to the cinematic engine in a later sprint.

   Two halves:
     1. The :root token block, GENERATED from config/design-tokens.json.
        Edit the manifest, then run `node tools/build-css.mjs`.
     2. Hand-written utility classes and Elementor defaults, which consume
        those tokens and never restate a literal value.
   ========================================================================== */

/* == GENERATED TOKENS — BEGIN ==
   Generated by tools/build-css.mjs from config/design-tokens.json.
   Kit Invelo Agency — Global Design System v0.3.1.
   Do not hand-edit between these markers — edit the manifest and re-run. */

  /* Self-hosted, so the production site makes no fonts.googleapis.com or
     fonts.gstatic.com request. The setup plugin also switches Elementor's own
     Google Fonts loader off, because naming a family in the kit is otherwise
     enough to make Elementor fetch it. */
  /* Display — Soliden Trial Bold → Archivo 800
     SIL Open Font License 1.1 — assets/fonts/LICENSE-Archivo.txt */
  @font-face {
    font-family: 'Archivo';
    src: url('fonts/archivo-800.woff2') format('woff2');
    font-weight: 800;
    font-style: normal;
    font-display: swap;
  }
  /* Body / Navigation — Poppins Regular → Poppins 400
     SIL Open Font License 1.1 — assets/fonts/LICENSE-Poppins.txt */
  @font-face {
    font-family: 'Poppins';
    src: url('fonts/poppins-400.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }
  /* Numerals / Metrics — Nexa Bold → Outfit 700
     SIL Open Font License 1.1 — assets/fonts/LICENSE-Outfit.txt */
  @font-face {
    font-family: 'Outfit';
    src: url('fonts/outfit-700.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
  }

:root {

  /* Brand colour ramp */
  --invelo-orange-1: #F04E23;   /* Orange 1 */
  --invelo-orange-2: #F15722;   /* Orange 2 */
  --invelo-orange-3: #F46F20;   /* Orange 3 */
  --invelo-orange-4: #F8961C;   /* Orange 4 */
  --invelo-orange-5: #FAA61A;   /* Orange 5 */
  --invelo-orange-ink-on-light: #D3451F;   /* Orange Ink on Light — brand orange darkened to clear 4.5:1 on white */
  --invelo-brand-gradient: linear-gradient(90deg, #F04E23 0%, #F15722 19%, #F46F20 49%, #F8961C 87%, #FAA61A 100%);
  --invelo-cta-ink: #111111;   /* PM Revision 01: dark label, 5.23:1-9.47:1 across the ramp. .invelo-btn--ink-light reverts it */

  /* Surfaces */
  --invelo-black: #000000;   /* Invelo Black */
  --invelo-white: #FFFFFF;   /* Invelo White */
  --invelo-near-black: #090909;   /* Near Black */
  --invelo-surface: #111111;   /* Dark Surface */
  --invelo-surface-elevated: #171717;   /* Dark Surface Elevated */

  /* Ink */
  --invelo-text-primary: #FFFFFF;   /* Text Primary */
  --invelo-text-muted: rgba(255,255,255,0.72);   /* Text Muted */
  --invelo-text-soft: rgba(255,255,255,0.55);   /* Text Soft */
  --invelo-text-dark: #111111;   /* Text Dark */
  --invelo-text-dark-muted: #555555;   /* Text Dark Muted */

  /* Borders */
  --invelo-glass-border: rgba(255,255,255,0.25);   /* Glass Border */
  --invelo-soft-border: rgba(255,255,255,0.14);   /* Soft Border */
  --invelo-dark-border: rgba(0,0,0,0.12);   /* Dark Border */

  /* Layout — content is boxed, scenes are not */
  --invelo-container-max: 1440px;   /* Figma canvas 1728. (1728 - 1440) / 2 = 144. At the 1728 baseline the container is exactly 1440 wide and its first usable pixel is x=144, so a coordinate read off the comp maps straight onto the build. */
  --invelo-page-gutter-desktop: 48px;
  --invelo-page-gutter-tablet: 32px;
  --invelo-page-gutter-mobile: 22px;
  --invelo-page-gutter: var(--invelo-page-gutter-desktop);   /* re-pointed per breakpoint below */
  --invelo-gutter: var(--invelo-page-gutter);   /* deprecated alias — use --invelo-page-gutter */

  /* Radius */
  --invelo-radius-sm: 12px;
  --invelo-radius-md: 20px;
  --invelo-radius-lg: 28px;
  --invelo-radius-pill: 999px;

  /* Spacing */
  --invelo-space-xs: 8px;
  --invelo-space-sm: 16px;
  --invelo-space-md: 24px;
  --invelo-space-lg: 40px;
  --invelo-space-xl: 64px;
  --invelo-space-2xl: 96px;
  --invelo-space-3xl: 144px;

  /* Glass */
  --invelo-glass-bg: linear-gradient(150deg, rgba(201,201,201,0.18), rgba(196,196,196,0.04));
  --invelo-glass-bg-flat: rgba(190,190,190,0.12);   /* used when transparency is reduced */
  --invelo-glass-stroke: rgba(255,255,255,0.20);   /* what .invelo-glass draws — see glass.borderNote */
  --invelo-glass-blur: 20px;

  /* Type families — display and metric are TEMPORARY licensed-font fallbacks */
  --invelo-font-display: Archivo, 'Archivo ExtraBold', 'Helvetica Neue', Arial, sans-serif;   /* Soliden Trial Bold → Archivo 800 */
  --invelo-font-body: Poppins, 'Helvetica Neue', Arial, sans-serif;   /* Poppins Regular → Poppins 400 */
  --invelo-font-metric: Outfit, 'Helvetica Neue', Arial, sans-serif;   /* Nexa Bold → Outfit 700 */
  --invelo-weight-display: 800;
  --invelo-weight-body: 400;
  --invelo-weight-metric: 700;

  /* Type scale — clamp() equivalents of the kit's per-breakpoint sizes */
  --invelo-fs-display-xl: clamp(50px, 5vw, 96px);   /* Display XL */
  --invelo-fs-display-l: clamp(42px, 4vw, 72px);   /* Display L */
  --invelo-fs-h2: clamp(34px, 3.2vw, 56px);   /* Heading H2 */
  --invelo-fs-h3: clamp(26px, 2.1vw, 36px);   /* Heading H3 */
  --invelo-fs-body-lg: clamp(18px, 1.2vw, 20px);   /* Body Large */
  --invelo-fs-body: clamp(16px, 1.05vw, 18px);   /* Body */
  --invelo-fs-body-sm: clamp(15px, 0.95vw, 16px);   /* Body Small */
  --invelo-fs-nav: 16px;   /* Navigation */
  --invelo-fs-eyebrow: clamp(14px, 0.95vw, 16px);   /* Eyebrow */
  --invelo-fs-metric: clamp(48px, 4.2vw, 72px);   /* Metric */

  /* Buttons */
  --invelo-btn-min-h: 56px;
  --invelo-btn-min-h-mobile: 52px;
  --invelo-btn-pad-x: 34px;
  --invelo-btn-pad-x-mobile: 26px;
  --invelo-btn-glow: 0 10px 30px rgba(244,118,32,0.32);
  --invelo-cta-circle: 48px;
  --invelo-cta-circle-mobile: 44px;
  --invelo-tap-min: 44px;

  /* Forms */
  --invelo-field-h: 56px;
  --invelo-field-bg: rgba(255,255,255,0.05);
  --invelo-field-border: rgba(255,255,255,0.18);
  --invelo-field-placeholder: rgba(255,255,255,0.45);
  --invelo-field-focus: #F8961C;
  --invelo-field-focus-glow: 0 0 0 3px rgba(248,150,28,0.28);

  /* Focus ring */
  --invelo-focus-width: 2px;
  --invelo-focus-offset: 3px;
  --invelo-focus-color: #FFFFFF;
  --invelo-focus-color-light: #D8410F;

  /* Header — variables only, the template is a later sprint */
  --invelo-header-height-desktop: 110px;
  --invelo-header-height-mobile: 88px;
  --invelo-header-height: var(--invelo-header-height-desktop);
  --invelo-header-z: 9999;
  /* == GENERATED TOKENS — END == */
}


/* == 1. Page defaults =====================================================
   Elementor and Hello Elementor both ship opinionated defaults. These
   replace them, and are the first line of defence against Elementor blue.
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--invelo-black);
  color: var(--invelo-text-primary);
  font-family: var(--invelo-font-body);
  font-size: var(--invelo-fs-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Horizontal overflow is clipped on the page wrapper only. `clip` rather than
   `hidden` because `hidden` on an ancestor silently kills position: sticky,
   which the cinematic sections depend on. Vertical overflow is never touched. */
body,
.elementor,
.site-main,
#page {
  overflow-x: clip;
}

img,
video,
svg { max-width: 100%; }

img { height: auto; }


/* == 2. Container =========================================================
   Only CONTENT is boxed. Scene backgrounds — black, orange, white, video,
   transition planes, atmospheric effects — stay full viewport width, which is
   why the width lives on the container and never on the scene.

   1728 (Figma canvas) - 1440 = 288; 288 / 2 = 144. A 1440px box on the
   original canvas reproduces its 144px side gutters exactly.
   -------------------------------------------------------------------------- */
/* THE GUTTER GOES HERE AND NOWHERE ELSE.

   An earlier revision padded `.e-con-boxed > .e-con-inner`, i.e. every boxed
   Elementor container on the site. Elementor uses `.e-con` for NESTED
   containers as well as top-level ones, so that padding compounds: a widget
   three containers deep sat 144px in on desktop instead of 48, and the error
   grew with the nesting depth rather than showing up as one obvious mistake.

   So the page gutter is opt-in. A section's OUTERMOST content container gets
   the `invelo-container` CSS class; everything nested inside it gets nothing
   and stays flush. Nested containers may of course still carry their own
   padding for their own design — they just never inherit the page gutter. */
/* 1440 IS THE CONTENT SPAN, NOT THE BOX AROUND IT.

   Revision 01 had `max-width: 1440px` plus `padding-inline: 48px`, which at the
   1728 Figma baseline gave a 1440 box with only 1344 of usable width and a first
   content pixel at x=192. The Figma baseline is a 1440 content span starting at
   x=144, so every coordinate taken from the comp would have been 48px out — and
   the Hero is about to be mapped from exactly those coordinates.

   The gutter is a MINIMUM VIEWPORT MARGIN for narrower screens, not padding
   inside an already-constrained content area. Expressing it as a width rather
   than as padding is what makes it behave that way: the container is as wide as
   the viewport allows minus one gutter each side, and stops growing at 1440.

     1728 → min(1632, 1440) = 1440, centred, left edge 144   ← the Figma baseline
     1440 → min(1344, 1440) = 1344, left edge 48
     1024 → min( 960, 1440) =  960, left edge 32
      768 → min( 704, 1440) =  704, left edge 32
      390 → min( 346, 1440) =  346, left edge 22

   padding-inline is 0 by design: with border-box, width IS the usable content
   width, so the number in the CSS is the number a designer measures. */
.invelo-container,
.e-con.invelo-container {
  width: min(calc(100% - (2 * var(--invelo-page-gutter))), var(--invelo-container-max));
  max-width: var(--invelo-container-max);
  margin-inline: auto;
  padding-inline: 0;
}

/* Elementor puts a boxed container's width on its inner wrapper, so when the
   class lands on the `.e-con` itself the inner has to be told to fill its
   parent — otherwise Elementor's own Content Width re-constrains it and the
   geometry above is quietly undone one level down. */
.e-con.invelo-container > .e-con-inner {
  width: 100%;
  max-width: none;
  padding-inline: 0;
}

/* A full-bleed container inside a boxed one — for scene backgrounds that have
   to escape the 1440 box without leaving the document flow. */
.invelo-bleed {
  width: 100vw;
  max-width: 100vw;
  margin-inline: calc(50% - 50vw);
}


/* == 3. Scenes ============================================================
   Full viewport-width environmental sections. A scene owns a background and
   an ink colour; it never owns a width.
   -------------------------------------------------------------------------- */
.invelo-scene {
  position: relative;
  width: 100%;
  padding-block: clamp(56px, 8vw, 144px);
}

.invelo-scene--black  { background: var(--invelo-black); color: var(--invelo-text-primary); }
.invelo-scene--white  { background: var(--invelo-white); color: var(--invelo-text-dark); }
.invelo-scene--orange {
  background: linear-gradient(180deg, var(--invelo-orange-1) 0%, var(--invelo-orange-3) 52%, var(--invelo-orange-5) 100%);
  color: var(--invelo-white);
}

/* Marker class for future cinematic stages. Deliberately inert: no pin, no
   scroll behaviour, no transform. The engine attaches all of that later. */
.invelo-stage { position: relative; }


/* == 4. Typography ========================================================
   Ten roles. The Elementor kit stores per-breakpoint pixel sizes because its
   size control is a numeric slider; these classes carry the clamp() equivalent
   of the same scale, so a value set in Elementor and a value set in CSS agree.
   -------------------------------------------------------------------------- */
.invelo-display-xl,
.invelo-display-l,
.invelo-h2,
.invelo-h3,
.invelo-display {
  font-family: var(--invelo-font-display);
  font-weight: var(--invelo-weight-display);
  margin: 0;
}

.invelo-display-xl { font-size: var(--invelo-fs-display-xl); line-height: .95; letter-spacing: -.02em; }
.invelo-display-l  { font-size: var(--invelo-fs-display-l);  line-height: 1;   letter-spacing: -.02em; }
.invelo-h2         { font-size: var(--invelo-fs-h2);         line-height: 1;   letter-spacing: -.015em; }
.invelo-h3         { font-size: var(--invelo-fs-h3);         line-height: 1.15; letter-spacing: -.01em; }

.invelo-body-lg,
.invelo-body,
.invelo-body-sm,
.invelo-nav,
.invelo-eyebrow {
  font-family: var(--invelo-font-body);
  font-weight: var(--invelo-weight-body);
  margin: 0;
}

.invelo-body-lg { font-size: var(--invelo-fs-body-lg); line-height: 1.45; }
.invelo-body    { font-size: var(--invelo-fs-body);    line-height: 1.5; }
.invelo-body-sm { font-size: var(--invelo-fs-body-sm); line-height: 1.5; }
.invelo-nav     { font-size: var(--invelo-fs-nav);     line-height: 1.4; }

.invelo-eyebrow {
  font-size: var(--invelo-fs-eyebrow);
  line-height: 1.3;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--invelo-text-muted);
}

.invelo-metric {
  font-family: var(--invelo-font-metric);
  font-weight: var(--invelo-weight-metric);
  font-size: var(--invelo-fs-metric);
  line-height: .95;
  letter-spacing: -.01em;
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.invelo-text-muted { color: var(--invelo-text-muted); }
.invelo-text-soft  { color: var(--invelo-text-soft); }

/* --- Light surfaces ------------------------------------------------------
   The ink tokens are written for the dark environment, which is the site's
   default — but the same components have to survive the white scene and the
   light card. Rather than have every utility class carry two colours, the
   light surfaces re-point the three ink variables once, and everything that
   consumes them inverts with no further rules.

   This was a real bug before it was a principle: .invelo-eyebrow resolved to
   rgba(255,255,255,.72) inside .invelo-card--light, i.e. white on white. */
.invelo-scene--white,
.invelo-card--light {
  --invelo-text-primary: #111111;
  --invelo-text-muted: rgba(0, 0, 0, 0.68);
  --invelo-text-soft: rgba(0, 0, 0, 0.52);
  --invelo-focus-color: var(--invelo-focus-color-light);
}

/* The orange scene keeps white ink but needs more of it — 72% white on a mid
   orange is under 4.5:1. */
.invelo-scene--orange {
  --invelo-text-muted: rgba(255, 255, 255, 0.92);
  --invelo-text-soft: rgba(255, 255, 255, 0.80);
}

/* Brand gradient as text. `fit-content` matters: without it the gradient box is
   the full width of the parent and a short word only ever shows the red end of
   the ramp instead of a sweep across the word. */
.invelo-gradient-text {
  display: inline-block;
  width: fit-content;
  background: var(--invelo-brand-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* Forced-colors and print both flatten the clip, which would render the text
   invisible. Give it a real colour back in those modes. */
@media (forced-colors: active), print {
  .invelo-gradient-text {
    background: none;
    color: var(--invelo-orange-3);
    -webkit-text-fill-color: currentColor;
  }
}


/* == 5. Links =============================================================
   Navigation is never underlined. Links inside body copy carry a dotted rule
   so they are distinguishable without relying on colour alone.
   -------------------------------------------------------------------------- */
a { color: var(--invelo-white); text-decoration: none; }
a:hover,
a:focus-visible { color: var(--invelo-orange-4); }

.invelo-prose a,
.entry-content a {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  text-decoration-color: rgba(255, 255, 255, .45);
}
.invelo-prose a:hover,
.entry-content a:hover { text-decoration-color: currentColor; }

.invelo-scene--white a,
.invelo-card--light a { color: var(--invelo-text-dark); }
/* Orange 1 as text on white is 3.61:1 and Orange 3 is 2.94:1 — both fail AA.
   --invelo-orange-ink-on-light is Orange 1 darkened to 4.53:1 and exists for
   exactly this case. The brand ramp itself is untouched; this token is only
   for brand orange that has to be READ, not for orange that is a surface. */
.invelo-scene--white a:hover,
.invelo-card--light a:hover { color: var(--invelo-orange-ink-on-light); }
.invelo-scene--white .invelo-prose a { text-decoration-color: rgba(0, 0, 0, .45); }

/* Same reasoning for gradient text: the light ramp is unreadable on white, so
   on light surfaces the sweep runs over the darkened end of the brand. */
.invelo-scene--white .invelo-gradient-text,
.invelo-card--light .invelo-gradient-text {
  background: linear-gradient(90deg, #B8360F 0%, var(--invelo-orange-ink-on-light) 100%);
  -webkit-background-clip: text;
  background-clip: text;
}


/* == 6. Buttons ===========================================================
   One pill, three skins. Hover is a 1px lift and a slightly stronger glow —
   never a scale. Every variant clears the 44px tap-target minimum.
   -------------------------------------------------------------------------- */
.invelo-btn {
  --_glow: 0 0 0 rgba(0, 0, 0, 0);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--invelo-space-sm);
  min-height: var(--invelo-btn-min-h);
  padding-inline: var(--invelo-btn-pad-x);
  border: 0;
  border-radius: var(--invelo-radius-pill);
  font-family: var(--invelo-font-body);
  font-size: var(--invelo-fs-nav);
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--_glow);
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease;
}

/* CONTRAST — SETTLED IN PM REVISION 01.
   The label is dark by default. White on this gradient measures 3.61:1 at the
   darkest stop and 1.99:1 at the lightest, and WCAG AA wants 4.5:1 at the 16px
   the label is set in — it cannot pass anywhere along the ramp. #111111 passes
   across the whole of it, 5.23:1 to 9.47:1.

   .invelo-btn--ink-light restores a white label for a deliberate exception. It
   does not pass AA at label size; use it only where the type is large. */
.invelo-btn--primary {
  background: var(--invelo-brand-gradient);
  color: var(--invelo-cta-ink);
}
.invelo-btn--primary:hover {
  --_glow: var(--invelo-btn-glow);
  transform: translateY(-1px);
  color: var(--invelo-cta-ink);
}
/* Deliberate exception only — see the note above. */
.invelo-btn--ink-light { --invelo-cta-ink: #FFFFFF; }

.invelo-btn--glass {
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--invelo-glass-stroke);
  color: var(--invelo-white);
}
.invelo-btn--glass:hover {
  background: rgba(255, 255, 255, .13);
  transform: translateY(-1px);
  color: var(--invelo-white);
}

/* On the white scene the glass button has to invert or it disappears. */
.invelo-scene--white .invelo-btn--glass {
  background: rgba(0, 0, 0, .04);
  border-color: var(--invelo-dark-border);
  color: var(--invelo-text-dark);
}
.invelo-scene--white .invelo-btn--glass:hover { background: rgba(0, 0, 0, .08); }

/* --- CTA with the circular arrow -----------------------------------------
   [ label                              ( → ) ]
   The circle is inset from the right edge and vertically centred, so the pill
   keeps its height whatever the label length. The arrow is an inline SVG in
   the markup — no icon library is loaded for one glyph. */
.invelo-cta-arrow {
  justify-content: space-between;
  gap: var(--invelo-space-lg);
  padding-right: calc((var(--invelo-btn-min-h) - var(--invelo-cta-circle)) / 2);
  padding-left: var(--invelo-btn-pad-x);
  text-align: left;
}
.invelo-cta-arrow__label { display: block; }
/* White circle, dark arrow — unchanged by the label colour. The approved
   treatment, and it reads on both variants. */
.invelo-cta-arrow__circle {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: var(--invelo-cta-circle);
  height: var(--invelo-cta-circle);
  border-radius: 50%;
  background: var(--invelo-white);
  color: var(--invelo-text-dark);
}
.invelo-cta-arrow__circle svg {
  width: 45%;
  height: auto;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}


/* == 7. Glass =============================================================
   Reusable for the nav pill, cards, proof elements and metric cards. Applied
   ONLY through this class — Elementor containers are never glass by default.
   -------------------------------------------------------------------------- */
.invelo-glass {
  background: var(--invelo-glass-bg);
  border: 1px solid var(--invelo-glass-stroke);
  border-radius: var(--invelo-radius-md);
  -webkit-backdrop-filter: blur(var(--invelo-glass-blur));
  backdrop-filter: blur(var(--invelo-glass-blur));
}

/* backdrop-filter is the most expensive thing this system can ask for, and
   "Reduce Transparency" is an explicit request not to have it. Honour it with
   a flat surface that keeps the same contrast. */
@media (prefers-reduced-transparency: reduce) {
  .invelo-glass {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--invelo-glass-bg-flat);
  }
}
/* "neither property is supported", written as nested @supports rather than
   `not ((a) or (b))`. The two are logically identical, but the single-condition
   form parses in every validator and older engine; the disjunction form is
   rejected by some CSS parsers even though browsers accept it. */
@supports not (backdrop-filter: blur(1px)) {
  @supports not (-webkit-backdrop-filter: blur(1px)) {
    .invelo-glass,
    .invelo-card--glass { background: var(--invelo-glass-bg-flat); }
  }
}


/* == 8. Cards =============================================================
   Clean and premium, not SaaS dashboard: no drop shadows by default.
   -------------------------------------------------------------------------- */
.invelo-card {
  border-radius: var(--invelo-radius-md);
  padding: clamp(22px, 2vw, 28px);
}
.invelo-card--feature { border-radius: var(--invelo-radius-lg); }

.invelo-card--glass {
  background: var(--invelo-glass-bg);
  border: 1px solid var(--invelo-glass-stroke);
  -webkit-backdrop-filter: blur(var(--invelo-glass-blur));
  backdrop-filter: blur(var(--invelo-glass-blur));
}
@media (prefers-reduced-transparency: reduce) {
  .invelo-card--glass {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--invelo-glass-bg-flat);
  }
}

.invelo-card--dark {
  background: var(--invelo-surface);
  border: 1px solid rgba(255, 255, 255, .10);
  color: var(--invelo-text-primary);
}
.invelo-card--light {
  background: var(--invelo-white);
  border: 1px solid var(--invelo-dark-border);
  color: var(--invelo-text-dark);
}
/* .invelo-card--light .invelo-text-muted needs no rule: the light-surface
   block above re-points --invelo-text-muted, so the utility class inverts on
   its own. */


/* == 9. Images ============================================================ */
.invelo-image-card {
  border-radius: var(--invelo-radius-md);
  overflow: hidden;
  background: var(--invelo-surface);
  display: block;
}
.invelo-image-card img,
.invelo-image-card > picture > img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}


/* == 10. Forms ============================================================
   Elementor Pro styles form fields per-widget and Site Settings exposes no
   global form control, so the kit reaches every form from here instead of
   asking each template to restate it.
   -------------------------------------------------------------------------- */
.invelo-field,
.elementor-field-group .elementor-field-textual,
.invelo-form input[type="text"],
.invelo-form input[type="email"],
.invelo-form input[type="tel"],
.invelo-form input[type="url"],
.invelo-form input[type="number"],
.invelo-form select,
.invelo-form textarea {
  width: 100%;
  min-height: var(--invelo-field-h);
  padding: 0 18px;
  background: var(--invelo-field-bg);
  border: 1px solid var(--invelo-field-border);
  border-radius: var(--invelo-radius-sm);
  color: var(--invelo-text-primary);
  font-family: var(--invelo-font-body);
  font-size: var(--invelo-fs-body-sm);
  line-height: 1.4;
  transition: border-color .18s ease, box-shadow .18s ease;
}

.invelo-form textarea,
.elementor-field-group textarea.elementor-field-textual {
  min-height: calc(var(--invelo-field-h) * 2.4);
  padding: 16px 18px;
  resize: vertical;
}

.invelo-field::placeholder,
.elementor-field-group .elementor-field-textual::placeholder,
.invelo-form ::placeholder { color: var(--invelo-field-placeholder); opacity: 1; }

/* Focus is signalled by TWO things — the border doubles in width as well as
   changing colour — so it is never carried by colour alone. */
.invelo-field:focus,
.invelo-field:focus-visible,
.elementor-field-group .elementor-field-textual:focus,
.invelo-form :is(input, select, textarea):focus {
  outline: none;
  border-width: 2px;
  border-color: var(--invelo-field-focus);
  box-shadow: var(--invelo-field-focus-glow);
  padding-inline: 17px;                 /* keep the text from shifting 1px */
}

.invelo-label,
.elementor-field-label {
  display: block;
  margin-bottom: var(--invelo-space-xs);
  font-family: var(--invelo-font-body);
  font-size: var(--invelo-fs-body-sm);
  color: var(--invelo-text-muted);
}

/* Light variant, for forms sitting on the white scene.

   Re-points the field variables rather than overriding the properties. The
   first attempt did the latter and silently lost: the base rule's
   `.invelo-form input[type="text"]` is specificity (0,2,1) — a class, an
   element and an attribute — while `.invelo-form--light .invelo-field` is only
   (0,2,0), so the dark field survived on a white card and the input vanished
   into the background. Variables sidestep the whole contest: the base rule
   already reads every colour from a custom property, so re-pointing the
   property is enough and no specificity war can happen. */
.invelo-scene--white,
.invelo-form--light,
.invelo-card--light {
  --invelo-field-bg: #FFFFFF;
  --invelo-field-border: rgba(0, 0, 0, 0.18);
  --invelo-field-placeholder: #767676;
  --invelo-field-focus: #D8410F;
  --invelo-field-focus-glow: 0 0 0 3px rgba(216, 65, 15, 0.22);
}


/* == 11. Focus ============================================================
   focus-visible only, so a mouse click never draws a ring but a keyboard tab
   always does.
   -------------------------------------------------------------------------- */
:where(a, button, [role="button"], summary, [tabindex]):focus-visible {
  outline: var(--invelo-focus-width) solid var(--invelo-focus-color);
  outline-offset: var(--invelo-focus-offset);
  border-radius: var(--invelo-radius-sm);
}

.invelo-scene--white :where(a, button, [role="button"], summary, [tabindex]):focus-visible,
.invelo-card--light :where(a, button, [role="button"]):focus-visible {
  outline-color: var(--invelo-focus-color-light);
}

.invelo-skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: calc(var(--invelo-header-z) + 1);
  padding: 12px 18px;
  background: var(--invelo-white);
  color: var(--invelo-text-dark);
  border-radius: 0 0 var(--invelo-radius-sm) 0;
}
.invelo-skip-link:focus { left: 0; }

.invelo-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* == 12. Elementor widget defaults ========================================
   Elementor's Site Settings cover most of this, but a handful of its widget
   styles are hard-coded and would otherwise put default blue or Roboto on the
   page. These are the specific overrides that stop that.
   -------------------------------------------------------------------------- */
/* Heading tags carry their role's SIZE here, not only its family.

   The kit writes h1_typography_* … h6_typography_* into Theme Style, but that
   output is `.elementor-kit-N h1 {…}` at specificity (0,1,1) and it loses to
   Elementor's own `.elementor-widget-heading .elementor-heading-title` at
   (0,2,0) — so on the first live build every Heading widget rendered at the
   theme's default size while the utility classes beside it were correct. Left
   as-is, the kit's headings only work if nothing else claims them.

   Setting the size here makes the roles hold whether or not the Theme Style
   keys landed, which also means a wrong key name degrades to "the kit tab looks
   empty" rather than "the site is the wrong size". Mapping matches
   typography.headingTagDefaults in the manifest. */
.elementor-widget-heading .elementor-heading-title,
.invelo-scene :is(h1, h2, h3, h4, h5, h6) {
  color: var(--invelo-text-primary);
}

/* h1–h3 are display roles */
h1, .elementor-widget-heading h1.elementor-heading-title,
h2, .elementor-widget-heading h2.elementor-heading-title,
h3, .elementor-widget-heading h3.elementor-heading-title {
  font-family: var(--invelo-font-display);
  font-weight: var(--invelo-weight-display);
}
h1, .elementor-widget-heading h1.elementor-heading-title {
  font-size: var(--invelo-fs-display-xl);
  line-height: .95;
  letter-spacing: -.02em;
}
h2, .elementor-widget-heading h2.elementor-heading-title {
  font-size: var(--invelo-fs-h2);
  line-height: 1;
  letter-spacing: -.015em;
}
h3, .elementor-widget-heading h3.elementor-heading-title {
  font-size: var(--invelo-fs-h3);
  line-height: 1.15;
  letter-spacing: -.01em;
}

/* h4–h6 are body roles — Poppins, not the display face */
h4, .elementor-widget-heading h4.elementor-heading-title,
h5, .elementor-widget-heading h5.elementor-heading-title,
h6, .elementor-widget-heading h6.elementor-heading-title {
  font-family: var(--invelo-font-body);
  font-weight: var(--invelo-weight-body);
}
h4, .elementor-widget-heading h4.elementor-heading-title { font-size: var(--invelo-fs-body-lg); line-height: 1.45; }
h5, .elementor-widget-heading h5.elementor-heading-title { font-size: var(--invelo-fs-body);    line-height: 1.5; }
h6, .elementor-widget-heading h6.elementor-heading-title {
  font-size: var(--invelo-fs-eyebrow);
  line-height: 1.3;
  letter-spacing: .02em;
  text-transform: uppercase;
}

.elementor-widget-text-editor,
.elementor-widget-theme-post-content {
  font-family: var(--invelo-font-body);
  color: var(--invelo-text-muted);
}

/* Elementor's Button widget: neutralise its default blue and Roboto, and give
   it the pill so a plain dragged-in button already looks like the system. */
.elementor-button,
.elementor-button-wrapper .elementor-button {
  /* inline-flex, not just min-height: Elementor's own rule makes the button
     inline-block, on which min-height cannot centre the label — and if this
     sheet ever loads without Elementor's (the QA mirror, a stripped template)
     an inline <a> ignores min-height entirely and the 56px target collapses
     to the line box. Measured at 23px before this line. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--invelo-font-body);
  font-size: var(--invelo-fs-nav);
  font-weight: 500;
  min-height: var(--invelo-btn-min-h);
  padding-inline: var(--invelo-btn-pad-x);
  border-radius: var(--invelo-radius-pill);
  background-color: transparent;
  background-image: var(--invelo-brand-gradient);
  color: var(--invelo-white);
  fill: var(--invelo-white);
  transition: transform .18s ease, box-shadow .18s ease;
}
.elementor-button:hover,
.elementor-button:focus {
  color: var(--invelo-white);
  transform: translateY(-1px);
  box-shadow: var(--invelo-btn-glow);
}

/* Divider, icon and progress widgets default to the Elementor accent. Point
   them at the brand instead. */
.elementor-widget-divider { --divider-color: var(--invelo-soft-border); }
.elementor-widget-icon .elementor-icon { color: var(--invelo-orange-3); }
.elementor-widget-icon-box .elementor-icon { color: var(--invelo-orange-3); }

/* Elementor injects its own selection colour on some setups. */
::selection { background: var(--invelo-orange-3); color: var(--invelo-white); }


/* == 13. Spacing utilities ================================================ */
.invelo-stack > * + * { margin-top: var(--invelo-space-md); }
.invelo-stack-sm > * + * { margin-top: var(--invelo-space-sm); }
.invelo-stack-lg > * + * { margin-top: var(--invelo-space-lg); }

.invelo-section-pad { padding-block: clamp(56px, 8vw, 144px); }
.invelo-section-pad-sm { padding-block: clamp(40px, 5vw, 96px); }


/* == 14. Breakpoints ======================================================
   Two, matching Elementor's own defaults. 1440+ needs no breakpoint: it is the
   point at which the container stops growing, which max-width already says.
   The gutter is the only thing that has to move.
   -------------------------------------------------------------------------- */
@media (max-width: 1024px) {
  :root {
    --invelo-page-gutter: var(--invelo-page-gutter-tablet);
    --invelo-header-height: var(--invelo-header-height-mobile);
  }
}

@media (max-width: 767px) {
  :root {
    --invelo-page-gutter: var(--invelo-page-gutter-mobile);
    --invelo-btn-min-h: var(--invelo-btn-min-h-mobile);
    --invelo-btn-pad-x: var(--invelo-btn-pad-x-mobile);
    --invelo-cta-circle: var(--invelo-cta-circle-mobile);
  }

  /* Mobile is not scaled desktop: every interactive element clears 44px. */
  .invelo-btn,
  .elementor-button { min-height: max(var(--invelo-btn-min-h), var(--invelo-tap-min)); }

  .invelo-cta-arrow { gap: var(--invelo-space-md); }
}


/* == 15. Reduced motion ===================================================
   The Default Kit animates nothing, so there is nothing here to switch off —
   only the two transitions the button and field carry. Motion reduction for
   the cinematic sections is the engine's job, not the kit's.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .invelo-btn,
  .elementor-button,
  .invelo-field,
  .elementor-field-group .elementor-field-textual { transition: none; }
  .invelo-btn:hover,
  .elementor-button:hover { transform: none; }
}
