:root{
  /* Page ground. Not an Elementor Global Color — the brand palette lives
     in the body{} block below this rule. See docs/wordpress-migration/03. */
  --bg:#ffffff;

  --radius:16px;
  --shadow-sm:0 2px 10px rgba(24,84,108,.06);
  --shadow:0 12px 34px rgba(24,84,108,.10);
  --shadow-lg:0 26px 60px rgba(24,84,108,.20);
  --font:'Segoe UI',-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif;

  /* Sticky-header offset for in-page anchors. Elementor's sticky header
     can override this one value instead of every scroll-margin rule. */

  /* ---------------------------------------------------------------
     Fluid type & spacing scale.
     Every size below interpolates with the viewport instead of being
     fixed, so the page stays proportionate from a 1366x768 laptop up
     to a 27" display rather than being tuned for one screen.
     These map onto Elementor's Global Fonts / Site Settings values.
     --------------------------------------------------------------- */
  --fs-h1:clamp(2rem, 1.32rem + 2.1vw, 2.85rem);          /* 32 -> 46px */
  --fs-h1-course:clamp(1.8rem, 1.3rem + 1.55vw, 2.4rem);  /* 29 -> 38px */
  --fs-h2:clamp(1.5rem, 1.18rem + 1vw, 1.95rem);          /* 24 -> 31px */
  --fs-lede:clamp(1rem, .97rem + .16vw, 1.1rem);
  --fs-body-lg:clamp(.95rem, .93rem + .1vw, 1.02rem);

  --sp-section:clamp(46px, 2.6vw + 30px, 66px);
  --sp-head:clamp(26px, 1.4vw + 18px, 38px);
  --sp-gap:clamp(16px, 1vw + 8px, 22px);
  --sp-hero-top:clamp(40px, 2.4vw + 24px, 58px);
  --sp-hero-bottom:clamp(44px, 2.4vw + 26px, 62px);

  --header-h:90px;
  /* Height of the curved section dividers */
  --curve-h:72px;
}

/* ---------------------------------------------------------------
   Brand palette — sampled directly from the master logo artwork
   (assets/Certifii Plus Logo.png).

   These READ FROM Elementor's Global Colors, so editing a colour in
   Site Settings → Global Colors updates this entire stylesheet —
   buttons, cards, footer and all. The hex after each comma is the
   fallback and is the original sampled value: if Elementor's generated
   CSS is ever missing, regenerating, or a colour gets deleted, the site
   still renders correctly.

   ON body, NOT :root, DELIBERATELY. Elementor declares its globals on
   .elementor-kit-<id>, which it applies as a <body> class. Custom
   properties inherit downward only, so the same var() read from :root
   (i.e. <html>) would see no value, silently fall back to the hex, and
   the bridge would do nothing at all while looking perfectly correct.
   Nothing in this stylesheet colours <html> — the only html rule is
   scroll-behavior — so the block loses nothing by sitting one level
   down.

   The --e-global-color-* IDs are generated per site. These are the ones
   for certifiiplus.com.au, read from
   /wp-content/uploads/elementor/css/post-6.css. The four system colours
   (primary/secondary/text/accent) have fixed names; the custom ones do
   not, and change if a colour is deleted and re-created.
   See docs/wordpress-migration/03-design-tokens.md.
   --------------------------------------------------------------- */
body{
  --teal:        var(--e-global-color-primary,   #009078);  /* logo primary green   — surfaces, gradients, borders */
  --teal-dark:   var(--e-global-color-2e0becf,   #007a66);  /* text-safe green      — 5.3:1 on white */
  --teal-darker: var(--e-global-color-6c3463a,   #186054);  /* logo shadow green    — deep gradient stop */
  --mint:        var(--e-global-color-a8f26d3,   #6fc3a8);
  --mint-soft:   var(--e-global-color-c915901,   #e3f3ee);

  --slate:       var(--e-global-color-secondary, #18546c);  /* logo wordmark slate  — headings, dark surfaces (8.3:1 on white) */
  --slate-soft:  var(--e-global-color-b8de430,   #3d6b7d);
  --slate-deep:  var(--e-global-color-e3093c8,   #123f52);  /* footer ground */

  --ink:         var(--e-global-color-text,      #2b3f49);
  --muted:       var(--e-global-color-a34f651,   #69838d);
  --line:        var(--e-global-color-78f8b81,   #e4ecee);
  --bg-soft:     var(--e-global-color-48cd870,   #f4f9f8);
  --amber:       var(--e-global-color-accent,    #f0a538);  /* warm accent — deliberate contrast to the teal */
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:var(--font);color:var(--ink);background:var(--bg);line-height:1.6;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
[hidden]{display:none!important}
.cfp-wrap{max-width:1180px;margin:0 auto;padding:0 24px}
section{scroll-margin-top:var(--header-h)}
h1,h2,h3,h4{color:var(--slate);line-height:1.2;font-weight:800}
.cfp-eyebrow{color:var(--teal-dark);font-weight:800;letter-spacing:.14em;text-transform:uppercase;font-size:.78rem;margin-bottom:12px}
.cfp-btn{display:inline-flex;align-items:center;gap:9px;font-weight:700;font-size:.98rem;padding:13px 24px;border-radius:999px;border:2px solid transparent;cursor:pointer;transition:.18s;font-family:inherit;white-space:nowrap}
.cfp-btn-primary{background:linear-gradient(135deg,var(--teal),var(--teal-dark));color:#fff;box-shadow:0 8px 20px rgba(31,122,110,.28)}
.cfp-btn-primary:hover{transform:translateY(-2px);box-shadow:0 12px 26px rgba(31,122,110,.38)}
.cfp-btn-ghost{background:transparent;color:var(--slate);border-color:var(--line)}
.cfp-btn-ghost:hover{border-color:var(--teal);color:var(--teal-dark)}
.cfp-btn-white{background:#fff;color:var(--teal-dark)}
.cfp-btn-white:hover{transform:translateY(-2px)}
.cfp-btn-outline-white{background:transparent;color:#fff;border-color:rgba(255,255,255,.6)}
.cfp-btn-outline-white:hover{background:rgba(255,255,255,.14)}
.cfp-btn-block{width:100%;justify-content:center}

/* ---------- Scroll reveal ----------
   Everything is gated behind .cfp-js, which JS adds to <html> on boot.
   If the script fails, is blocked, or the page is crawled, nothing is
   ever hidden — the content renders normally. Motion is also dropped
   entirely for prefers-reduced-motion.
   `data-reveal` fades one element; `data-reveal-group` staggers its
   direct children. */
:root{--reveal-shift:16px;--reveal-slide:26px;--reveal-time:.55s;--reveal-ease:cubic-bezier(.22,.61,.36,1);
  /* For anything that has to play backwards. --reveal-ease is a strong
     ease-OUT, which is right for an entrance and wrong for a retreat: run in
     reverse it loses half its travel in 52ms, so the thing appears to vanish
     and then creep. An ease-IN is no better — measured on the nav underline
     it moved 20% in the first 100ms and 59% in the last 110ms, which reads as
     a hang followed by a snap.

     easeInOutSine instead. It is the gentlest symmetric curve: soft at both
     ends, near constant through the middle, so a retracting element travels
     at an even speed and lands rather than stops. */
  --reveal-ease-back:cubic-bezier(.33,0,.67,1)}

.cfp-js [data-reveal],
.cfp-js [data-reveal-group] > *{
  opacity:0;
  transform:translate3d(0,var(--reveal-shift),0);
  transition:opacity var(--reveal-time) var(--reveal-ease),
             transform var(--reveal-time) var(--reveal-ease);
  will-change:opacity,transform
}
.cfp-js [data-reveal].cfp-is-visible,
.cfp-js [data-reveal-group].cfp-is-visible > *{
  opacity:1;transform:none;will-change:auto
}
/* stagger — small enough to feel like one movement, not a queue */
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(1){transition-delay:0s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(2){transition-delay:.06s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(3){transition-delay:.12s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(4){transition-delay:.18s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(5){transition-delay:.24s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(6){transition-delay:.30s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(7){transition-delay:.36s}
.cfp-js [data-reveal-group].cfp-is-visible > *:nth-child(8){transition-delay:.42s}

/* Card grids slide instead of rising.
   `data-reveal-group="slide"` swaps the group's vertical lift for a short
   horizontal travel, so a row of cards reads as sliding into place one
   after another while section headings keep the plainer fade-up. Only the
   resting transform is overridden — the observer matches any
   [data-reveal-group] whatever its value, so no script change is needed,
   and the `.cfp-is-visible` rule above still wins on specificity to land
   every card at transform:none.

   26px is deliberately short. Long travel is what makes this kind of
   entrance feel like a slideshow; at this distance it registers as the
   card settling rather than flying in, and nothing moves far enough to
   look misaligned if the stagger is interrupted mid-scroll.

   `data-reveal="slide"` does the same for a single element that is not
   part of a group. Both directions exist because travel should start
   from the element's own side: the hero card sits hard right, and
   sliding it in from the left would track it across the headline. */
.cfp-js [data-reveal="slide"],
.cfp-js [data-reveal-group="slide"] > *{
  transform:translate3d(calc(var(--reveal-slide) * -1),0,0)
}
.cfp-js [data-reveal="slide-right"]{
  transform:translate3d(var(--reveal-slide),0,0)
}

/* The hero card is the only reveal that sits above the fold, and that
   works against it twice over.

   First, it is racy: init() runs at DOMContentLoaded, so the observer can
   add .cfp-is-visible in the same frame the page first paints. With no
   painted resting state to transition *from*, the browser has nothing to
   interpolate and the card just appears — which is why the movement was
   barely there rather than merely small. A delay removes the race
   outright: the resting state is guaranteed a frame before the transition
   starts.

   Second, it reads against a 370px card and a full-width hero, so 26px
   was simply too little to register at that scale.

   The delay doubles as staging — the headline is already settled, so the
   card arrives as its own beat instead of being part of the page load. */
/* Hero copy. Slightly longer travel than a card grid because it reads
   against a full-width band, and the same softer curve as the card so the
   two halves of the hero feel like one movement. The copy comes from the
   LEFT while the card comes from the right, so they meet in the middle
   instead of both tracking the same way — and the copy's stagger starts
   at 0 while the card waits 0.22s, so the text leads and the card lands
   last. Delays themselves come from the nth-child rules above, which
   outrank this on specificity.

   The course-page hero takes the same treatment: its .cfp-wrap holds the
   same five-item run (badges, code, h1, lede, quickfacts), so the two
   hero types enter identically and the course pages do not feel like a
   different site. */
.cfp-js .cfp-hero-copy > *,
.cfp-js .cfp-course-hero > .cfp-wrap > *{
  --reveal-slide:40px;
  transition-duration:.8s;
  transition-timing-function:cubic-bezier(.16,.68,.3,1)
}

.cfp-js .cfp-hero-card[data-reveal]{
  --reveal-slide:88px;
  transition-duration:.85s;
  /* Short on purpose. The delay only has to outlast first paint to kill
     the race above — one frame would do it — so anything longer is pure
     staging, and past ~250ms it stops reading as a beat and starts
     reading as the page having stalled. The travel and the timing curve
     do the work of being noticeable, not the wait. */
  transition-delay:.22s;
  /* The shared --reveal-ease is heavily front-loaded: it covers over half
     its distance in the first ~170ms, which on a single large card reads
     as a snap rather than a slide. This curve keeps some speed in the
     back half so the travel is actually seen, and still settles without
     overshooting. */
  transition-timing-function:cubic-bezier(.16,.68,.3,1)
}

@media (prefers-reduced-motion:reduce){
  .cfp-js [data-reveal],
  .cfp-js [data-reveal-group] > *{
    opacity:1!important;transform:none!important;transition:none!important
  }
}

/* ---------- Curved section dividers ----------
   Mirrors the DOM shape Elementor Pro emits for its native Shape Divider
   (.elementor-shape > svg), so these sections can either keep this markup
   or be swapped to Elementor's built-in divider with no visual change.
   Fill colour comes from `color` so each instance can match the
   neighbouring section's background. */
.cfp-curve{position:absolute;left:0;width:100%;line-height:0;pointer-events:none;z-index:1;overflow:hidden;color:#fff}
.cfp-curve svg{display:block;position:relative;left:50%;transform:translateX(-50%);width:calc(100% + 1.3px);height:var(--curve-h)}
.cfp-curve path{fill:currentColor}
.cfp-curve-bottom{bottom:-1px}
.cfp-curve-top{top:-1px}
.cfp-curve-top svg{transform:translateX(-50%) rotate(180deg)}
.cfp-curve-soft{color:var(--bg-soft)}
.cfp-curve-white{color:#fff}

/* Visible keyboard focus (none existed before). :focus-visible keeps it
   off for mouse users. */
a:focus-visible,button:focus-visible,input:focus-visible,
select:focus-visible,textarea:focus-visible{
  outline:3px solid var(--teal);outline-offset:2px;border-radius:4px
}
.cfp-hero a:focus-visible,.cfp-course-hero a:focus-visible,.cfp-ctaband a:focus-visible,
.cfp-hero button:focus-visible,.cfp-course-hero button:focus-visible,.cfp-ctaband button:focus-visible,
.cfp-contact a:focus-visible{outline-color:#bff0e4}

/* ---------- Logo ----------
   The mark is cropped straight out of the master artwork rather than
   redrawn. That file (assets/Certifii Plus Logo.png, 3403x4490) is a
   vertical lockup — mark stacked above the wordmark — but the header
   needs a horizontal one, so the mark is windowed out of it and the
   wordmark stays live text beside it. Live text also keeps the brand
   name selectable, translatable and in the accessibility tree.

   The offsets are the mark's measured bounding box inside that file
   (x 379-3050, y 29-2899) expressed as percentages of the crop:
     width  3403/2671 = 127.4%      left -379/2671 = -14.19%
                                    top   -29/2870 =  -1.01%
   Re-export the artwork and these three numbers are the only thing to
   re-measure. */
.cfp-logo{display:flex;align-items:center;gap:11px}
.cfp-logo .cfp-logo-mark{position:relative;flex:none;overflow:hidden;
  width:46px;aspect-ratio:2671/2870}
.cfp-logo .cfp-logo-mark img{position:absolute;width:127.4%;max-width:none;
  height:auto;left:-14.19%;top:-1.01%}
.cfp-logo .cfp-wordmark{display:flex;flex-direction:column;line-height:1}
/* #205e6c is sampled from the wordmark in the master artwork — the same
   value across CERTIFii, PLUS and the rule beneath them. The old markup
   tinted the "ii" separately, which the real logo does not do. */
.cfp-logo .cfp-wordmark-name{font-weight:800;font-size:1.28rem;letter-spacing:.02em;color:#205e6c}
.cfp-logo .cfp-wordmark-sub{font-weight:700;font-size:.62rem;letter-spacing:.42em;color:#205e6c;margin-top:3px;padding-left:2px}

/* ---------- Top bar ---------- */
/* Same light-to-dark diagonal as the logo and the bands.

   Teal, not slate. Slate is a real brand colour — it carries the wordmark
   and the headings — but this strip sits directly above a white header
   and then the teal hero, and a blue bar was the one thing at the top of
   the page not relating to what follows it. Teal makes the opening read
   as one idea: brand strip, white header, brand hero. Slate still owns
   the contact band and the footer, at the other end of the page.

   The light end stops at #0b6153 (9.3% luminance), which holds the
   strip's #cfe0dc text at 5.4:1. */
.cfp-topbar{background:linear-gradient(135deg,#0b6153 0%,#084a40 55%,#063229 100%);
  color:#cfe0dc;font-size:.82rem}
.cfp-topbar .cfp-wrap{display:flex;justify-content:space-between;align-items:center;gap:16px;padding-top:8px;padding-bottom:8px}
.cfp-topbar a:hover{color:#fff}
.cfp-topbar .cfp-topbar-right{display:flex;gap:20px;align-items:center}
/* The chip used a mint tint, which lightened its own ground and dragged
   #9fe4d4 down to about 3.7:1 — under AA for 0.74rem text, and that was
   true on the old slate bar too. Tinting dark instead of light keeps the
   chip reading as a chip while lifting the label well clear. */
.cfp-topbar .cfp-pill{background:rgba(4,33,31,.32);color:#9fe4d4;padding:3px 11px;border-radius:999px;font-weight:700;font-size:.74rem}

/* ---------- Header ---------- */
header{position:sticky;top:0;z-index:60;background:rgba(255,255,255,.92);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
header .cfp-wrap{display:flex;align-items:center;justify-content:space-between;padding-top:14px;padding-bottom:14px}
nav.cfp-nav{display:flex;align-items:center;gap:30px}
nav.cfp-nav a.cfp-nav-link{font-weight:600;color:var(--slate-soft);font-size:.96rem;position:relative}
nav.cfp-nav a.cfp-nav-link:hover{color:var(--teal-dark)}
.cfp-nav-cta{display:flex;align-items:center;gap:14px}
.cfp-hamburger{display:none;background:none;border:none;cursor:pointer;padding:6px}
.cfp-hamburger span{display:block;width:24px;height:2.5px;background:var(--slate);border-radius:2px;margin:5px 0;transition:.2s}

.cfp-hamburger[aria-expanded="true"] span:nth-child(1){transform:translateY(7.5px) rotate(45deg)}
.cfp-hamburger[aria-expanded="true"] span:nth-child(2){opacity:0}
.cfp-hamburger[aria-expanded="true"] span:nth-child(3){transform:translateY(-7.5px) rotate(-45deg)}

/* ---------- Arc pattern ----------
   The reusable band background, split cleanly in two:

     CSS owns the colour   — a diagonal ramp, three stops.
     SVG owns the form     — the arcs, lighting and Plus watermark, as
                             vector artwork (the #cfpArcArt and
                             #cfpArcPlusArt symbols in the markup, drawn
                             per band with <use>).

   Why vector and not gradients: a CSS radial-gradient can only fade
   between colour stops, so every arc edge it draws is soft, and every arc
   must be concentric with one focal point. The artwork needs hard edges
   and arbitrary crescents, which is why the reference sites ship this as
   a flat PNG. An inline <symbol> gets those edges without the PNG's
   costs — it stays sharp past 2000px, weighs a few KB, costs no request,
   and recolours from CSS instead of needing one export per palette.

   The artwork is painted in white / black alpha only, so it carries no
   hue and sits over any ramp unchanged. Re-skinning a band is three
   colour variables and nothing else moves.

   Use:   <section class="cfp-arcs cfp-arcs-amber">
            <svg class="cfp-arcs-art" aria-hidden="true" focusable="false">
              <use class="cfp-arcs-l-arcs" href="#cfpArcArt"/>
              <use class="cfp-arcs-l-plus" href="#cfpArcPlusArt"/>
            </svg>
            ...
          </section>
          The page needs one copy of the .cfp-arcs-defs <svg> (see markup).
   Skin:  set --arc-from / --arc-mid / --arc-to (see the palettes below)
   Tune:  --art-weight  scales the whole arc artwork on this band
          --art-plus    scales the Plus watermark independently
   -------------------------------------------------------------------- */
.cfp-arcs{
  position:relative;overflow:hidden;

  /* Colour ramp — the only thing a palette modifier touches.
     Direction and stop position are lifted from the logo's own gradient
     (<linearGradient x1="0" y1="0" x2="1" y2="1"> with its mid stop at
     .55): light in the top-left corner, dark into the bottom-right.
     --arc-from is therefore always the LIGHT end, --arc-to the dark. */
  --arc-from:#005e51;
  --arc-mid:#05423a;
  --arc-to:#04211f;
  --arc-angle:135deg;

  background:linear-gradient(var(--arc-angle),
    var(--arc-from) 0%, var(--arc-mid) 55%, var(--arc-to) 100%);
}

/* The artwork layer. Sits under the band's content and under the curve
   dividers (z-index 1), which have to stay on top. */
.cfp-arcs-art{position:absolute;inset:0;width:100%;height:100%;display:block;
  pointer-events:none;z-index:0}
.cfp-arcs > .cfp-wrap{position:relative;z-index:2}
/* One hidden definition per page feeds every band through <use>. */
.cfp-arcs-defs{position:absolute;width:0;height:0;overflow:hidden}

/* Per-band weighting.
   These have to be `opacity` on the <use> elements rather than variables
   read inside the SVG: custom properties do NOT inherit into a <use>
   shadow tree in Chrome or Safari, so a var() in those gradient stops
   always resolves to its fallback. The <use> elements themselves are
   ordinary light-DOM children, so CSS reaches them normally. Keep the
   gradient stops literal and adjust the band from here. */
.cfp-arcs-art .cfp-arcs-l-arcs{opacity:var(--art-weight,1)}
.cfp-arcs-art .cfp-arcs-l-plus{opacity:var(--art-plus,1)}

/* Palettes. Same artwork, different ramp — extend this list rather than
   redeclaring anything else. Every one runs light (top-left) to dark
   (bottom-right), matching the logo.

   The light end is held near 9-12% relative luminance rather than taking
   the logo's mint literally: these bands carry white body copy, and the
   logo's #6fc3a8 sits at 45% luminance — 2.1:1 against white, which is
   unreadable. The arcs supply the lift instead of the ramp. Amber is the
   exception; it reproduces the reference artwork and carries no body
   copy of its own. */
.cfp-arcs-teal{--arc-from:#005e51;--arc-mid:#05423a;--arc-to:#04211f}
.cfp-arcs-slate{--arc-from:#175a78;--arc-mid:#0f3f57;--arc-to:#081f2b}
.cfp-arcs-amber{--arc-from:#f0a01e;--arc-mid:#d1600f;--arc-to:#8f2408}
.cfp-arcs-deep{--arc-from:#0d4a5e;--arc-mid:#093a48;--arc-to:#051f28}

/* Flip the sweep for bands whose artwork sits on the left. Mirroring the
   vector costs nothing and keeps the Plus marks the right way round,
   since a "+" is symmetrical. */
.cfp-arcs-mirror .cfp-arcs-art{transform:scaleX(-1)}

/* ---------- Coloured bands ----------
   The bands no longer carry their own gradient stacks. They take the
   shared arc pattern above and add nothing but a palette class in the
   markup (.cfp-arcs .cfp-arcs-teal on the hero, .cfp-arcs-slate on the
   contact band), so a re-skin is a colour swap in one place instead of
   four hand-tuned layer stacks drifting apart. */
.cfp-hero{color:#fff}
.cfp-hero .cfp-wrap{position:relative;z-index:2;display:grid;grid-template-columns:1.05fr .95fr;gap:44px;align-items:center;padding-top:var(--sp-hero-top);padding-bottom:var(--sp-hero-bottom)}
.cfp-hero .cfp-eyebrow{color:#a9ebdb}
.cfp-hero h1{color:#fff;font-size:var(--fs-h1);letter-spacing:-.5px}
.cfp-hero h1 .cfp-hl{color:#bff0e4}
.cfp-hero p.cfp-lede{font-size:var(--fs-lede);color:#e2f4ef;margin-top:16px;max-width:520px}
.cfp-hero .cfp-cta-row{display:flex;gap:14px;margin-top:30px;flex-wrap:wrap}
.cfp-hero .cfp-trust-row{display:flex;gap:26px;margin-top:34px;flex-wrap:wrap}
.cfp-hero .cfp-trust-row .cfp-trust-item{display:flex;align-items:center;gap:9px;font-size:.9rem;color:#dcf1ec;font-weight:600}
.cfp-hero .cfp-trust-row svg{width:20px;height:20px;flex:none}
/* hero card */
.cfp-hero-card{background:#fff;color:var(--ink);border-radius:22px;box-shadow:var(--shadow-lg);padding:26px;position:relative}
.cfp-hero-card .cfp-hero-card-tag{position:absolute;top:-13px;left:26px;background:var(--amber);color:#4a2f00;font-weight:800;font-size:.72rem;letter-spacing:.06em;padding:5px 13px;border-radius:999px}
.cfp-hero-card h3{font-size:1.16rem;margin-bottom:4px}
.cfp-hero-card .cfp-hero-card-code{color:var(--teal-dark);font-weight:800;font-size:.82rem;letter-spacing:.05em}
.cfp-hero-card .cfp-hero-card-meta{display:flex;gap:18px;margin:16px 0;flex-wrap:wrap}
.cfp-hero-card .cfp-hero-card-meta div{font-size:.82rem;color:var(--muted)}
.cfp-hero-card .cfp-hero-card-meta b{display:block;color:var(--slate);font-size:1rem}
.cfp-hero-card .cfp-hero-card-foot{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--line);padding-top:16px;margin-top:4px}
.cfp-hero-card .cfp-hero-card-price{font-size:1.5rem;font-weight:800;color:var(--slate)}
.cfp-hero-card .cfp-hero-card-price span{font-size:.8rem;color:var(--muted);font-weight:600}

/* ---------- Stat strip ---------- */
.cfp-stats{background:var(--bg-soft);border-bottom:1px solid var(--line)}
.cfp-stats .cfp-wrap{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;padding-top:36px;padding-bottom:36px;text-align:center}
.cfp-stats .cfp-stat-num{font-size:2.1rem;font-weight:800;color:var(--teal-dark);line-height:1}
.cfp-stats .cfp-stat-label{color:var(--muted);font-size:.88rem;margin-top:6px;font-weight:600}

/* ---------- Section shell ---------- */
.cfp-section{padding:var(--sp-section) 0}
.cfp-section-head{text-align:center;max-width:680px;margin:0 auto var(--sp-head)}
.cfp-section-head h2{font-size:var(--fs-h2);margin-bottom:10px}
.cfp-section-head p{color:var(--muted);font-size:var(--fs-body-lg)}

/* ---------- Filter tabs ---------- */
.cfp-filters{display:flex;justify-content:center;gap:10px;margin-bottom:38px;flex-wrap:wrap}
.cfp-filters button{background:#fff;border:1.5px solid var(--line);color:var(--slate-soft);font-weight:700;padding:9px 20px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:.9rem;transition:.15s}
.cfp-filters button:hover{border-color:var(--teal)}
.cfp-filters button.cfp-is-active{background:var(--teal-dark);border-color:var(--teal-dark);color:#fff}

/* ---------- Course cards ---------- */
.cfp-course-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-gap)}
.cfp-course-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;display:flex;flex-direction:column;box-shadow:var(--shadow-sm);transition:.2s}
.cfp-course-card:hover{transform:translateY(-5px);box-shadow:var(--shadow);border-color:transparent}
.cfp-course-card .cfp-course-thumb{height:150px;position:relative;overflow:hidden;display:flex;align-items:flex-end;padding:16px}
/* The thumb takes the same arc artwork as the full bands, but at 150px it
   is a very close crop, so it needs dialling back or it competes with the
   badge and code chip sitting on it. The Plus layer is left out of the
   thumb markup entirely — the card already carries its own oversized "+"
   — and the idle drift is switched off: it is imperceptible at this size
   and would put six more infinite compositor animations on the page. */
.cfp-course-card .cfp-course-thumb .cfp-arcs-art{--art-weight:.6;animation:none}
.cfp-course-card .cfp-course-thumb .cfp-course-plusmark{position:absolute;right:-16px;top:-16px;font-size:120px;font-weight:800;color:rgba(255,255,255,.16);line-height:1}
.cfp-course-card .cfp-course-thumb .cfp-course-code{position:relative;z-index:2;background:rgba(255,255,255,.92);color:var(--teal-darker);font-weight:800;font-size:.76rem;letter-spacing:.04em;padding:5px 11px;border-radius:8px}
.cfp-thumb-a{background:linear-gradient(135deg,#2fa48f,#1f7a6e)}
.cfp-thumb-b{background:linear-gradient(135deg,#3aa48f,#155e55)}
.cfp-thumb-c{background:linear-gradient(135deg,#4bb4a0,#2b7a86)}
.cfp-thumb-d{background:linear-gradient(135deg,#5cbfa9,#3a6f7d)}
.cfp-thumb-e{background:linear-gradient(135deg,#7fd0bf,#4a5a63)}
.cfp-badge{position:absolute;top:14px;right:14px;z-index:3;font-weight:800;font-size:.68rem;letter-spacing:.05em;text-transform:uppercase;padding:5px 10px;border-radius:999px}
.cfp-badge.cfp-badge-accredited{background:var(--amber);color:#4a2f00}
.cfp-badge.cfp-badge-soon{background:rgba(38,52,61,.85);color:#cfe0dc}
.cfp-course-card .cfp-course-body{padding:20px;display:flex;flex-direction:column;flex:1}
.cfp-course-card h3{font-size:1.14rem;margin-bottom:8px}
.cfp-course-card h3 a{color:inherit;transition:.15s}
.cfp-course-card h3 a:hover{color:var(--teal-dark)}
.cfp-course-card .cfp-course-desc{color:var(--muted);font-size:.92rem;flex:1}
.cfp-course-card .cfp-course-meta{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}
.cfp-course-card .cfp-course-meta span{background:var(--mint-soft);color:var(--teal-darker);font-size:.76rem;font-weight:700;padding:4px 10px;border-radius:7px}
.cfp-course-card .cfp-course-foot{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--line);padding-top:16px;margin-top:6px}
.cfp-course-card .cfp-price{font-size:1.35rem;font-weight:800;color:var(--slate)}
.cfp-course-card .cfp-price small{display:block;font-size:.72rem;color:var(--muted);font-weight:600}
.cfp-course-card.cfp-is-soon .cfp-price{color:var(--muted)}

/* ---------- Why / features ---------- */
.cfp-why{background:var(--bg-soft)}
.cfp-features{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-gap)}
.cfp-features .cfp-feature{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow-sm)}
.cfp-features .cfp-icon{width:52px;height:52px;border-radius:13px;background:var(--mint-soft);display:flex;align-items:center;justify-content:center;margin-bottom:16px}
.cfp-features .cfp-icon svg{width:26px;height:26px}
.cfp-features h3{font-size:1.1rem;margin-bottom:8px}
.cfp-features p{color:var(--muted);font-size:.94rem}


/* ---------- Setting you up for success ----------
   Copy on the left, video on the right. It sits on --bg-soft between two
   white sections deliberately: #how and #about were previously adjacent
   whites, so this restores the light/soft alternation down the page.

   The video is a facade, not an iframe — see playVideo() in app.js for
   why, and for how it maps onto Elementor Pro's Video widget.
   -------------------------------------------------------------------- */
/* No background of its own — .cfp-arcs-teal supplies the ramp and the
   artwork, same as the hero and contact bands. Text is inverted for the
   dark ground; the values below were measured against the composited
   band rather than guessed, since the arcs lighten parts of it. */
.cfp-setup .cfp-wrap{display:grid;grid-template-columns:1fr 1.08fr;
  gap:clamp(28px,4vw,56px);align-items:center}
.cfp-setup .cfp-eyebrow{color:#a9ebdb}
.cfp-setup-copy h2{font-size:var(--fs-h2);color:#fff}
.cfp-setup-copy > p{color:#dcefe9;font-size:var(--fs-lede);margin:12px 0 24px;max-width:52ch}

.cfp-setup-points{list-style:none;display:grid;gap:13px;margin:0 0 30px}
.cfp-setup-points li{display:flex;gap:11px;align-items:flex-start;
  font-size:.95rem;color:#d3e8e2}
.cfp-setup-points li b{color:#fff;font-weight:800}
.cfp-setup-points svg{width:21px;height:21px;flex:none;margin-top:2px;color:#8fdcc6}

/* ---------- Video facade ---------- */
.cfp-video{position:relative;aspect-ratio:16/9;border-radius:18px;overflow:hidden;
  box-shadow:var(--shadow-lg);background:var(--slate-deep)}
.cfp-video img,.cfp-video iframe{position:absolute;inset:0;width:100%;height:100%;
  border:0;object-fit:cover;display:block}
.cfp-video-btn{position:absolute;inset:0;width:100%;height:100%;padding:0;border:0;
  background:none;cursor:pointer;display:block}
/* No tint at rest. An earlier version washed the whole poster in teal to
   pull it into our palette, but against a dark band that made the video
   recede rather than stand out — it read as dimmed rather than styled.
   The frame is left alone and the play button carries its own shadow for
   legibility. The wash is kept only for hover, as affordance. */
.cfp-video-btn::after{content:"";position:absolute;inset:0;opacity:0;
  background:linear-gradient(135deg,rgba(0,94,81,.20),rgba(4,33,31,.28));
  transition:opacity .28s var(--reveal-ease)}
.cfp-video-btn:hover::after,.cfp-video-btn:focus-visible::after{opacity:1}
.cfp-video-play{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:74px;height:74px;border-radius:50%;color:#fff;
  background:linear-gradient(135deg,var(--teal),var(--teal-dark));
  /* Ring plus shadow: with the poster no longer darkened, the button has
     to hold its own against whatever frame the video happens to open on. */
  box-shadow:0 14px 34px rgba(4,33,31,.5),0 0 0 5px rgba(255,255,255,.16);
  display:flex;align-items:center;justify-content:center;
  transition:transform .28s var(--reveal-ease),box-shadow .28s}
.cfp-video-btn:hover .cfp-video-play,
.cfp-video-btn:focus-visible .cfp-video-play{transform:translate(-50%,-50%) scale(1.09);
  box-shadow:0 18px 42px rgba(4,33,31,.55)}
.cfp-video-play svg{width:32px;height:32px;margin-left:4px}
.cfp-video-note{color:var(--muted);font-size:.85rem;margin-top:12px;text-align:center}
/* On the dark band the note needs lifting, and --shadow-lg is a blue-grey
   shadow tuned for light grounds — it does nothing over a dark one, so the
   card gets a plain black drop instead. */
.cfp-setup .cfp-video-note{color:#c8dbd5}
.cfp-setup .cfp-video{box-shadow:0 26px 60px rgba(0,0,0,.38)}

@media (prefers-reduced-motion:reduce){
  .cfp-video-btn::after,.cfp-video-play{transition:none}
  .cfp-video-btn:hover .cfp-video-play,
  .cfp-video-btn:focus-visible .cfp-video-play{transform:translate(-50%,-50%)}
}
/* ---------- Steps ---------- */
.cfp-steps{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-gap);counter-reset:s}
.cfp-step{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:26px 22px;box-shadow:var(--shadow-sm)}
.cfp-step .cfp-step-num{width:42px;height:42px;border-radius:12px;background:linear-gradient(135deg,var(--teal),var(--teal-dark));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.1rem;margin-bottom:16px}
.cfp-step h3{font-size:1.05rem;margin-bottom:6px}
.cfp-step p{color:var(--muted);font-size:.9rem}

/* ---------- About ---------- */
.cfp-about .cfp-wrap{display:grid;grid-template-columns:1fr 1fr;gap:54px;align-items:center}
.cfp-about ul{list-style:none;margin-top:22px;display:grid;gap:14px}
.cfp-about li{display:flex;gap:12px;align-items:flex-start}
.cfp-about li svg{width:22px;height:22px;flex:none;margin-top:2px}
.cfp-about li b{color:var(--slate)}
.cfp-about li span{color:var(--muted);font-size:.95rem}
.cfp-about-visual{position:relative;border-radius:22px;overflow:hidden;min-height:400px;background:linear-gradient(135deg,#0a7a66,var(--teal-darker));display:flex;align-items:center;justify-content:center;color:#fff;box-shadow:var(--shadow)}
.cfp-about-visual .cfp-plus{position:absolute;font-weight:800;color:rgba(255,255,255,.10)}
.cfp-about-visual .cfp-plus-a{font-size:220px;top:-40px;left:-30px}
.cfp-about-visual .cfp-plus-b{font-size:120px;bottom:10px;right:20px}
.cfp-about-visual .cfp-quote{position:relative;z-index:2;padding:40px;max-width:360px}
.cfp-about-visual .cfp-quote .cfp-quote-mark{font-size:4rem;line-height:.5;color:var(--mint)}
.cfp-about-visual .cfp-quote p{font-size:1.2rem;font-weight:600;margin:10px 0 18px}
.cfp-about-visual .cfp-quote .cfp-quote-who{font-size:.9rem;color:#cbeee5;font-weight:700}

/* ---------- Contact ---------- */
.cfp-contact{color:#dce8e4}
.cfp-contact .cfp-wrap{display:grid;grid-template-columns:1fr 1.1fr;gap:54px;align-items:start}
.cfp-contact h2{color:#fff;font-size:var(--fs-h2)}
.cfp-contact .cfp-lede{color:#cfe0dc;margin:12px 0 26px}
.cfp-contact .cfp-contact-item{display:flex;gap:14px;align-items:flex-start;margin-bottom:20px}
.cfp-contact .cfp-contact-item .cfp-icon{width:44px;height:44px;border-radius:11px;background:rgba(127,208,191,.14);display:flex;align-items:center;justify-content:center;flex:none}
.cfp-contact .cfp-contact-item .cfp-icon svg{width:22px;height:22px}
.cfp-contact .cfp-contact-item b{color:#fff;display:block;font-size:.95rem}
.cfp-contact .cfp-contact-item span{color:#c8dbd5;font-size:.92rem}
.cfp-form-card{background:#fff;border-radius:20px;padding:30px;box-shadow:var(--shadow-lg)}
.cfp-form-card h3{color:var(--slate);margin-bottom:4px}
.cfp-form-card p{color:var(--muted);font-size:.9rem;margin-bottom:20px}
.cfp-field{margin-bottom:16px}
.cfp-field label{display:block;font-weight:700;font-size:.84rem;color:var(--slate);margin-bottom:6px}
.cfp-field input,.cfp-field select,.cfp-field textarea{width:100%;padding:12px 14px;border:1.5px solid var(--line);border-radius:10px;font-family:inherit;font-size:.95rem;color:var(--ink);background:#fff;transition:.15s}
.cfp-field input:focus,.cfp-field select:focus,.cfp-field textarea:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(47,164,143,.15)}
.cfp-form-note{margin-top:14px;font-size:.86rem;color:var(--teal-dark);background:var(--mint-soft);border:1px solid #c8e6dc;border-radius:10px;padding:10px 12px}
.cfp-field .cfp-field-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}

/* ---------- Footer ---------- */
/* ---------- Footer ----------
   The footer was the last flat-colour dark surface on the site — every
   other dark band is a 135deg ramp — which is what made it read as bolted
   on rather than as the end of the page. It now takes the same ramp, and
   crucially keeps *descending*: the contact band above finishes around
   #134d67 on its bottom-left edge, so starting the footer at #0f3f52 and
   running down to near-black continues the diagonal instead of stepping
   back to a lighter tone, which is what the hard seam was.

   The seam is handled by separation rather than blending. Two independent
   135deg ramps meeting on a straight line sit at different points of
   their own gradients — roughly 28-100% for the band above, 0-70% here —
   so they can never agree, and chasing a match is chasing a moving
   target. Instead the footer drops to a clearly darker ground with a
   hairline above it, and the change reads as intended rather than as a
   mismatch.

   The darker ground also fixes two contrast failures that predate this:
   on the old flat #123f52, the body's #8ea6a0 was 4.32:1 and the
   footbar's #6f8781 was 2.90:1 — both under AA. Against #0a2c3a the
   original muted tones pass comfortably, so the palette keeps its
   intended hierarchy instead of being flattened brighter. */
footer{background:linear-gradient(135deg,#0a2c3a 0%,#071f29 55%,#04121a 100%);
  border-top:1px solid rgba(255,255,255,.12);
  color:#9db3ad;font-size:.9rem}
footer .cfp-wrap{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:34px;padding-top:56px;padding-bottom:36px}
footer h4{color:#fff;font-size:.9rem;letter-spacing:.08em;text-transform:uppercase;margin-bottom:16px}
footer a{display:block;padding:5px 0;color:#8ea6a0}
footer a:hover{color:var(--mint)}
footer .cfp-foot-about p{margin:16px 0}
footer .cfp-logo .cfp-wordmark-name{color:#fff}
footer .cfp-logo .cfp-wordmark-sub{color:#9fb8b2}
.cfp-foot-about .cfp-pill{display:inline-block;background:rgba(111,195,168,.16);color:#9fe4d4;padding:4px 12px;border-radius:999px;font-weight:700;font-size:.78rem}
.cfp-footbar{border-top:1px solid rgba(255,255,255,.08)}
.cfp-footbar .cfp-wrap{display:flex;justify-content:space-between;align-items:center;padding-top:18px;padding-bottom:18px;font-size:.82rem;color:#8ea6a0}

/* ---------- Modal ---------- */
.cfp-overlay{position:fixed;inset:0;background:rgba(20,30,35,.62);backdrop-filter:blur(4px);z-index:200;display:none;align-items:flex-start;justify-content:center;padding:40px 18px;overflow-y:auto}
.cfp-overlay.cfp-is-open{display:flex}
.cfp-modal{background:#fff;border-radius:20px;max-width:520px;width:100%;box-shadow:var(--shadow-lg);overflow:hidden;animation:pop .25s ease}
@keyframes pop{from{transform:translateY(18px) scale(.98);opacity:0}to{transform:none;opacity:1}}
.cfp-modal-head{background:linear-gradient(135deg,var(--teal-dark),var(--teal-darker));color:#fff;padding:22px 26px;position:relative}
/* Flex-centred rather than relying on the glyph's own metrics. A bare
   <button> centres its text horizontally but sits it on the baseline, so the
   ✕ rode high inside the 32px circle; UA and theme button padding shifted it
   again. padding:0 removes both. */
.cfp-modal-head .cfp-modal-close{position:absolute;top:16px;right:18px;background:rgba(255,255,255,.16);border:none;color:#fff;width:32px;height:32px;border-radius:50%;font-size:1.1rem;cursor:pointer;line-height:1;
  display:flex;align-items:center;justify-content:center;padding:0}
.cfp-modal-head .cfp-modal-close:hover{background:rgba(255,255,255,.28)}
.cfp-modal-head .cfp-modal-code{font-size:.78rem;color:#bff0e4;font-weight:700;letter-spacing:.04em}
.cfp-modal-head h3{color:#fff;font-size:1.24rem;margin-top:3px}
/* stepper */
.cfp-stepper{display:flex;gap:6px;margin-top:16px}
.cfp-stepper .cfp-stepper-dot{flex:1;height:5px;border-radius:999px;background:rgba(255,255,255,.25)}
.cfp-stepper .cfp-stepper-dot.cfp-is-active{background:#fff}
.cfp-modal-body{padding:26px}
.cfp-step-pane{display:none}
.cfp-step-pane.cfp-is-active{display:block}
.cfp-order-sum{background:var(--bg-soft);border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin-bottom:22px;display:flex;justify-content:space-between;align-items:center}
.cfp-order-sum .cfp-order-sum-left b{display:block;color:var(--slate)}
.cfp-order-sum .cfp-order-sum-left span{font-size:.82rem;color:var(--muted)}
.cfp-order-sum .cfp-order-sum-right{font-size:1.35rem;font-weight:800;color:var(--teal-dark)}
.cfp-demo-note{display:flex;gap:9px;align-items:flex-start;background:#fff8ec;border:1px solid #f4e2c0;border-radius:10px;padding:11px 13px;font-size:.82rem;color:#8a6d2f;margin-bottom:18px}
.cfp-demo-note svg{width:18px;height:18px;flex:none;margin-top:1px}
.cfp-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.cfp-field-grid .cfp-field-full{grid-column:1/-1}
.cfp-field-err{color:#c0392b;font-size:.8rem;margin-top:5px;display:none}
.cfp-field.cfp-is-invalid input{border-color:#e07b6c;box-shadow:0 0 0 3px rgba(224,123,108,.15)}
.cfp-field.cfp-is-invalid .cfp-field-err{display:block}
.cfp-modal-foot{display:flex;gap:12px;justify-content:space-between;margin-top:24px}
.cfp-link-btn{background:none;border:none;color:var(--muted);font-family:inherit;font-weight:700;cursor:pointer;font-size:.92rem;padding:10px}
.cfp-link-btn:hover{color:var(--slate)}
.cfp-modal-intro{font-size:.9rem;color:var(--muted);margin-bottom:18px}
.cfp-processing-title{font-size:1.15rem}
.cfp-success .cfp-btn-block{margin-top:16px}
/* processing */
.cfp-processing{text-align:center;padding:26px 10px}
.cfp-spinner{width:56px;height:56px;border:5px solid var(--mint-soft);border-top-color:var(--teal-dark);border-radius:50%;margin:0 auto 20px;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.cfp-processing .cfp-process-log{text-align:left;max-width:340px;margin:22px auto 0;font-size:.86rem}
.cfp-processing .cfp-process-log .cfp-process-line{display:flex;gap:10px;align-items:center;padding:7px 0;color:var(--muted);opacity:.35;transition:.3s}
.cfp-processing .cfp-process-log .cfp-process-line.cfp-is-done{opacity:1;color:var(--slate)}
.cfp-processing .cfp-process-log .cfp-process-line .cfp-tick{width:20px;height:20px;border-radius:50%;background:var(--line);display:flex;align-items:center;justify-content:center;flex:none;transition:.3s}
.cfp-processing .cfp-process-log .cfp-process-line.cfp-is-done .cfp-tick{background:var(--teal-dark)}
.cfp-processing .cfp-process-log .cfp-process-line .cfp-tick svg{width:12px;height:12px}
/* success */
.cfp-success{text-align:center;padding:12px 6px}
.cfp-success .cfp-success-check{width:74px;height:74px;border-radius:50%;background:linear-gradient(135deg,var(--teal),var(--teal-dark));display:flex;align-items:center;justify-content:center;margin:0 auto 18px;animation:pop .3s ease}
.cfp-success .cfp-success-check svg{width:38px;height:38px}
.cfp-success h3{font-size:1.4rem}
.cfp-success p{color:var(--muted);margin-top:8px}
.cfp-receipt{text-align:left;background:var(--bg-soft);border:1px solid var(--line);border-radius:12px;padding:18px;margin:22px 0;font-size:.9rem}
/* gap and the two sizing rules below are what stop a long course title from
   running into its own label. justify-content:space-between alone lets the
   value grow until it touches the label — measured 0px between them for
   "BSB41419 — Certificate IV in Work Health & Safety" — and its wrapped
   second line falls back to the left edge, under the value rather than
   aligned with it. */
.cfp-receipt .cfp-receipt-row{display:flex;justify-content:space-between;padding:6px 0;
  gap:18px;align-items:baseline}
.cfp-receipt .cfp-receipt-row span{color:var(--muted);flex:none}
.cfp-receipt .cfp-receipt-row b{color:var(--slate);font-family:'Courier New',monospace;
  text-align:right;min-width:0}
.cfp-axe-sync{display:flex;gap:11px;align-items:center;background:var(--mint-soft);border:1px solid #bfe6dc;border-radius:10px;padding:12px 14px;font-size:.85rem;color:var(--teal-darker);margin-bottom:8px}
.cfp-axe-sync svg{width:22px;height:22px;flex:none}

/* ================= COURSE DETAIL PAGE ================= */
.cfp-breadcrumb{background:var(--bg-soft);border-bottom:1px solid var(--line);font-size:.86rem}
.cfp-breadcrumb .cfp-wrap{padding-top:14px;padding-bottom:14px;display:flex;gap:8px;align-items:center;color:var(--muted);flex-wrap:wrap}
.cfp-breadcrumb a{color:var(--teal-dark);font-weight:600}
.cfp-breadcrumb a:hover{text-decoration:underline}
.cfp-breadcrumb .cfp-breadcrumb-sep{color:var(--line);font-weight:700}
.cfp-breadcrumb .cfp-breadcrumb-current{color:var(--slate);font-weight:600}

/* course hero */
/* Same ramp as .cfp-arcs-teal, so the course pages read as the same
   system. Light top-left into dark bottom-right, per the logo. */
/* Both course-page bands now take the shared arc pattern in the markup
   (.cfp-arcs .cfp-arcs-teal), so neither carries a gradient stack of its
   own any more, and the artwork's own watermark replaced the oversized
   `+` divs these two used to sit behind. */
.cfp-course-hero{color:#fff}
.cfp-course-hero .cfp-plus.cfp-plus-1{font-size:240px;top:-40px;right:8%}
.cfp-course-hero .cfp-wrap{position:relative;z-index:2;padding-top:var(--sp-hero-top);padding-bottom:var(--sp-hero-top);max-width:900px}
.cfp-course-hero .cfp-course-hero-badges{display:flex;gap:10px;margin-bottom:18px;flex-wrap:wrap}
.cfp-course-hero .cfp-course-badge{font-weight:800;font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;padding:6px 13px;border-radius:999px}
.cfp-course-hero .cfp-course-badge.cfp-course-badge-amber{background:var(--amber);color:#4a2f00}
.cfp-course-hero .cfp-course-badge.cfp-course-badge-ghost{background:rgba(255,255,255,.14);color:#eafaf5;border:1px solid rgba(255,255,255,.3)}
.cfp-course-hero .cfp-course-hero-code{font-weight:800;letter-spacing:.06em;color:#bff0e4;font-size:.95rem;margin-bottom:6px}
.cfp-course-hero h1{color:#fff;font-size:var(--fs-h1-course);letter-spacing:-.5px}
.cfp-course-hero p.cfp-lede{font-size:var(--fs-lede);color:#e2f4ef;margin-top:14px;max-width:640px}
.cfp-course-hero .cfp-quickfacts{display:flex;gap:34px;margin-top:30px;flex-wrap:wrap}
.cfp-course-hero .cfp-quickfacts .cfp-quickfact{display:flex;gap:11px;align-items:center}
.cfp-course-hero .cfp-quickfacts .cfp-quickfact svg{width:26px;height:26px;flex:none}
.cfp-course-hero .cfp-quickfacts .cfp-quickfact b{display:block;font-size:1.02rem;color:#fff}
.cfp-course-hero .cfp-quickfacts .cfp-quickfact span{font-size:.8rem;color:#d9efe9}

/* detail layout */
.cfp-detail{padding:64px 0}
.cfp-detail .cfp-wrap{display:grid;grid-template-columns:1fr 340px;gap:48px;align-items:start}
.cfp-detail .cfp-detail-main h2{font-size:1.7rem;margin:0 0 14px}
.cfp-detail .cfp-detail-main h2:not(:first-child){margin-top:44px}
.cfp-detail .cfp-detail-main p{color:var(--slate-soft);margin-bottom:14px}
.cfp-detail .cfp-detail-main .cfp-lead-p{font-size:1.08rem;color:var(--ink)}
.cfp-outcomes{list-style:none;display:grid;gap:12px;margin:6px 0 4px}
.cfp-outcomes li{display:flex;gap:12px;align-items:flex-start;color:var(--slate-soft)}
.cfp-outcomes li svg{width:22px;height:22px;flex:none;margin-top:2px}

/* unit cards */
.cfp-units{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:6px}
.cfp-unit{display:flex;gap:14px;align-items:flex-start;border:1px solid var(--line);border-left:4px solid var(--teal);border-radius:12px;padding:18px 20px;background:#fff;box-shadow:var(--shadow-sm);transition:.2s}
.cfp-unit:hover{box-shadow:var(--shadow);transform:translateY(-2px)}
.cfp-unit .cfp-unit-num{width:30px;height:30px;flex:none;border-radius:8px;background:var(--mint-soft);color:var(--teal-darker);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:.9rem;margin-top:2px}
.cfp-unit .cfp-unit-code{color:var(--teal-dark);font-weight:800;font-size:.8rem;letter-spacing:.04em}
.cfp-unit .cfp-unit-title{color:var(--slate);font-weight:700;font-size:1.02rem;margin-top:3px;line-height:1.35}
.cfp-elective-note{background:var(--bg-soft);border:1px solid var(--line);border-left:4px solid var(--teal);border-radius:10px;padding:16px 18px;color:var(--slate-soft);font-size:.94rem;margin-top:16px}
.cfp-elective-note b{color:var(--slate)}
.cfp-elective-list{columns:2;column-gap:26px;margin-top:14px;font-size:.92rem}
@media(max-width:560px){.cfp-elective-list{columns:1}}
.cfp-elective-list .cfp-elective{break-inside:avoid;padding:6px 0;color:var(--slate-soft);display:flex;gap:8px}
.cfp-elective-list .cfp-elective b{color:var(--teal-dark);font-weight:700;white-space:nowrap}

.cfp-infogrid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:6px}
.cfp-infogrid .cfp-infobox{border:1px solid var(--line);border-radius:12px;padding:18px;background:#fff}
.cfp-infogrid .cfp-infobox h4{font-size:.82rem;letter-spacing:.06em;text-transform:uppercase;color:var(--teal-dark);margin-bottom:8px}
.cfp-infogrid .cfp-infobox p{font-size:.94rem;color:var(--slate-soft);margin:0}

/* sticky sidebar enrol card */
.cfp-enrol-card{position:sticky;top:calc(var(--header-h) + 6px);background:#fff;border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow);overflow:hidden}
.cfp-enrol-card .cfp-enrol-card-top{background:linear-gradient(135deg,var(--teal-dark),var(--teal-darker));color:#fff;padding:22px 24px}
.cfp-enrol-card .cfp-enrol-card-top .cfp-enrol-card-price{font-size:2rem;font-weight:800}
.cfp-enrol-card .cfp-enrol-card-top .cfp-enrol-card-price span{font-size:.85rem;font-weight:600;color:#bff0e4}
.cfp-enrol-card .cfp-enrol-card-top .cfp-enrol-card-sub{font-size:.85rem;color:#cdeee6;margin-top:2px}
.cfp-enrol-card .cfp-enrol-card-body{padding:22px 24px}
.cfp-enrol-card .cfp-enrol-card-facts{list-style:none;display:grid;gap:13px;margin-bottom:20px}
.cfp-enrol-card .cfp-enrol-card-facts li{display:flex;gap:11px;align-items:flex-start;font-size:.9rem;color:var(--slate-soft)}
.cfp-enrol-card .cfp-enrol-card-facts li svg{width:19px;height:19px;flex:none;margin-top:2px;color:var(--teal-dark)}
.cfp-enrol-card .cfp-enrol-card-facts li b{color:var(--slate)}
.cfp-enrol-card .cfp-enrol-card-seal{display:flex;gap:10px;align-items:center;background:var(--mint-soft);border-radius:10px;padding:11px 13px;margin-top:16px;font-size:.82rem;color:var(--teal-darker);font-weight:600}
.cfp-enrol-card .cfp-enrol-card-seal svg{width:24px;height:24px;flex:none}

/* CTA band */
/* Same pattern as the course hero above it, but .cfp-arcs-mirror flips
   the artwork, so the two bands on one page do not read as the same
   image twice. */
.cfp-ctaband{color:#fff;text-align:center;padding:62px 0}
.cfp-ctaband h2{color:#fff;font-size:2rem;position:relative;z-index:2}
.cfp-ctaband p{color:#ecf8f5;margin:12px 0 26px;position:relative;z-index:2}
.cfp-ctaband .cfp-cta-row{display:flex;gap:14px;justify-content:center;position:relative;z-index:2;flex-wrap:wrap}


/* ---------- Motion & interaction ----------
   The page had exactly four hover states and no idle motion, which is
   what made it read as a printed page. Everything below is transform and
   opacity only, so it composites on the GPU and never triggers layout,
   and the whole block is switched off for prefers-reduced-motion at the
   end of this section.
   -------------------------------------------------------------------- */

/* Nav: an underline that grows from the left, rather than a colour jump.
   The link already has position:relative. */
/* The two states carry their own origin and easing, so the line grows from
   the left on the way in and retracts to the right on the way out — one
   continuous travel rather than a rewind. Sharing the entry's ease-out made
   the exit look like the line was cut: half its length gone in 52ms. */
nav.cfp-nav a.cfp-nav-link::after{
  content:"";position:absolute;left:0;right:0;bottom:-7px;height:2px;border-radius:2px;
  background:linear-gradient(135deg,var(--teal),var(--teal-darker));
  transform:scaleX(0);transform-origin:right;
  transition:transform .3s var(--reveal-ease-back)
}
nav.cfp-nav a.cfp-nav-link:hover::after,
nav.cfp-nav a.cfp-nav-link:focus-visible::after{
  transform:scaleX(1);transform-origin:left;
  transition:transform .26s var(--reveal-ease)
}

/* The header earns a shadow once the page has actually moved, so it
   separates from the content it is floating over. .cfp-is-stuck is set
   from app.js on a passive scroll listener. */
header{transition:box-shadow .3s ease,background-color .3s ease}
header.cfp-is-stuck{background:rgba(255,255,255,.97);box-shadow:0 6px 24px rgba(24,84,108,.10)}

/* Feature cards: lift, and let the icon lead the movement slightly. */
.cfp-features .cfp-feature{
  transition:transform .22s var(--reveal-ease),box-shadow .22s var(--reveal-ease),border-color .22s
}
.cfp-features .cfp-feature:hover{transform:translateY(-4px);box-shadow:var(--shadow);border-color:transparent}
.cfp-features .cfp-icon{transition:transform .22s var(--reveal-ease),background-color .22s}
.cfp-features .cfp-feature:hover .cfp-icon{transform:translateY(-2px) scale(1.06);background:#d3ece4}

/* Course cards already lift; give the thumb a slow push in behind it. */
.cfp-course-card .cfp-course-thumb{transition:transform .4s var(--reveal-ease)}
.cfp-course-card:hover .cfp-course-thumb{transform:scale(1.05)}

/* Steps */
.cfp-steps .cfp-step{transition:transform .22s var(--reveal-ease),box-shadow .22s var(--reveal-ease)}
.cfp-steps .cfp-step:hover{transform:translateY(-4px);box-shadow:var(--shadow)}

/* Contact rows */
.cfp-contact .cfp-contact-item .cfp-icon{transition:transform .22s var(--reveal-ease),background-color .22s}
.cfp-contact .cfp-contact-item:hover .cfp-icon{transform:scale(1.08);background:rgba(127,208,191,.24)}

/* Footer links drift toward the reader instead of only changing colour. */
footer a{transition:color .18s,transform .18s var(--reveal-ease)}
footer a:hover{transform:translateX(3px)}

/* Buttons had a hover but no press state, which is what makes a button
   feel dead under the finger. */
.cfp-btn:active{transform:translateY(0) scale(.985)}
.cfp-filters button:active{transform:scale(.985)}

/* Stat strip: the count-up rewrites this text every frame, so fix the
   digit width or the whole row jitters as it counts. */
.cfp-stats .cfp-stat-num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* The band artwork drifts, very slowly. 44 seconds for a couple of
   percent — this should be felt rather than watched, and it is the one
   thing that stops a full-width band from reading as a flat print. Only
   `transform` animates, so it stays on the compositor. */
@keyframes cfpArcDrift{
  0%,100%{transform:scale(1.04) translate3d(0,0,0)}
  50%    {transform:scale(1.07) translate3d(-1.1%,.7%,0)}
}
@keyframes cfpArcDriftMirror{
  0%,100%{transform:scaleX(-1) scale(1.04) translate3d(0,0,0)}
  50%    {transform:scaleX(-1) scale(1.07) translate3d(-1.1%,.7%,0)}
}
.cfp-arcs-art{animation:cfpArcDrift 44s ease-in-out infinite}
.cfp-arcs-mirror .cfp-arcs-art{animation-name:cfpArcDriftMirror}

@media (prefers-reduced-motion:reduce){
  .cfp-arcs-art{animation:none}
  .cfp-arcs-mirror .cfp-arcs-art{transform:scaleX(-1)}
  nav.cfp-nav a.cfp-nav-link::after,
  header,
  .cfp-features .cfp-feature,.cfp-features .cfp-icon,
  .cfp-course-card .cfp-course-thumb,
  .cfp-steps .cfp-step,
  .cfp-contact .cfp-contact-item .cfp-icon,
  footer a{transition:none}
  .cfp-features .cfp-feature:hover,
  .cfp-features .cfp-feature:hover .cfp-icon,
  .cfp-course-card:hover .cfp-course-thumb,
  .cfp-steps .cfp-step:hover,
  .cfp-contact .cfp-contact-item:hover .cfp-icon,
  footer a:hover,
  .cfp-btn:active,.cfp-filters button:active{transform:none}
}
/* ---------- Responsive ---------- */
@media (max-width:900px){
  .cfp-hero .cfp-wrap{grid-template-columns:1fr}
  .cfp-course-grid,.cfp-features,.cfp-steps{grid-template-columns:1fr 1fr}
  .cfp-stats .cfp-wrap{grid-template-columns:1fr 1fr;gap:28px}
  .cfp-about .cfp-wrap,.cfp-contact .cfp-wrap{grid-template-columns:1fr;gap:34px}
  .cfp-setup .cfp-wrap{grid-template-columns:1fr;gap:34px}
  footer .cfp-wrap{grid-template-columns:1fr 1fr}
  .cfp-detail .cfp-wrap{grid-template-columns:1fr;gap:34px}
  .cfp-enrol-card{position:static;order:-1}
}
@media (max-width:640px){
  nav.cfp-nav{display:none;position:absolute;top:100%;left:0;right:0;background:#fff;flex-direction:column;align-items:stretch;padding:12px 24px 20px;border-bottom:1px solid var(--line);box-shadow:var(--shadow);gap:4px}
  nav.cfp-nav.cfp-is-open{display:flex}
  nav.cfp-nav a.cfp-nav-link{padding:11px 0;border-bottom:1px solid var(--line)}
  .cfp-hamburger{display:block}
  .cfp-nav-cta .cfp-btn:not(.cfp-hamburger){display:none}
  .cfp-course-grid,.cfp-features,.cfp-steps,.cfp-stats .cfp-wrap,footer .cfp-wrap,.cfp-field-grid,.cfp-infogrid,.cfp-units{grid-template-columns:1fr}
  /* Email + Mobile shared one row down to 375, giving each input a 97px
     content box against a 111px 'jane@email.com' placeholder — clipped
     before a single character is typed. Declared with both classes to beat
     .cfp-field .cfp-field-row above. */
  .cfp-field .cfp-field-row{grid-template-columns:1fr}
  .cfp-topbar .cfp-topbar-left{display:none}
}

/* ---------- Curve clearance ----------
   Kept at the end of the sheet deliberately: these have to win against
   the responsive .cfp-section padding overrides declared above. */
@media (max-width:640px){:root{--curve-h:44px}}
.cfp-hero .cfp-wrap{padding-bottom:calc(var(--sp-hero-bottom) + var(--curve-h))}
.cfp-course-hero .cfp-wrap{padding-bottom:calc(var(--sp-hero-top) + var(--curve-h))}
.cfp-contact{padding-top:calc(var(--sp-section) + var(--curve-h))}
.cfp-ctaband{padding-top:calc(var(--sp-section) + var(--curve-h));padding-bottom:var(--sp-section)}
/* curves on both edges, so it needs clearance at both ends */
.cfp-setup{padding-top:calc(var(--sp-section) + var(--curve-h));padding-bottom:calc(var(--sp-section) + var(--curve-h))}

/* =========================================================================
   WORDPRESS BRIDGE

   Everything above this line is the source mockup's stylesheet, unmodified,
   so it can be replaced wholesale from styles.css. Everything below adapts
   it to the markup Elementor emits.

   ADDITIVE ONLY. If you replace the file above from the mockup, re-append
   this block afterwards.

   See docs/wordpress-migration/ — blocks are noted against the document
   that introduces them.
   ========================================================================= */

/* ---------- 06: Elementor's boxed-container wrapper ----------
   Elementor inserts .e-con-inner between a Boxed container and its children,
   which gives a grid declared on .cfp-wrap exactly one grid item and breaks
   the direct-child selector .cfp-arcs > .cfp-wrap. Every container in this
   build is set to Full Width so the wrapper is never created — this rule is
   insurance, and matches nothing when the build is correct. */
.cfp-wrap > .e-con-inner{display:contents}

/* ---------- 04: the double <header> ----------
   Elementor wraps every Theme Builder header in its own
   <header class="elementor-location-header">. A container inside it with
   HTML Tag: header therefore makes TWO <header> elements, the mockup's
   header{} rules style both, and app.js's document.querySelector('header')
   binds .cfp-is-stuck to the OUTER one.

   So the inner container is a div and Elementor's wrapper is THE header —
   see 04. That wrapper holds the topbar as well as the header row, and
   header{position:sticky;top:0} would pin both. Offsetting it by the
   topbar's own height scrolls the topbar away and rests the header row at
   the top of the viewport, which is what the mockup does with a topbar
   that is a plain sibling of <header>.

   --cfp-topbar-h is the topbar's rendered height: 8px padding top and
   bottom around a 25px line. Measure it again if the topbar's contents
   change; the symptom of a wrong value is the header row resting a few
   pixels high or low once the page is scrolled. */
:root{--cfp-topbar-h:41px}
header.elementor-location-header{top:calc(-1 * var(--cfp-topbar-h))}

/* ---------- 04: header children are content-width groups ----------
   Same Elementor default as .cfp-topbar-right — a child container arrives
   at width:100%. Here two of them do, so the nav and the CTA each claimed
   533px of the 1180 and squeezed the logo widget to 67px, which is why the
   wordmark rendered underneath the first nav link. The mockup's nav and CTA
   are plain divs in a flex row, i.e. content-width, and space-between then
   places logo, nav and CTA across the full width.

   .cfp-nav gets no padding reset: at <=640 it becomes the drawer and sets
   its own padding, which this would outrank. Set Padding: 0 in the panel
   instead — Elementor writes that at a lower specificity than the drawer
   rule, so the drawer still wins where it matters.

   Not scoped to header. The Elementor editor renders a template without
   its location wrapper, so there is no <header> on the canvas and a
   header-scoped rule would apply on the front end but not while you build,
   which is the worst way for a rule to behave. At <=640 .cfp-nav is an
   absolutely positioned drawer pinned by left:0/right:0, so width:auto
   changes nothing there. */
nav.cfp-nav{width:auto}
.cfp-nav-cta{width:auto;padding:0}

/* ---------- 04: Elementor Nav Menu ----------
   The mockup's nav is hand-written <a class="cfp-nav-link">; Elementor's Nav
   Menu widget emits <a class="elementor-item"> and brings its own padding and
   colours. This aliases Elementor's class to the mockup's rules inside
   .cfp-nav only, and zeroes the widget's own spacing. */
nav.cfp-nav .elementor-nav-menu{display:flex;align-items:center;gap:30px}
nav.cfp-nav .elementor-nav-menu li{margin:0}
/* .elementor-nav-menu is in these selectors for specificity, not to narrow
   the match. Elementor's widget defaults are
     .elementor-widget-nav-menu .elementor-nav-menu .elementor-item
       {font-weight:var(--e-global-typography-primary-font-weight)}
     .elementor-widget-nav-menu .elementor-nav-menu--main .elementor-item
       {color:var(--e-global-color-text)}
   at 0,3,0. Without the extra class these rules sit at 0,2,2 and lose, so
   the links render in Primary's weight 800 and Ink rather than 600 and
   Slate Soft — while font-size, which Elementor does not set, applied
   correctly and made the failure look like a partial one. */
nav.cfp-nav .elementor-nav-menu a.elementor-item{
  font-weight:600;color:var(--slate-soft);font-size:.96rem;
  position:relative;padding:0;background:none
}
nav.cfp-nav .elementor-nav-menu a.elementor-item:hover,
nav.cfp-nav .elementor-nav-menu a.elementor-item.elementor-item-active{color:var(--teal-dark)}
nav.cfp-nav .elementor-nav-menu a.elementor-item::after{
  content:"";position:absolute;left:0;right:0;bottom:-7px;height:2px;border-radius:2px;
  background:linear-gradient(135deg,var(--teal),var(--teal-darker));
  transform:scaleX(0);transform-origin:right;
  transition:transform .3s var(--reveal-ease-back)
}
nav.cfp-nav .elementor-nav-menu a.elementor-item:hover::after,
nav.cfp-nav .elementor-nav-menu a.elementor-item:focus-visible::after{
  transform:scaleX(1);transform-origin:left;
  transition:transform .26s var(--reveal-ease)
}
/* Elementor hides the pseudo-element outright whenever the link is not
   hovered:

     .elementor-item:not(:hover):not(:focus):not(.elementor-item-active)
                    :not(.highlighted):after{opacity:0}

   Each :not() carries the specificity of its argument, so that is 0,5,1 and
   it clears everything above. opacity is not in our transition, so the
   instant the pointer leaves, the line is switched off — while the transform
   underneath goes on animating for its full duration, invisibly. The effect
   looked like a transition that only played one way, and measuring the
   transform confirmed it was running, because the transform was never the
   problem.

   The same :not() chain plus this block's own classes comes to 0,7,3 and
   takes it back. Visibility stays entirely with the transform, which is what
   the mockup does — there the pseudo-element has no opacity rule at all. */
nav.cfp-nav .elementor-nav-menu a.elementor-item:not(:hover):not(:focus):not(.elementor-item-active):not(.highlighted)::after{
  opacity:1
}

/* ---------- 04: the drawer moves to <=900 ----------
   The mockup drops to the hamburger at 640 because its nav is five short
   hand-written links. Elementor's Nav Menu is wider — it carries the
   widget's own list markup — and the header row stops fitting on one line
   at tablet, wrapping the logo, nav and CTA onto separate rows. So the
   drawer takes over at 900 instead, which is also Elementor's Tablet
   breakpoint, and the header keeps its single row at every width.

   These repeat the mockup's own <=640 rules rather than editing them, so
   styles.css stays a droppable file. Below 640 both sets apply and agree. */
@media (max-width:900px){
  nav.cfp-nav{
    display:none;position:absolute;top:100%;left:0;right:0;width:auto;
    background:#fff;padding:12px 24px 20px;
    border-bottom:1px solid var(--line);box-shadow:var(--shadow)
  }
  nav.cfp-nav.cfp-is-open{display:flex}
  /* .e-con is here for specificity. Elementor's
       .e-con-full.e-flex{flex-direction:var(--flex-direction);
                          align-items:var(--align-items);
                          gap:var(--row-gap) var(--column-gap)}
     is 0,2,0 and clears nav.cfp-nav at 0,1,1, so the drawer would keep the
     panel's Row direction and Center alignment and lay its links out in a
     line. Routing through --flex-direction instead does not work either:
     Elementor's own per-element rule sets that variable at 0,3,0. */
  nav.cfp-nav.e-con{flex-direction:column;align-items:stretch;gap:4px}
  /* The widget nests <div> > <nav> > <ul> > <li> > <a>, and the middle
     <nav> is a flex ROW, so the <ul> is a flex item sized to its content —
     95px, the width of the longest label. Every divider then stopped there
     regardless of what the <a> did. */
  nav.cfp-nav .elementor-nav-menu__container,
  nav.cfp-nav .elementor-nav-menu{width:100%}
  nav.cfp-nav .elementor-nav-menu{flex-direction:column;align-items:stretch;gap:4px}
  /* display:block so the divider spans the drawer. Elementor puts each link
     inside an <li>, so the flex item that stretches is the <li> and the
     inline <a> only draws its border under the text — which is why the rule
     read as "the line stops short". The mockup has no <li> to get between
     them. */
  nav.cfp-nav .elementor-nav-menu a.elementor-item{
    display:block;padding:11px 0;border-bottom:1px solid var(--line)
  }
  .cfp-hamburger{display:block}
  .cfp-nav-cta .cfp-btn:not(.cfp-hamburger){display:none}
}

/* ---------- 05: the footer's RTO pill ----------
   Two things the mockup gets for free and Elementor does not.

   The mockup's pill is a <span class="cfp-pill"> inside a plain block <div>,
   so display:inline-block hugs its text. Elementor makes .cfp-foot-about a
   flex column, which BLOCKIFIES its children — inline-block computes to
   block — and align-items:normal then stretches it across the whole column.
   Measured 308px wide where the design is 88. align-self:flex-start opts it
   out of the stretch and width:auto lets it size to content.

   And the Text Editor wraps its content in <p>, which collects the 16px top
   margin from footer .cfp-foot-about p{margin:16px 0} — a rule written for
   the blurb above it, which the mockup's <span> never matched. That made the
   chip 44px tall against a designed 28. */
.cfp-foot-about .cfp-pill.elementor-widget{align-self:flex-start;width:auto}
.cfp-foot-about .cfp-pill p{margin:0}

/* ---------- 06: heading margins the widget reset clears ----------
   .elementor-heading-title{margin:0} is 0,1,0, so every mockup heading margin
   written as one class plus one element loses. The footer's was the first to
   show; these are the rest, restated at 0,2,1. The ones the mockup already
   writes with two classes — .cfp-detail .cfp-detail-main h2, .cfp-infogrid
   .cfp-infobox h4 — win on their own and are not listed.

   Only Heading WIDGETS carry .elementor-heading-title. A heading inside an
   HTML widget keeps the mockup's own rule and needs nothing. */
/* And their colour. The mockup's h1,h2,h3,h4{color:var(--slate)} is 0,0,1
   against Elementor's heading default at 0,2,0, so every heading on a light
   section renders in Global Primary teal instead of slate. Restated at 0,2,0
   here, ABOVE the dark-band overrides below, which tie on specificity and
   win on order. */
.elementor-widget-heading .elementor-heading-title{color:var(--slate)}
.cfp-section-head .elementor-heading-title{margin-bottom:10px}
.cfp-features .elementor-heading-title{margin-bottom:8px}
.cfp-step .elementor-heading-title{margin-bottom:6px}
.cfp-course-card .elementor-heading-title{margin-bottom:8px}
.cfp-hero-card .elementor-heading-title{margin-bottom:4px}
.cfp-form-card .elementor-heading-title{margin-bottom:4px}

/* ---------- 06: the filter row ----------
   .cfp-filters is declared with one class, so Elementor's
   .e-con-full.e-flex{gap;justify-content;flex-wrap} at 0,2,0 outranks it and
   the tabs lose their 10px gap, their centring and their wrapping. Adding
   .e-con brings this to 0,2,0 as well, which wins on load order.

   And the three <button>s live in one HTML widget — they have to, because
   app.js delegates real <button> clicks — so the row has a single flex child
   and the gap has nothing to sit between. Same display:contents fix as
   .cfp-cta-row. */
.cfp-filters.e-con{flex-direction:row;gap:10px;justify-content:center;flex-wrap:wrap}
.cfp-filters > [class*="elementor-widget-"]{display:contents}

/* ---------- 06: two buttons, one HTML widget ----------
   .cfp-cta-row is a flex row with gap:14px and expects the buttons to be its
   own children — that is how the mockup writes it, and how the gap finds
   something to sit between. Putting both anchors in one HTML widget, which is
   what avoids Elementor's Button widget and its wrapper-class problem, leaves
   the row with exactly ONE child: the widget div. The gap then has nothing to
   apply to and the two buttons touch, which only shows once they wrap onto
   separate lines at phone widths.

   display:contents drops the wrapper out of the box tree so the anchors
   become the row's flex children, and the mockup's own gap takes over — 14px
   horizontally on desktop, 14px vertically once wrapped. Same technique as
   the .e-con-inner guard further down. Covers .cfp-ctaband's row too. */
.cfp-cta-row > [class*="elementor-widget-"]{display:contents}

/* ---------- 04/06: Elementor's default container padding ----------
   Every container arrives with 10px on all four sides, which the mockup
   never asks for. On a phone that is 20px off the width of anything nested
   two containers deep: the hero's CTA row and the featured card measured
   307px against the mockup's 327, which reads as everything being slightly
   squeezed.

   Setting Padding: 0 by hand on every container works and is what the
   documents used to say, but there are dozens of them across 04-13 and one
   missed container is a 20px error nobody can see the cause of.

   Elementor derives that default through a variable of its own:

     .e-con{--padding-top:var(--container-default-padding-top,10px)}

   so redefining the four fallbacks changes the default everywhere at once.
   Explicit panel padding is unaffected — Elementor writes --padding-top
   directly on the element at 0,3,0, well above this — and so is every
   padding the stylesheet sets with the property itself, .cfp-wrap included. */
:root{
  --container-default-padding-top:0px;
  --container-default-padding-right:0px;
  --container-default-padding-bottom:0px;
  --container-default-padding-left:0px
}

/* ---------- 09: the course detail's h2 rhythm ----------
   The mockup separates the detail sections with

     .cfp-detail .cfp-detail-main h2:not(:first-child){margin-top:44px}

   which works because all six h2s are siblings inside .cfp-detail-main, so
   :first-child excludes exactly one — "Course overview".

   Under Elementor every h2 is the only child of its own widget wrapper: the
   Heading widget's div for the first, .elementor-shortcode for the five that
   come from [cfp_heading]. So EVERY h2 matches :first-child, the rule matches
   none of them, and all five gaps collapse to zero. Measured: every heading
   reported margin-top 0 against the mockup's 44px.

   Moving the :not() onto the wrapper restores it — the wrappers really are
   siblings, so :first-child means what the mockup meant by it. 0,3,1, which
   clears both .elementor-heading-title{margin:0} and the mockup's own
   0,2,1 margin shorthand. */
.cfp-detail-main > [class*="elementor-widget-"]:not(:first-child) h2{margin-top:44px}

/* ---------- 06: the arc artwork and the curve dividers ----------
   Both are position:absolute and expect .cfp-arcs to be the box they resolve
   against — .cfp-arcs-art{inset:0} fills the band, .cfp-curve-bottom
   {bottom:-1px} sits on its lower edge. In the mockup they are direct
   children of the band, so that is exactly what happens.

   Elementor wraps each one in a widget div and gives every widget
   position:relative. That div becomes the containing block instead, and it
   is a zero-height flex item at the top of the band, so the artwork computes
   to height:0 and disappears, and the bottom curve lands at the TOP of the
   section — a pale wave across the join, which is what it looks like in the
   editor before you notice the numbers.

   position:static on the wrapper hands the containing block back to
   .cfp-arcs. The wrapper stays a zero-height flex item and contributes
   nothing else. */
.cfp-arcs > [class*="elementor-widget-"]{position:static}

/* ---------- 06/09: selectors written as element.class ----------
   The mockup styles the hero lede as

     .cfp-hero p.cfp-lede{font-size:var(--fs-lede);color:#e2f4ef;
                          margin-top:16px;max-width:520px}

   — the class on a <p>. Elementor puts a Text Editor's CSS Classes on the
   WIDGET WRAPPER, a <div>, so p.cfp-lede matches nothing at all and the lede
   loses its size, colour, top margin and measure together. Not an override
   fight: the rule simply never applies.

   Restated for the wrapper. Watch for this shape anywhere the mockup writes
   element.class rather than .class — these two are the only ones. */
.cfp-hero .cfp-lede.elementor-widget,
.cfp-course-hero .cfp-lede.elementor-widget{
  font-size:var(--fs-lede);color:#e2f4ef;margin-top:16px
}
.cfp-course-hero .cfp-lede.elementor-widget{margin-top:14px}
/* The measure goes on the paragraph, not the wrapper: the wrapper is a flex
   item and its max-width is contested, while the <p> inside is not. */
.cfp-hero .cfp-lede p{max-width:520px}
.cfp-course-hero .cfp-lede p{max-width:640px}

/* ---------- 06: the dark bands ----------
   The same widget-default problem the topbar had, on every band that carries
   light text. Two shapes of it:

   Where the band sets a colour on itself — .cfp-hero and .cfp-ctaband — the
   widgets can simply inherit it back. The light cards nested inside those
   bands then have to re-assert their own: .cfp-hero-card is white with ink
   text, .cfp-form-card is white and its contents set their own colours.

   Where the band colours specific ELEMENTS instead — .cfp-setup-copy h2,
   .cfp-contact h2, .cfp-hero h1, all 0,1,1 — Elementor's heading default at
   0,2,0 wins and the heading renders in Global Primary teal on a dark teal
   ground. Those need restating, not inheriting.

   .cfp-setup-copy > p is a third case: the mockup's child combinator assumes
   the paragraph is a direct child, and a Text Editor puts its own div in
   between, so the rule stops matching entirely. */
.cfp-hero [class*="elementor-widget-"],
.cfp-ctaband [class*="elementor-widget-"]{color:inherit}
.cfp-hero-card [class*="elementor-widget-"]{color:var(--ink)}
.cfp-form-card [class*="elementor-widget-"]{color:var(--muted)}

.cfp-hero .elementor-heading-title,
.cfp-course-hero .elementor-heading-title,
.cfp-setup-copy .elementor-heading-title,
.cfp-contact .elementor-heading-title,
.cfp-ctaband .elementor-heading-title{color:#fff}
.cfp-form-card .elementor-heading-title{color:var(--slate)}
.cfp-setup-copy > [class*="elementor-widget-"] p{
  color:#dcefe9;font-size:var(--fs-lede);margin:12px 0 24px;max-width:52ch
}

/* ---------- 06: the eyebrow is a <div> in the mockup ----------
   .cfp-eyebrow carries its colour and 0.78rem size, and under Elementor that
   class lands on the Text Editor's wrapper while the text sits in a <p>
   inside it. Any rule that targets paragraphs in the same block then hits the
   eyebrow, which a <div> never was: .cfp-section-head p{color:var(--muted);
   font-size:var(--fs-body-lg)} turned it grey at body size, and
   .cfp-setup-copy's lede rule would tint it #dcefe9.

   Inheriting from the wrapper restores whatever the band intends — teal-dark
   on light sections, #a9ebdb on the hero and the setup band — without naming
   any of them. 0,2,1, the same weight as .cfp-setup-copy's own
   paragraph rule, so it has to sit AFTER that rule to win the tie — which is
   why this block lives down here rather than with the other 06 fixes. */
.cfp-eyebrow.elementor-widget p{color:inherit;font-size:inherit}

/* ---------- 06: the Contact band ----------
   Most of this band needs nothing. .cfp-contact{color:#dce8e4} sets a base
   the contact items inherit, and everything else names its own element at
   0,3,0 — .cfp-contact-item b, .cfp-contact-item span — so Elementor's widget
   defaults lose without help. Deliberately NOT adding .cfp-contact to the
   blanket color:inherit list further down: that would sit above
   .cfp-contact .cfp-lede{color:#cfe0dc} and flatten the lede to the band's
   own #dce8e4.

   Two things do need restating. The lede's 26px bottom margin is a widget
   margin, so Elementor's 0,3,0 zeroes it — four classes here clears that. And
   the eyebrow's mint is an inline style="" in the mockup, the same problem
   as the three in the About column. */
.cfp-contact .cfp-eyebrow{color:var(--mint)}
.cfp-contact .cfp-lede.elementor-widget.elementor-widget{margin-bottom:26px}

/* ---------- 06: the About visual ----------
   .cfp-about-visual is a flex box in the mockup that centres the quote in a
   400px-tall gradient panel, and the two big + marks are absolutely
   positioned against it. Two things break under Elementor:

   Its align-items and justify-content are 0,1,0, under Elementor's
   .e-con-full.e-flex at 0,2,0 — so the quote would sit top-left instead of
   centred. Restated at 0,2,0, which wins on order.

   And the + marks live inside an HTML widget whose wrapper Elementor gives
   position:relative, so they would anchor to that zero-height wrapper rather
   than to the panel — the same fault as the arc artwork in §1. Handing the
   containing block back with position:static puts them in the corners, where
   overflow:hidden crops them as intended.

   min-height:400px needs nothing: it is 0,1,0 against Elementor's own
   .e-con{min-height:var(--min-height)} at 0,1,0, and wins on order. */
.cfp-about-visual.e-con{align-items:center;justify-content:center}
.cfp-about-visual > [class*="elementor-widget-"]{position:static}

/* ---------- 06: the About column's three inline styles ----------
   The mockup sets font-size on the h2, colour and margin-top on the intro,
   and margin-top on the button with style="" attributes. Elementor's editor
   strips some inline attributes on save, which produces a section that looks
   right until someone reopens it, so they are restated here against two
   classes that exist only for this purpose — cfp-about-copy on the column and
   cfp-about-lede on the intro. Both are set in the panel; neither appears in
   the mockup. */
.cfp-about-copy .elementor-heading-title{font-size:2.15rem}
.cfp-about-lede p{color:var(--muted);margin-top:14px}
.cfp-about-copy .cfp-btn{margin-top:26px}

/* ---------- 06: the video's aspect-ratio box inside a flex column ----------
   .cfp-video is sized entirely by aspect-ratio:16/9 — its poster and its
   iframe are both position:absolute, so the box has no in-flow content and no
   intrinsic height of its own. In the mockup .cfp-setup-media is a plain
   block <div>, so the video takes its width from the column and derives its
   height, and the parent follows.

   Elementor makes every container a flex column. An aspect-ratio box with no
   in-flow children measures badly as a flex item: the grid row came out
   199px while the video painted 403, so the poster spilled through the bottom
   curve into the next section and took the caption with it. It only shows
   between roughly 430 and 900, where the two columns have stacked but the
   video is still wide enough for the difference to be large.

   Restoring display:block makes it the plain div the mockup assumes. Measured
   after: the row grows to 451px at 764, 311 at 514 and 362 at 1440, each one
   containing its video. */
.cfp-setup-media.e-con{display:block}

/* ---------- 06: Elementor zeroes every widget's bottom margin ----------
     .e-con .elementor-widget.elementor-widget{margin-block-end:0}

   at 0,3,0 — the class is repeated deliberately to make it hard to override.
   Any mockup rule that spaces an element with margin-bottom loses it the
   moment that element becomes a widget wrapper. Two do:

     .cfp-eyebrow{margin-bottom:12px}                 0,1,0
     .cfp-step .cfp-step-num{margin-bottom:16px}      0,2,0

   The eyebrow one has been wrong on every section since the hero — 12px
   missing under every eyebrow on the site. Repeating .elementor-widget here
   matches their 0,3,0 and wins on load order.

   Not affected: .cfp-features .cfp-icon and .cfp-setup-points sit inside HTML
   widgets rather than being wrappers themselves, and .cfp-filters and
   .cfp-section-head are containers, which carry .e-con and not
   .elementor-widget. */
.cfp-eyebrow.elementor-widget.elementor-widget{margin-bottom:12px}
.cfp-step .cfp-step-num.elementor-widget.elementor-widget{margin-bottom:16px}

/* ---------- 06: the step numeral ----------
   .cfp-step .cfp-step-num paints the 42px tile and sets color:#fff on the
   WRAPPER, but the numeral itself is a <p> inside it — and .cfp-step p
   {color:var(--muted);font-size:.9rem} at 0,1,1 targets that paragraph
   directly, so the digit renders muted grey at body size on the teal tile.
   Same shape as the eyebrow: a rule written for the card's body copy, which
   the mockup's <div class="cfp-step-num"> never matched. */
.cfp-step .cfp-step-num p{color:inherit;font-size:inherit}

/* ---------- 05/06: the grid gaps Elementor overwrites ----------
   The mockup declares display:grid, grid-template-columns AND gap on every
   layout wrapper, so nothing about the grid needs setting in a panel. Two of
   those three survive contact with Elementor: it never sets
   grid-template-columns, and its .e-con{display:var(--display)} is 0,1,0,
   which the mockup's own rules match or beat.

   gap is the exception. Elementor's .e-con-full.e-flex{gap:var(--row-gap)
   var(--column-gap)} is 0,2,0, and with Widgets Space set to 0 in 03 those
   variables resolve to 0px. Any mockup gap declared with fewer than two
   classes loses and the layout closes up. The wrappers that already use two
   (.cfp-hero .cfp-wrap, .cfp-stats .cfp-wrap, .cfp-about, .cfp-contact,
   .cfp-setup, .cfp-detail) tie on specificity and win on order, so they are
   not listed here — only the ones that lose.

   Restated at 0,2,x rather than set in the panel, because --sp-gap is a
   clamp() and no panel field can express it. */
footer .cfp-wrap.e-con{gap:34px}
.cfp-course-grid.e-con,
.cfp-features.e-con,
.cfp-steps.e-con{gap:var(--sp-gap)}

/* ---------- 04: Hello Elementor's link hover colour ----------
   reset.css sets

     a:active,a:hover{color:#336}

   at 0,1,1. The mockup gives links `color:inherit` and lets the component
   decide, so a colour that lives on the anchor's own class — .cfp-btn-primary
   at 0,1,0, with no hover rule of its own because it never needed one — is
   overridden the moment the pointer lands. #336 is a dark navy that reads as
   black on the teal button.

   The first rule restores the mockup's inheritance for ordinary links. It sits
   at 0,1,1 and loads later, so it clears reset.css while staying below every
   component rule that names its own hover colour: .cfp-topbar a:hover (0,2,1),
   footer a:hover (0,1,2) and .cfp-btn-ghost:hover (0,2,0) all still win.

   The variants below carry their colour on the anchor itself, so inheritance
   is not what they want — they need the value restating at 0,2,1. */
a:hover,a:focus,a:active{color:inherit}

/* The variants restate BOTH colour and background, and are not qualified to
   <a>. [cfp_enrol_button] emits a <button> whenever the course has no
   axcelerate_url, so reset.css's button:hover{background-color:#c36} at 0,1,1
   applies to it — the CTA band's Enrol Now went magenta on hover while the
   identical-looking link beside it did not. 0,2,0 here clears both a:hover and
   button:hover in one go, whichever element the renderer chose. */
.cfp-btn-primary:hover,.cfp-btn-primary:focus,.cfp-btn-primary:active{
  background:linear-gradient(135deg,var(--teal),var(--teal-dark));color:#fff
}
.cfp-btn-white:hover,.cfp-btn-white:focus,.cfp-btn-white:active{
  background:#fff;color:var(--teal-dark)
}
.cfp-btn-outline-white:hover,.cfp-btn-outline-white:focus,.cfp-btn-outline-white:active{
  background:transparent;color:#fff
}
.cfp-btn-ghost:hover,.cfp-btn-ghost:focus,.cfp-btn-ghost:active{background:transparent}

/* ---------- 09: stacked buttons in the enrolment card ----------
   The mockup separates them with style="margin-top:10px" on the second one.
   .cfp-btn + .cfp-btn would be the obvious replacement and does not work:
   Elementor puts each in its own widget wrapper, so they are not siblings —
   the same counting problem as the detail column's :first-child. A class on
   the button itself does not care what wraps it. */
.cfp-btn-stacked{margin-top:10px}

/* ---------- 04: Hello Elementor's default button styling ----------
   reset.css paints every bare <button>:

     button:focus, button:hover{background-color:#c36;color:#fff}

   at 0,1,1, which clears .cfp-hamburger's 0,1,0 — so the hamburger sits
   correctly until you touch it and then flashes magenta. The base state was
   never wrong, which is why this only shows on hover, focus and the moment
   after a tap. */
.cfp-hamburger,
.cfp-hamburger:hover,
.cfp-hamburger:focus,
.cfp-hamburger:active{background:none;border:none;color:inherit;box-shadow:none}
.cfp-hamburger:focus-visible{outline:2px solid var(--teal-dark);outline-offset:3px}

/* ---------- 04: the topbar at <=640 ----------
   With .cfp-topbar-left hidden the three contact items still overflow a
   phone and wrap, landing ragged against the left gutter. Centring them and
   splitting the gap into a tight row gap and a looser column gap makes the
   wrap look deliberate rather than broken. */
@media (max-width:640px){
  .cfp-topbar .cfp-wrap{justify-content:center}
  .cfp-topbar .cfp-topbar-right{
    flex-wrap:wrap;justify-content:center;gap:6px 16px;text-align:center
  }
}

/* ---------- 08: renderer icon colours ----------
   cfp_icon() draws with currentColor so each context can colour its icons
   from CSS. Every other context already sets a colour or inherits correctly;
   the course hero's quickfacts were a literal #bff0e4 in the mockup. */
.cfp-course-hero .cfp-quickfact svg{color:#bff0e4}

/* ---------- 09: course detail ----------
   Two small treatments the mockup carried as inline style attributes.
   Elementor can strip inline styles pasted into a Text Editor on save, which
   produces a section that looks right until someone opens it again. */
.cfp-detail-main .cfp-elective-label{margin-top:22px;font-weight:800;color:var(--slate)}
.cfp-detail-main .cfp-disclaimer{font-size:.82rem;color:var(--muted);margin-top:34px}

/* ---------- 10: short-course badge ----------
   The mockup carried this as an inline style on each short-course badge. */
.cfp-badge.cfp-badge-short{background:var(--teal-dark);color:#fff}

/* ---------- 13: sticky footer ----------
   Hello Elementor wraps everything in #page.site and lets the footer fall
   wherever the content ends. On a short page the body background shows
   beneath it: measured on the privacy-policy stub at 1440x900, the footer
   ended at 536px with 364px of empty page below.

   The mockup never showed this because every one of its pages is taller than
   the viewport. The four legal stubs from 12 are the first short pages the
   site has ever had.

   min-height on the wrapper is not enough on its own — the footer has to be
   pushed down, which needs a flex column plus margin-top:auto. body and #page
   are both made column flex because Hello Elementor's wrapper is filterable
   and may not always be there.

   .cfp-overlay (position:fixed) and .cfp-arcs-defs (position:absolute) are
   out of flow, so neither becomes a flex item. The editor is excluded: it
   appends its own furniture to body and should keep normal block flow. */
body:not(.elementor-editor-active){min-height:100vh;display:flex;flex-direction:column}
body:not(.elementor-editor-active) > #page,
body:not(.elementor-editor-active) > .site{display:flex;flex-direction:column;flex:1 0 auto}
main.site-main,.elementor-location-main{flex:1 0 auto}
.elementor-location-footer,body > footer,#page > footer{margin-top:auto}

/* ---------- 12: Elementor Form ----------
   Maps Elementor's form classes onto the mockup's field styling so the
   contact card looks identical without forking .cfp-field. */
/* Fallback only. The widget's own Rows Gap / Columns Gap are emitted as
   .elementor-element-<id> .elementor-field-group{...}, which ties this on
   specificity and wins on load order — so the numbers that actually apply are
   the ones typed into the panel (Rows 16, Columns 14, matching .cfp-field's
   margin-bottom and .cfp-field-row's gap). This covers the case where they
   are left unset. */
.cfp-form-card .elementor-field-group{margin-bottom:16px}
.cfp-form-card .elementor-field-group > label{
  display:block;font-weight:700;font-size:.84rem;
  color:var(--slate);margin-bottom:6px
}
.cfp-form-card .elementor-field-textual{
  width:100%;padding:12px 14px;border:1.5px solid var(--line);border-radius:10px;
  font-family:inherit;font-size:.95rem;color:var(--ink);background:#fff;transition:.15s
}
.cfp-form-card .elementor-field-textual:focus{
  outline:none;border-color:var(--teal);
  box-shadow:0 0 0 3px rgba(47,164,143,.15)
}

/* The Form widget offers a Button ID, not a button CSS class, so there is no
   way to put .cfp-btn .cfp-btn-primary .cfp-btn-block on the submit from the
   panel — it renders as a bare .elementor-button and the enquiry button ends
   up the one grey control on the page. Restated here at 0,3,0, which beats
   both .elementor-button (0,1,0) and the Style tab's
   .elementor-element-<id> .elementor-button (0,2,0). */
.cfp-form-card .elementor-field-type-submit .elementor-button{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  width:100%;font-family:inherit;font-weight:700;font-size:.98rem;
  padding:13px 24px;border-radius:999px;border:2px solid transparent;
  cursor:pointer;transition:.18s;white-space:nowrap;
  background:linear-gradient(135deg,var(--teal),var(--teal-dark));color:#fff;
  box-shadow:0 8px 20px rgba(31,122,110,.28)
}
.cfp-form-card .elementor-field-type-submit .elementor-button:hover,
.cfp-form-card .elementor-field-type-submit .elementor-button:focus{
  transform:translateY(-2px);box-shadow:0 12px 26px rgba(31,122,110,.38);
  background:linear-gradient(135deg,var(--teal),var(--teal-dark));color:#fff
}
.cfp-form-card .elementor-field-type-submit .elementor-button:active{
  transform:translateY(0) scale(.985)
}

/* Match .cfp-form-note so the confirmation reads as part of the design
   rather than a plugin default. */
.cfp-form-card .elementor-message{
  margin-top:14px;font-size:.86rem;color:var(--teal-dark);
  background:var(--mint-soft);border:1px solid #c8e6dc;border-radius:10px;padding:10px 12px
}
/* .elementor-message is also the class on validation errors, both the inline
   per-field span and the form-level one, so the rule above renders a failure
   in the success palette. The mockup's error colours are .cfp-field-err
   (#c0392b) and .cfp-field.cfp-is-invalid (#e07b6c). */
.cfp-form-card .elementor-message.elementor-message-danger{
  color:#c0392b;background:#fdf1ef;border-color:#f0cec7
}
.cfp-form-card .elementor-message.elementor-help-inline{
  margin-top:5px;padding:0;background:none;border:0;font-size:.8rem
}
.cfp-form-card .elementor-field-group.elementor-error .elementor-field-textual{
  border-color:#e07b6c;box-shadow:0 0 0 3px rgba(224,123,108,.15)
}
/* The required asterisk inherits the label's slate otherwise, reading as
   part of the label text. */
.cfp-form-card .elementor-mark-required .elementor-field-label:after{color:#c0392b}

/* ---------- 04: mark-only logo artwork ----------
   The mockup had only the vertical lockup (mark stacked above the
   wordmark), so .cfp-logo-mark windows the mark out of it with three
   measured percentages — width:127.4%, left:-14.19%, top:-1.01% against
   an aspect-ratio of 2671/2870. The WordPress build has a proper
   mark-only export instead, and pointing those offsets at it crops into
   the mark rather than around it.

   No crop is needed for a mark-only file: the image simply fills the box.
   The mark's own proportions are 2360/2534 = 0.9313, which is the crop box
   the mockup already describes (2671/2870 = 0.9307) to within 0.06%, so
   .cfp-logo-mark keeps its aspect-ratio untouched and the mark lands at
   exactly the designed size. object-fit:contain is the safety net: an
   export with different proportions is letterboxed rather than stretched.

   Use a TRIMMED export — assets/img/logo-mark.png, cropped to the mark's
   opaque bounding box. Transparent padding around the mark is not free:
   contain fits the whole canvas, so padding shrinks the mark inside its
   box. The file WordPress produced (Certifii-Plus-Logo-Fit-scaled.png,
   2560x2560) carries ~100px of it on three sides.

   Delete this block and the mockup's crop takes over again, unchanged —
   which is what you want if the lockup ever becomes the source. */
.cfp-logo .cfp-logo-mark img{
  position:static;width:100%;height:100%;left:auto;top:auto;object-fit:contain
}

/* ---------- 04: Elementor's container defaults vs the mockup's divs ----------
   Two defaults Elementor gives every container that a plain <div> does not
   have, both measured on the topbar:

   width:100% on a CHILD container. The mockup's .cfp-topbar-right is a div in
   a flex row, so it is content-width and justify-content:space-between pushes
   it to the right gutter. At 100% it instead fills all 861px of free space,
   its own contents pack against its left edge, and the row reads as though
   space-between were not applied at all — the group's right edge IS at the
   gutter, its contents are just 480px short of it. Panel equivalent: set the
   child container's Width to Inline.

   padding:10px on every container. The mockup puts padding on .cfp-wrap and
   nowhere else, so this quietly added 20px to the topbar's height (45px where
   the design is 25px). Panel equivalent: Advanced → Padding: 0. */
.cfp-topbar .cfp-topbar-right{width:auto;padding:0}

/* ---------- 04/05: the Text Editor widget's paragraph margins ----------
   Elementor's Text Editor wraps its content in <p>, and Hello Elementor's
   p{margin-bottom} beats the mockup's universal *{margin:0} reset whatever the
   load order — 0,0,1 against 0,0,0. Inside a chip that margin is visible
   height: it made .cfp-pill 39px tall against a designed 25px, which is why
   the chip read as a rounded rectangle rather than a pill. Never an issue in
   the mockup, where .cfp-pill is a <span> with no paragraph in it.

   :where() contributes nothing to specificity, so this rule weighs exactly
   0,0,1 — the same as reset.css's own p{margin-bottom}. Loading later, it
   wins that tie and clears the default; and it loses to every one of the
   eight places the mockup deliberately sets a paragraph margin, from
   .cfp-setup-copy > p at 0,1,1 to .cfp-detail .cfp-detail-main p at 0,2,1,
   so none of those are touched.

   Both blunt versions were tried first and both were wrong. Zeroing every
   Text Editor's last paragraph at 0,2,1 also cleared footer .cfp-foot-about
   p (0,1,2) and closed the gap above the RTO chip. Scoping it to three
   places left a 14.4px margin under the topbar text, pushing it 7px above
   the contact group and growing the topbar from 41px to 51 and the footbar
   from 57 to 71. The footer chip still needs its own line below: it sits
   inside .cfp-foot-about, whose 0,1,2 rule outranks a bare p. */
:where(.elementor-widget-text-editor) p{margin:0}
.cfp-foot-about .cfp-pill p{margin:0}

/* ---------- 04: .cfp-wrap is a flex ITEM under Elementor ----------
   In the mockup every band is a plain block <div> and .cfp-wrap fills it,
   capped at 1180 and centred by margin:0 auto. Elementor renders every
   container as a flex box, so .cfp-wrap becomes a flex ITEM and is sized
   shrink-to-fit — the wrapper ends up only as wide as its contents, the row
   never reaches the 1180 gutters, and justify-content:space-between has no
   free space left to distribute, so a space-between row reads as packed to
   one side.

   Setting the band's Direction to Column in the panel fixes it (a column's
   align-items:stretch gives the child full width). This rule is the same
   insurance as the .e-con-inner guard below: harmless when the panel is set
   correctly, and it rescues the layout when it is not. */
.e-con > .cfp-wrap{width:100%}

/* ---------- 04: Elementor widget colour defaults vs the dark bands ----------
   Elementor writes a widget default into every template's generated CSS:

     .elementor-widget-text-editor{color:var(--e-global-color-text)}

   and applies it to the widget element itself. A DIRECTLY APPLIED declaration
   always beats an INHERITED one whatever the specificity, so a colour a band
   sets on itself can never reach text sitting inside a widget. On the topbar
   that put Ink #2b3f49 on #0b6153 green — 1.4:1, effectively invisible — while
   .cfp-pill looked correct, because that rule targets the widget element
   directly and this one does not.

   Re-inheriting through the widget wrapper hands the band's own colour back.
   The attribute selector catches every widget type at once (text-editor,
   heading, icon-list, button…) at 0,2,0, which clears Elementor's 0,1,0.
   Heading widgets colour the inner .elementor-heading-title, so that element
   is named separately.

   EXTEND THIS LIST as you build each dark band — .cfp-hero, .cfp-setup,
   .cfp-contact and the other .cfp-arcs sections all set light text on a dark
   ground and will need the same treatment. Watch for light-ground components
   nested inside a dark band (a white .cfp-form-card on .cfp-contact, for
   instance): those must re-assert their own colour after this rule, or their
   text inherits the band's white onto white. */
.cfp-topbar [class*="elementor-widget-"],
.cfp-topbar .elementor-heading-title,
footer [class*="elementor-widget-"],
footer .elementor-heading-title{color:inherit}
/* ---------- 05/06: Elementor's Heading widget reset ----------
   Every Heading widget on the site is reset by

     .elementor-heading-title{line-height:1;margin:0;padding:0}

   at 0,1,0, which clears the mockup's h1,h2,h3,h4{line-height:1.2} at 0,0,1
   and any element-level margin. The line-height applies to every heading in
   the build, so it is restored globally at 0,2,0.

   Margins are per-context and have to be restated where the mockup sets one.
   In the footer that is footer h4{margin-bottom:16px} at 0,0,2 — the gap
   between each column heading and its first link, which was collapsing to
   nothing. The same rule carries the white the mockup gives footer h4, since
   Elementor's own heading colour is 0,2,0 and the inherit rule above would
   otherwise leave it the body's #9db3ad. */
.elementor-widget-heading .elementor-heading-title{line-height:1.2}
footer .elementor-widget-heading .elementor-heading-title{color:#fff;margin-bottom:16px}

/* ---------- Motion ----------
   The mockup switches every transition off under prefers-reduced-motion;
   the aliased nav link needs the same treatment. */
@media (prefers-reduced-motion:reduce){
  nav.cfp-nav .elementor-nav-menu a.elementor-item::after{transition:none}
}
