/* ------------------------------------------------------------
   Measure.

   On hand-written markup these set the box directly. On an Elementor
   container the same job is done by --content-width, which Elementor
   itself reads back (see the compatibility layer at the foot of this
   file), so the direct properties are held off .e-con to leave that
   mechanism -- and the client's editor controls -- in charge.
   ------------------------------------------------------------ */
.wrap:not(.e-con) {
    max-width: 1160px;
    margin: 0 auto;
    padding: 0 var(--gutter)
}

.narrow:not(.e-con) {
    max-width: 820px
}

/* ---------- type ---------- */
/* `text-box: trim-both` removes the font's half-leading above the cap height
   and below the baseline, so the space around a heading is the space the
   layout asked for rather than that plus whatever Inter/SF Pro shipped.
   Baseline since Aug 2026; a browser without it renders exactly as before.
   `balance` evens the line lengths of a heading, `pretty` (further down)
   keeps a paragraph from ending on an orphan. */
h1,
h2,
h3,
h4 {
    color: var(--ink);
    font-weight: 600;
    font-optical-sizing: auto;
    text-wrap: balance;
    text-box: trim-both cap alphabetic;
}

h1 {
    font-size: clamp(2.35rem, 4.6vw, 3.7rem);
    line-height: 1.04;
    letter-spacing: -.036em
}

h2 {
    font-size: clamp(2rem, 4.2vw, 3.1rem);
    line-height: 1.06;
    letter-spacing: -.03em
}

h3 {
    font-size: 1.3rem;
    line-height: 1.22;
    letter-spacing: -.018em
}

h4 {
    font-size: 1.06rem;
    line-height: 1.3;
    letter-spacing: -.012em
}

h1 .soft {
    color: var(--ink-3)
}

p {
    max-width: 64ch;
    text-wrap: pretty;
}

li {
    text-wrap: pretty
}

.lede {
    font-size: clamp(1.12rem, 1.9vw, 1.32rem);
    line-height: 1.5;
    color: var(--ink-2);
    letter-spacing: -.011em;
    text-wrap: balance;
}

.cap {
    font-size: .94rem;
    line-height: 1.5;
    color: var(--ink-3);
    letter-spacing: 0
}

.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--red);
}

.eyebrow::before {
    content: "";
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--red-graphic)
}

/* ---------- glass material ----------

   Real glass is bright where light enters at the top edge and dark where it
   grounds at the bottom. A single inset highlight reads as a translucent
   rectangle; the four-part rim below -- top highlight, bottom shade, inner
   ring, outer lift -- is what makes it read as a material.

   Deliberately NOT feDisplacementMap refraction: Chromium-only, fixed-shape
   only, and unspecified (w3c/svgwg#1142). This is most of the perceived
   effect with none of the maintenance. */
.glass {
    position: relative;
    background: linear-gradient(180deg, rgba(255, 255, 255, .72), rgba(255, 255, 255, .54));
    -webkit-backdrop-filter: blur(28px) saturate(190%) brightness(1.04);
    backdrop-filter: blur(28px) saturate(190%) brightness(1.04);
    border: 1px solid transparent;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .95),
        inset 0 -1px 0 rgba(9, 18, 28, .10),
        inset 0 0 0 1px rgba(255, 255, 255, .35),
        var(--lift-md);
    overflow: hidden;
}

/* specular sheen — the light the material catches, tracks the pointer */
.glass::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    background: radial-gradient(340px circle at var(--gx, 50%) var(--gy, 0%),
            rgba(255, 255, 255, .62), transparent 62%);
    opacity: 0;
    transition: opacity .45s var(--ease-out);
}

.glass.lit::after {
    opacity: 1
}

.glass-dark {
    background: linear-gradient(180deg, rgba(241, 244, 248, .085), rgba(241, 244, 248, .035));
    -webkit-backdrop-filter: blur(22px) saturate(160%) brightness(1.06);
    backdrop-filter: blur(22px) saturate(160%) brightness(1.06);
    border: 1px solid transparent;
    box-shadow:
        inset 0 1px 0 rgba(241, 244, 248, .16),
        inset 0 -1px 0 rgba(0, 0, 0, .22),
        inset 0 0 0 1px var(--glass-dark-edge);
}

.glass-dark::after {
    background: radial-gradient(300px circle at var(--gx, 50%) var(--gy, 0%), rgba(241, 244, 248, .10), transparent 60%)
}

/* ---------- buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    min-height: 54px;
    padding: 0 30px;
    border-radius: var(--r-pill);
    font-family: inherit;
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -.012em;
    text-decoration: none;
    border: 1px solid transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: transform .1s var(--ease-out), background-color .22s var(--ease-out),
        border-color .22s var(--ease-out), box-shadow .22s var(--ease-out);
    will-change: transform;
}

/* A .btn is often a plain anchor -- in the header template, in a text
   widget on /contact/ -- and both the theme's link styles and Elementor's
   `.elementor-widget-text-editor a` outrank the variant classes below, which
   underlined the label and repainted it on hover. Pinning the states here,
   at a:hover-beating specificity, makes every one of them behave like the
   real button widget in the hero. */
a.btn,
a.btn:hover,
a.btn:focus,
a.btn:active,
a.btn:visited,
/* Elementor underlines links inside a text editor at .elementor-widget-text-editor a,
   which outranks a plain a.btn -- matched explicitly rather than padded with a
   repeated class. */
.elementor-widget-text-editor a.btn,
.elementor-widget-text-editor a.btn:hover,
.elementor-widget-text-editor a.btn:focus,
.elementor-widget-text-editor a.btn:visited {
    text-decoration: none
}

a.btn.btn-primary,
a.btn.btn-primary:hover,
a.btn.btn-primary:focus,
a.btn.btn-primary:visited {
    color: #fff
}

a.btn.btn-white,
a.btn.btn-white:hover,
a.btn.btn-white:focus,
a.btn.btn-white:visited {
    color: var(--navy)
}

a.btn.btn-glass,
a.btn.btn-glass:hover,
a.btn.btn-glass:focus,
a.btn.btn-glass:visited {
    color: var(--ink)
}

a.btn.btn-glass-dark,
a.btn.btn-glass-dark:hover,
a.btn.btn-glass-dark:focus,
a.btn.btn-glass-dark:visited {
    color: var(--bone)
}

.btn-primary {
    background: var(--navy);
    color: #fff;
    box-shadow: var(--lift-sm)
}

.btn-glass {
    background: rgba(255, 255, 255, .55);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    backdrop-filter: blur(20px) saturate(180%);
    border-color: rgba(255, 255, 255, .8);
    color: var(--ink);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .95), var(--lift-sm);
}

.btn-glass-dark {
    background: rgba(241, 244, 248, .09);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    backdrop-filter: blur(20px) saturate(160%);
    border-color: rgba(241, 244, 248, .2);
    color: var(--bone);
}

.btn-white {
    background: #fff;
    color: var(--navy);
    box-shadow: var(--lift-sm)
}

@media(hover:hover) and (pointer:fine) {
    .btn-primary:hover {
        background: var(--navy-lift);
        box-shadow: var(--lift-md)
    }

    .btn-glass:hover {
        background: rgba(255, 255, 255, .78)
    }

    .btn-glass-dark:hover {
        background: rgba(241, 244, 248, .15)
    }

    .btn-white:hover {
        box-shadow: var(--lift-md)
    }
}

/* One specular pass across the primary CTA on hover -- one pass, never a
   loop. `btn-primary` typed into Elementor lands on the widget WRAPPER, so
   the sweep has to be painted on the anchor or it paints a square slab
   behind the pill. Same wrapper/anchor split as the rest of this layer. */
.btn.btn-primary,
.elementor-widget-button.btn-primary .elementor-button {
    position: relative;
    overflow: hidden;
}

.btn.btn-primary::after,
.elementor-widget-button.btn-primary .elementor-button::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(105deg, transparent 34%, rgba(255, 255, 255, .3) 50%, transparent 66%);
    transform: translateX(-130%);
}

@media(hover:hover) and (pointer:fine) {

    .btn.btn-primary:hover::after,
    .elementor-widget-button.btn-primary .elementor-button:hover::after {
        animation: sweep .78s var(--ease-out)
    }
}

@keyframes sweep {
    from {
        transform: translateX(-130%)
    }

    to {
        transform: translateX(130%)
    }
}

/* feedback on pointer-down, never on release */
.btn.press {
    transform: scale(.97)
}

:focus-visible {
    outline: 2px solid var(--navy);
    outline-offset: 3px;
    border-radius: 4px
}

/* The global rule above swaps every focused element to a 4px radius so the
   outline hugs text links; on a pill button that snapped the corners square
   the moment it took keyboard focus. Same specificity, later in the sheet. */
.btn:focus-visible,
.elementor-button:focus-visible {
    border-radius: var(--r-pill)
}

.on-dark :focus-visible {
    outline-color: var(--red-lift)
}

.skip {
    position: absolute;
    left: -9999px
}

.skip:focus {
    left: 16px;
    top: 16px;
    z-index: 200;
    background: var(--navy);
    color: #fff;
    padding: 14px 20px;
    border-radius: var(--r-pill)
}

/* ---------- floating glass header ---------- */
.hdr {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    padding: var(--hdr-pad) var(--gutter);
    pointer-events: none
}

.hdr-inner {
    max-width: 1160px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 26px;
    height: var(--hdr-h);
    padding: 0 12px 0 22px;
    border-radius: var(--r-pill);
    pointer-events: auto;
    background: rgba(251, 251, 253, .55);
    -webkit-backdrop-filter: blur(24px) saturate(180%);
    backdrop-filter: blur(24px) saturate(180%);
    border: 1px solid rgba(255, 255, 255, .6);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .85);
    transition: background-color .3s var(--ease-out), box-shadow .3s var(--ease-out), border-color .3s var(--ease-out);
}

/* scroll edge effect — chrome thickens only once content is under it */
.hdr.stuck .hdr-inner {
    background: rgba(251, 251, 253, .82);
    border-color: rgba(255, 255, 255, .85);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .95), 0 10px 34px -14px rgba(9, 18, 28, .28);
}

/* The brand mark replaces the old text wordmark. It is the client's artwork
   used as drawn -- a stacked lockup, emblem over wordmark -- so its height is
   what has to give in a horizontal bar, not its arrangement. At 56px the
   emblem and NEXUS are unambiguous and VETERAN MD is legible; the bar grew to
   80px to carry it. The company name is the img's alt text, so the link keeps
   its accessible name. */
.logo {
    display: flex;
    align-items: center;
    flex: none;
    text-decoration: none;
    color: var(--ink)
}

.logo-img {
    height: 56px;
    width: auto;
    display: block
}

.nav {
    display: flex;
    gap: 4px;
    margin-left: auto
}

.nav a {
    padding: 9px 14px;
    border-radius: var(--r-pill);
    font-size: .95rem;
    font-weight: 500;
    letter-spacing: -.01em;
    text-decoration: none;
    color: var(--ink-2);
    transition: background-color .18s var(--ease-out), color .18s var(--ease-out);
}

@media(hover:hover) and (pointer:fine) {
    .nav a:hover {
        background: rgba(9, 18, 28, .055);
        color: var(--ink)
    }
}

.hdr .btn {
    min-height: 46px;
    padding: 0 22px;
    font-size: .95rem
}

@media(max-width:1040px) {
    .nav {
        display: none
    }

    .hdr .btn {
        margin-left: auto
    }
}

.hdr .btn .sm {
    display: none
}

@media(max-width:640px) {
    :root {
        --hdr-h: 66px
    }

    .hdr-inner {
        padding: 0 8px 0 14px;
        gap: 10px
    }

    .logo-img {
        height: 46px
    }

    .hdr .btn {
        min-height: 42px;
        padding: 0 16px;
        font-size: .9rem
    }

    .hdr .btn .lg {
        display: none
    }

    .hdr .btn .sm {
        display: inline
    }
}


/* ---------- hero ---------- */
.hero {
    position: relative;
    /* Tighter than the rest of the page on purpose. The booking calendar
       sets this section's height now -- it is 671px against the headline
       block's 396px -- so the hero no longer needs generous padding to have
       presence, and the extra was pushing the next section off a laptop
       screen. The --hdr-clear term is not part of the trim: it is what keeps
       the content out from under the fixed header. */
    padding: calc(var(--pad) * .5 + var(--hdr-clear) - 24px) 0 calc(var(--pad) * .6);
    overflow: hidden
}

.aurora {
    position: absolute;
    inset: -14%;
    z-index: 0;
    pointer-events: none;
    will-change: transform
}

.aurora i {
    position: absolute;
    display: block;
    border-radius: 50%;
    filter: blur(64px);
    opacity: .9
}

.aurora i:nth-child(1) {
    width: 52vw;
    height: 52vw;
    left: 44%;
    top: -14%;
    background: radial-gradient(circle, rgba(31, 71, 136, .42), transparent 66%)
}

.aurora i:nth-child(2) {
    width: 40vw;
    height: 40vw;
    left: 66%;
    top: 26%;
    background: radial-gradient(circle, rgba(74, 139, 206, .32), transparent 66%)
}

/* The third lobe is warm, and it is the only warm thing in the hero.
   Three blue fields over a blue-white paper is what made this page read as
   clinical; one low, wide field of warm light behind the headline is what a
   room with a lamp in it looks like. It is a warm neutral, not red -- the
   rule that ambient layers never take the accent red still stands, and for
   the same reason: red at low opacity over a large area reads as an alarm,
   not as a tint. */
.aurora i:nth-child(3) {
    width: 46vw;
    height: 46vw;
    left: -16%;
    top: 16%;
    background: radial-gradient(circle, rgba(198, 152, 106, .26), transparent 66%)
}

.hero-grid:not(.e-con) {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1.08fr .92fr;
    gap: clamp(36px, 5vw, 72px);
    align-items: center
}

/* The Elementor path needs the same centring, and does not inherit it from
   the rule above -- that one is the no-Elementor fallback and is scoped
   :not(.e-con).

   It matters more here than it looks. The booking calendar is 671px tall and
   the headline block is 395px, so top-aligned they leave a 276px hole under
   the buttons. Centring splits it above and below, which is the only lever
   available: the card's height is Calendly's own reported content height, and
   forcing it shorter just gives the booking widget an internal scrollbar.

   Set as the custom property rather than align-items, so an alignment the
   client picks in the editor still wins. */
.hero-grid.e-con {
    --align-items: center;
}

@media(max-width:980px) {
    .hero-grid:not(.e-con) {
        grid-template-columns: 1fr;
        gap: 48px
    }
}

/* The brand mark above the headline.

   A second instance of a logo that is already in the chrome, which is only
   worth doing if it is doing a different job: the header mark is 40px of
   navigation furniture, and this is the practice introducing itself at the
   top of its own page. So it is sized to be read rather than to be clicked,
   and it sits above the eyebrow rather than beside it.

   Height rather than width, because the artwork is a fixed-ratio drawing and
   the height is what has to agree with the type below it. */
.hero-mark {
    margin-bottom: 22px
}

.hero-mark img {
    width: auto;
    /* Deliberately much larger than the 56px mark in the fixed bar. At
       matched sizes the two read as the same logo printed twice, one under
       the other, which is worse than not having it here at all -- the size
       gap is what makes one navigation furniture and the other the practice
       signing its own page. */
    height: clamp(76px, 9vw, 116px)
}

@media(max-width:980px) {
    .hero-mark img {
        height: 82px
    }
}

.hero h1 {
    margin: 20px 0 22px;
    max-width: 19ch
}

.hero .lede {
    max-width: 52ch
}

.cta-row:not(.e-con) {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 34px
}

.hero .cta-row .btn {
    padding: 0 26px
}

/* ---------- Calendly inline embed (hero right column) ----------

   The booking widget lives on the page instead of behind a click. Three
   things have to be managed from out here, because the widget itself is a
   cross-origin iframe and cannot be styled at all:

   WIDTH. Calendly's calendar is seven day-columns wide. Below about 480px it
   drops to a cramped single-column layout and grows very tall, so the hero
   grid is 1fr 1fr rather than the old 1.2fr .8fr -- the column has to clear
   that threshold before anything else can be tuned. `hide_event_type_details`
   in the URL does the other half of the job by removing Calendly's own
   left-hand panel, which would otherwise eat half the width repeating the
   event name.

   HEIGHT. The heights here are a reserved floor, not the final value. The
   box has to be roughly right before Calendly answers or the hero reflows
   when the iframe lands, so the page allocates the space up front; then
   booking.js takes Calendly's own `calendly.page_height` messages and sets
   the exact height, again when a date is picked and the time slots appear.
   Without that the card is either a fixed box with dead space under the
   month view or one that scrolls internally once the slots show.

   FAILURE. booking.js adds .cal-failed when the widget does not load inside
   4s, which reveals the fallback anchor. Without it a Calendly outage would
   leave a blank rectangle where the booking used to be. */
.cal-card {
    border-radius: var(--r-lg);
    background: var(--glass);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    backdrop-filter: blur(20px) saturate(180%);
    padding: 14px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .95),
        inset 0 -1px 0 rgba(9, 18, 28, .10),
        inset 0 0 0 1px rgba(255, 255, 255, .35),
        var(--lift-lg);
}

/* Slides in from the right, opposite the headline block -- the two halves of
   the hero close on each other.

   Translate only, never scale. .rv rests at scale(.985) and .rv-l/.rv-r add
   their own .99; scaling an iframe mid-transition resamples the widget's
   text, so it arrives visibly blurred and snaps sharp at the end. A pure
   translate is a compositor move and leaves the raster alone, which is why
   the transform is written out here rather than inherited. */
.cal-card.rv {
    transform: translateX(var(--rv-x))
}

.cal-card.rv.in {
    transform: none
}

.cal-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 10px 12px;
}

.cal-dur {
    font-family: var(--mono);
    font-size: .72rem;
    letter-spacing: .06em;
    color: var(--ink-3);
    white-space: nowrap;
}

.cal-inline {
    position: relative;
    min-width: 320px;
    height: 604px;
    transition: height .32s var(--ease-out);
    border-radius: var(--r-md);
    overflow: hidden;
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Calendly injects an iframe as the only child once it initialises. */
.cal-inline iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

/* Loading shimmer, replaced the moment the iframe is appended. */
.cal-inline:not(.cal-ready):not(.cal-failed)::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(100deg, transparent 20%, rgba(31, 71, 136, .07) 50%, transparent 80%),
        var(--mist);
    background-size: 220% 100%, auto;
    animation: cal-shim 1.4s linear infinite;
}

@keyframes cal-shim {
    from { background-position: 120% 0, 0 0 }
    to   { background-position: -120% 0, 0 0 }
}

/* The fallback is present in the markup from the start so it works with no
   JS at all, but it is only *shown* once the widget has actually failed --
   otherwise it would flash under the shimmer on every load. */
.cal-fallback {
    display: none;
    position: relative;
    z-index: 1;
}

.cal-inline.cal-failed { height: auto; padding: 40px 24px; background: var(--mist) }
.cal-inline.cal-failed .cal-fallback { display: inline-flex }
.cal-inline.cal-ready .cal-fallback { display: none }

@media(max-width:1100px) {
    .cal-inline { height: 680px }
}

/* Stacked under the headline. The column is now full width, so the widget
   gets its roomy layout back and needs less height for it. */
@media(max-width:960px) {
    .cal-inline { height: 620px }
}

@media(max-width:640px) {
    .cal-card { padding: 10px }
    .cal-inline { min-width: 0; height: 660px }
    .cal-head { padding: 4px 6px 10px }
}

@media(prefers-reduced-motion:reduce) {
    .cal-inline:not(.cal-ready):not(.cal-failed)::after { animation: none }
}

/* ---------- proof card (signature) ---------- */
.proof {
    border-radius: var(--r-lg);
    padding: clamp(28px, 3.4vw, 40px);
    will-change: transform;

    /* Two sheets peeking out below, so the signature element reads as the top
       page of a document rather than as a UI panel.

       Drawn as outer box-shadows, not pseudo-elements: .glass clips its own
       overflow and .proof's will-change makes it a stacking context, so a
       z-index:-1 child would be clipped or would paint over the card's own
       background. An outer shadow is always behind the background and is
       never clipped by the element's overflow. The insets repeat .glass's
       rim because a box-shadow declaration replaces it wholesale. */
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .95),
        inset 0 -1px 0 rgba(9, 18, 28, .10),
        inset 0 0 0 1px rgba(255, 255, 255, .35),
        0 7px 0 -1px var(--surface),
        0 7px 0 0 var(--hairline),
        0 14px 0 -2px var(--surface),
        0 14px 0 -1px var(--hairline),
        var(--lift-md);
}

.proof-label:not(.e-con) {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px
}

.proof-label .cap {
    font-family: var(--mono);
    font-size: .72rem;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ink-3)
}

/* The red seal — two concentric rings, drawn not imaged. They are SVG
   rather than CSS borders so they can stroke on like a stamp when the card
   arrives: a document being certified, which is what the card is about. */
.proof-seal {
    flex: none;
    display: block;
    width: 34px;
    height: 34px;
    opacity: .85;
}

.proof-seal circle {
    fill: none;
    stroke: var(--red-graphic);
    stroke-linecap: round;
    transform: rotate(-90deg);
    transform-origin: center;
}

.proof-seal .o {
    stroke-width: 1.5;
    stroke-dasharray: 97;
    stroke-dashoffset: 97;
}

.proof-seal .i {
    stroke-width: 1;
    stroke-dasharray: 66;
    stroke-dashoffset: 66;
    opacity: .6;
}

.rv.in .proof-seal .o {
    animation: draw .95s var(--ease-out) .1s forwards
}

.rv.in .proof-seal .i {
    animation: draw .95s var(--ease-out) .28s forwards
}

@keyframes draw {
    to {
        stroke-dashoffset: 0
    }
}

.proof-title {
    margin: 16px 0 0;
    font-size: clamp(1.45rem, 2.3vw, 1.8rem);
    font-weight: 600;
    letter-spacing: -.03em;
    line-height: 1.15;
    color: var(--ink)
}

.proof-list:not(.e-con) {
    list-style: none;
    margin: 24px 0 0;
    padding: 0;
    display: grid;
    gap: 14px
}

.proof-list li {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ink-2);
    opacity: 0;
    transform: translateY(6px);
}

.proof-list svg {
    flex: none;
    margin-top: 1px;
}

.proof-list circle {
    fill: rgba(31, 71, 136, .1)
}

.proof-list path {
    fill: none;
    stroke: var(--navy);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 16;
    stroke-dashoffset: 16;
}

/* each line lands, then its check draws — the card assembles rather than
   appearing, which is the one hero moment on the page */
.rv.in .proof-list li {
    opacity: 1;
    transform: none;
    transition: opacity .5s var(--ease-out), transform .5s var(--spring);
}

.rv.in .proof-list li:nth-child(1) {
    transition-delay: .34s
}

.rv.in .proof-list li:nth-child(2) {
    transition-delay: .43s
}

.rv.in .proof-list li:nth-child(3) {
    transition-delay: .52s
}

.rv.in .proof-list li:nth-child(4) {
    transition-delay: .61s
}

.rv.in .proof-list li:nth-child(1) path {
    animation: draw .45s var(--ease-out) .5s forwards
}

.rv.in .proof-list li:nth-child(2) path {
    animation: draw .45s var(--ease-out) .59s forwards
}

.rv.in .proof-list li:nth-child(3) path {
    animation: draw .45s var(--ease-out) .68s forwards
}

.rv.in .proof-list li:nth-child(4) path {
    animation: draw .45s var(--ease-out) .77s forwards
}

.proof-note {
    margin-top: 26px;
    padding-top: 22px;
    border-top: 1px solid var(--hairline);
    font-size: .98rem;
    line-height: 1.55;
    color: var(--ink-2);
    max-width: none
}

.proof-note strong {
    color: var(--ink);
    font-weight: 600
}

/* ---------- sections ---------- */
.sec:not(.e-con) {
    padding: var(--pad) 0
}

/* The conditions grid continues the dark section above it, so it drops the
   padding that would otherwise put a gap in the middle of one surface. */
.sec-flush:not(.e-con) {
    padding-top: 0
}

.e-con.sec-flush {
    --padding-top: 0px
}

.sec-mist {
    background: var(--mist)
}

/* ------------------------------------------------------------
   Dark surfaces.

   .sec-dark is the painted surface; .on-dark is the ink that goes with
   it. They are separate because not every dark surface is a .sec-dark
   -- the CTA .band paints its own gradient and only needs the ink. Any
   element can opt into the dark palette by taking .on-dark alone.
   ------------------------------------------------------------ */
.sec-dark {
    background: var(--deep)
}

/* ---------- the dot field ----------

   Two tiled copies of one dot grid on every section: a base that is barely
   there, and a lens masked to a soft circle at the pointer, so the field
   brightens under the cursor the way paper does under a lamp.

   Pseudo-elements rather than markup. There are 331 generated sections
   across the site and none of them should need a widget added to carry a
   background; .sec is already on all of them. .band is excluded because it
   spends both its pseudo-elements on the sky glow and the grain, and it
   has the seal watermark already -- one ambient system per screen.

   The dots invert with the ground: ink on the light sections, sky on the
   dark ones, at opacities low enough that you notice the texture rather
   than the pattern. Only a mask offset changes on pointer move, which is
   compositor work: no repaint, no layout. */
.sec:not(.band),
.hero {
    position: relative;
    overflow: hidden;
    --dot: rgba(9, 18, 28, .55);
    --dot-base: .085;
    --dot-lens: .5;
}

.sec-dark:not(.band),
.sec.on-dark:not(.band) {
    --dot: rgba(74, 139, 206, .95);
    --dot-base: .13;
    --dot-lens: .85;
}

.sec:not(.band)::before,
.sec:not(.band)::after,
.hero::before,
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: radial-gradient(circle, var(--dot) 1.05px, transparent 1.45px);
    background-size: 24px 24px;
}

/* feathered at the edges, or the grid reads as a box laid on the section */
.sec:not(.band)::before,
.hero::before {
    opacity: var(--dot-base);
    -webkit-mask: radial-gradient(120% 96% at 50% 42%, #000 34%, transparent 78%);
    mask: radial-gradient(120% 96% at 50% 42%, #000 34%, transparent 78%);
}

.sec:not(.band)::after,
.hero::after {
    opacity: var(--dot-lens);
    -webkit-mask: radial-gradient(190px circle at var(--mx, -20%) var(--my, 50%), #000 0%, rgba(0, 0, 0, .42) 44%, transparent 72%);
    mask: radial-gradient(190px circle at var(--mx, -20%) var(--my, 50%), #000 0%, rgba(0, 0, 0, .42) 44%, transparent 72%);
}

/* An Elementor boxed container puts its widgets in an .e-con-inner, and the
   pseudo-elements above are painted after it. Lifting the content one level
   keeps the field behind it without reordering anything. */
.sec>.e-con-inner,
.sec:not(.e-con)>.wrap,
.sec:not(.e-con)>.narrow,
/* the hero is a full-width container, so it has no .e-con-inner and its
   children sit directly in it; the aurora keeps its own z-index: 0 and the
   dots land on top of it, which is where a texture belongs */
.hero>.e-con,
.hero>.wrap {
    position: relative;
    z-index: 1;
}

.sec-dark,
.on-dark {
    color: var(--sage)
}

:is(.sec-dark, .on-dark) :is(h1, h2, h3, h4, h5, h6) {
    color: var(--bone)
}

:is(.sec-dark, .on-dark) .eyebrow {
    color: var(--red-lift)
}

:is(.sec-dark, .on-dark) .eyebrow::before {
    background: var(--red-lift)
}

:is(.sec-dark, .on-dark) :is(p, li, .lede, .cap) {
    color: var(--sage)
}

.sec-head:not(.e-con) {
    max-width: none;
    margin-bottom: clamp(44px, 5vw, 68px)
}

/* The measure lives on the text. Constraining the container instead left a
   narrow column standing above a full-width grid, and cut the red rule
   under the heading down with it. */
.sec-head h2 {
    max-width: 22ch
}

.sec-head.wide h2 {
    max-width: 32ch
}

/* the red rule opens the section the way a rule opens a chapter; it
   wipes in with the head rather than being there from the start */
.sec-head h2 {
    margin: 18px 0 14px;
    position: relative;
    padding-bottom: 16px;
}

.sec-head h2::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    /* the full measure of the heading, not a stub under it */
    width: 100%;
    height: 2px;
    background: linear-gradient(90deg, var(--red-graphic),
            color-mix(in srgb, var(--red-graphic) 6%, transparent));
    transform: scaleX(0);
    transform-origin: left;
}

/* Its own trigger, not .rv.in. The reveal observer fires at 15% of a section
   head inside a viewport shortened by 10%, which for a two-line h2 is the
   moment its first pixels clear the bottom edge -- the rule had finished
   wiping before the heading was anywhere near read. `.ruled` lands when the
   whole heading is up out of the bottom two-fifths of the screen -- around
   mid-viewport -- so the wipe plays where someone is looking. motion.js owns
   the class. */
.sec-head h2.ruled::after {
    transform: scaleX(1);
    transition: transform .9s var(--ease-out) .1s;
}

.sec-head p {
    max-width: 56ch
}

/* ---------- can / can't ---------- */
.duo:not(.e-con) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px
}

@media(max-width:860px) {
    .duo:not(.e-con) {
        grid-template-columns: 1fr
    }
}

.panel {
    border-radius: var(--r-lg);
    border: 1px solid var(--hairline)
}

.panel:not(.e-con) {
    padding: clamp(30px, 3.4vw, 42px)
}

.panel-can {
    background: var(--surface);
    box-shadow: var(--lift-md)
}

.panel-cant {
    background: transparent
}

.panel h3 {
    margin-bottom: 8px
}

.panel>.cap {
    margin-bottom: 24px
}

.panel ul {
    list-style: none;
    display: grid;
    gap: 2px
}

.panel li {
    position: relative;
    padding: 13px 0 13px 34px;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ink-2);
    border-top: 1px solid var(--hairline)
}

.panel li:first-child {
    border-top: 0
}

.panel li::before {
    position: absolute;
    left: 0;
    top: 14px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: .72rem;
    font-weight: 700;
    line-height: 1;
}

.panel-can li::before {
    content: "✓";
    background: rgba(31, 71, 136, .1);
    color: var(--navy)
}

.panel-cant li::before {
    content: "—";
    background: rgba(9, 18, 28, .06);
    color: var(--ink-3)
}

/* ---------- entry cards ---------- */
.cards:not(.e-con) {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 18px
}

@media(max-width:960px) {
    .cards:not(.e-con) {
        grid-template-columns: repeat(2, 1fr)
    }
}

@media(max-width:620px) {
    .cards:not(.e-con) {
        grid-template-columns: 1fr
    }
}

.card {
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    box-shadow: var(--lift-sm);
    transition: transform .4s var(--spring), box-shadow .4s var(--ease-out);
}

.card:not(.e-con) {
    padding: 30px 28px 32px
}

@media(hover:hover) and (pointer:fine) {
    .card:hover {
        transform: translateY(-4px);
        box-shadow: var(--lift-md)
    }
}

.card .eyebrow {
    font-size: .72rem;
    margin-bottom: 16px
}

.card h3 {
    font-size: 1.14rem;
    margin-bottom: 10px
}

.card p {
    font-size: .98rem;
    line-height: 1.52;
    color: var(--ink-2)
}

/* ---------- process rail ---------- */
.proc:not(.e-con) {
    display: grid;
    grid-template-columns: .82fr 1.18fr;
    gap: clamp(32px, 5vw, 72px);
    align-items: start
}

@media(max-width:900px) {
    .proc:not(.e-con) {
        grid-template-columns: 1fr;
        gap: 44px
    }
}

.proc-head {
    position: sticky;
    top: 110px;
    margin-bottom: 0
}

@media(max-width:900px) {
    .proc-head {
        position: static;
        top: auto
    }
}

.rail-wrap:not(.e-con) {
    display: grid;
    grid-template-columns: 44px 1fr;
    gap: 0
}

@media(max-width:620px) {
    .rail-wrap:not(.e-con) {
        grid-template-columns: 30px 1fr
    }
}

.rail {
    position: relative;
    width: 2px;
    margin-left: 14px;
    background: var(--hairline-dark);
    border-radius: 2px
}

.rail-fill {
    position: absolute;
    inset: 0;
    border-radius: 2px;
    background: linear-gradient(180deg, var(--red-lift), var(--sky));
    transform-origin: top;
    transform: scaleY(0)
}

.steps:not(.e-con) {
    list-style: none
}

.step {
    position: relative;
    padding: 0 0 clamp(38px, 4.4vw, 56px) clamp(22px, 3vw, 36px)
}

.step:last-child {
    padding-bottom: 0
}

.step .dot {
    position: absolute;
    left: calc(-14px - 6px);
    top: 6px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--deep);
    border: 2px solid var(--hairline-dark);
    transition: border-color .4s var(--ease-out), background-color .4s var(--ease-out)
}

@media(max-width:620px) {
    .step .dot {
        left: calc(-8px - 6px)
    }
}

.step.hit .dot,
.e-con.step.hit::before {
    background: var(--red-lift);
    border-color: var(--red-lift)
}

/* the dot lands rather than tinting: one expanding ring, once per step */
.step .dot::after {
    content: "";
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 2px solid var(--red-lift);
    opacity: 0;
    transform: scale(.6);
}

.step.hit .dot::after {
    animation: ping .85s var(--ease-out) forwards
}

@keyframes ping {
    0% {
        opacity: .9;
        transform: scale(.6)
    }

    70%,
    100% {
        opacity: 0;
        transform: scale(2.5)
    }
}

.step .num {
    display: block;
    font-family: var(--mono);
    font-size: .7rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--red-lift);
    margin-bottom: 9px
}

.step h3 {
    margin-bottom: 8px
}

.step p {
    font-size: 1rem;
    line-height: 1.55;
    max-width: 58ch
}

/* ---------- conditions grid ----------

   A grid on the front end and in the builder both. It was a horizontal rail
   on the front end until the client asked for the grid back on 26 Aug 2026
   -- carousel.js, the .is-carousel block that lived here and its
   reduced-motion rule all went with the request.

   Five tracks, not the old four: the section carries ten primary conditions
   now, which fill two clean rows at five and leave a row of two at four. */
.grid-cond:not(.e-con) {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 12px
}

@media(max-width:1100px) {
    .grid-cond:not(.e-con) {
        grid-template-columns: repeat(3, 1fr)
    }
}

@media(max-width:760px) {
    .grid-cond:not(.e-con) {
        grid-template-columns: repeat(2, 1fr)
    }
}

@media(max-width:430px) {
    .grid-cond:not(.e-con) {
        grid-template-columns: 1fr
    }
}

/* The secondary grid sits under its own sub-head.

   A .sec-head one level down: the h3 takes the h2's spacing and its red
   rule, at a smaller size, so the two halves of the conditions section read
   as one section divided rather than as two sections run together. The rule
   is static here -- ruledHeads() in motion.js watches h2 only, and a second
   wiping rule ten lines under the first is a tic rather than a flourish. */
.sub-head {
    margin-top: clamp(52px, 6vw, 84px)
}

.sub-head h3 {
    position: relative;
    max-width: 32ch;
    margin: 16px 0 14px;
    padding-bottom: 14px;
    font-size: clamp(1.24rem, 1.9vw, 1.62rem);
}

.sub-head h3::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 2px;
    background: linear-gradient(90deg,
            color-mix(in srgb, var(--red-graphic) 62%, transparent),
            color-mix(in srgb, var(--red-graphic) 5%, transparent));
}

.sub-head p {
    max-width: 56ch
}

.grid-secondary {
    margin-bottom: 28px
}

/* ---------- priority grading ----------

   "we need to show top priority first, then lesser priority the more down we
   go. a grading color the more down we go will also be nice."

   --tier runs 1 (the client's highest priority) to 5, two conditions per
   tier, in reading order: left to right along the first row of five, then the
   second. Everything below is derived from that one number, so retiering a
   tile is a matter of swapping its tier-N class in Elementor's CSS-classes
   field -- there is no per-tile paint to keep in step.

   The grade is carried on the red, which is the brand's own accent and the
   colour every other emphasis on this site already uses. It is deliberately
   restrained: a tier-1 tile is a tinted surface with a warm rim, not a red
   card. Red at weight over a large area on a dark ground reads as an alarm,
   which is the same reason the ambient layers take --sky and not this.

   .tile is (0,1,0) and so are these, so source order decides -- they are
   below the resting state on purpose. */
.tile {
    --tier: 6;
    /* how far down the scale this tile sits: 1 at tier 1, 0 at tier 6 */
    --grade: calc((6 - var(--tier)) / 5)
}

.tier-1 { --tier: 1 }
.tier-2 { --tier: 2 }
.tier-3 { --tier: 3 }
.tier-4 { --tier: 4 }
.tier-5 { --tier: 5 }

/* One background-color, never a colour over a ground. Two background *layers*
   cannot interpolate with the single colour the hover state uses, so a
   gradient here makes the surface drop out and come back rather than fade.
   Nested color-mix() gets the same look out of one colour. */
.grid-primary .tile {
    background: color-mix(in srgb,
            var(--red-graphic) calc(var(--grade) * 11%),
            rgba(241, 244, 248, .035));
    border-color: color-mix(in srgb,
            var(--red-lift) calc(var(--grade) * 30%),
            rgba(241, 244, 248, .09));
}

/* The grade is carried by the surface and the rim only, never by the label.
   `.tile-note` sits on the widget *wrapper* and colours the heading inside
   it by inheritance, which Elementor's injected per-element colour rule --
   (0,4,0), on the title itself, canvas only -- overrides. A graded label
   would therefore be right on the published page and flat in the builder,
   and the fix for that class of mismatch is to rebind the global rather than
   out-specify it, which a value that changes per tier cannot do. The surface
   tint carries the grade on its own; see the screenshots in BUILD-LOG.md. */

@media(hover:hover) and (pointer:fine) {
    .grid-primary .tile:hover {
        background: color-mix(in srgb,
                var(--red-graphic) calc(var(--grade) * 11% + 4%),
                rgba(241, 244, 248, .075));
    }
}

.tile {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 10px;
    min-height: 104px;
    border-radius: var(--r-sm);
    text-decoration: none;
    color: var(--bone);
    background: rgba(241, 244, 248, .035);
    border: 1px solid rgba(241, 244, 248, .09);
    transition: background-color .25s var(--ease-out), transform .4s var(--spring);
    overflow: hidden;
}

.tile:not(.e-con) {
    padding: 20px 18px
}

.tile b {
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -.014em;
    line-height: 1.25
}

.tile em {
    margin-top: auto;
    font-family: var(--mono);
    font-style: normal;
    font-size: .66rem;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--sage)
}

/* The proximity value motion.js already computes used to be spent on an
   inset shadow, which reads as a smudge. Sent into a gradient masked to the
   1px border instead, it lights the actual rim, so the tile nearest the
   cursor looks physically closer to it. --mx/--my place the hot spot where
   the pointer is; --near fades the whole thing with distance. */
.tile::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    pointer-events: none;
    background: radial-gradient(190px circle at var(--mx, 50%) var(--my, 50%),
            rgba(74, 139, 206, calc(.10 + var(--near, 0) * .8)),
            rgba(74, 139, 206, .05) 55%,
            transparent 75%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
}

/* Twenty tiles are links and nothing said so. A chevron that slides in on
   hover is the whole affordance -- drawn in CSS so the generated tile keeps
   its two heading widgets and nothing else. */
.tile::after {
    content: "";
    position: absolute;
    right: 17px;
    bottom: 19px;
    width: 7px;
    height: 7px;
    border-right: 1.6px solid var(--red-lift);
    border-top: 1.6px solid var(--red-lift);
    transform: translateX(-4px) rotate(45deg);
    opacity: 0;
    pointer-events: none;
    transition: opacity .3s var(--ease-out), transform .4s var(--spring);
}

@media(hover:hover) and (pointer:fine) {
    .tile:hover {
        background: rgba(241, 244, 248, .075);
        transform: translateY(-3px)
    }

    .tile:hover::after {
        opacity: 1;
        transform: translateX(0) rotate(45deg);
    }
}

/* ---------- contact channels ----------

   The three ways to reach the practice sit in .card, and the thing you act on
   is the last line of each. Pushing it to the bottom of the card keeps the
   three actions on one line across the row however long the copy above them
   runs. */
.contact-line {
    margin-top: auto;
    padding-top: 4px;
}

.contact-line p {
    max-width: none
}

.contact-strong {
    font-size: 1.08rem;
    font-weight: 600;
    letter-spacing: -.014em;
    color: var(--navy);
    text-decoration: none;
    border-bottom: 1px solid color-mix(in srgb, var(--navy) 34%, transparent);
    padding-bottom: 2px;
    transition: border-color .25s var(--ease-out), color .25s var(--ease-out);
}

.contact-strong:hover {
    color: var(--navy-lift);
    border-bottom-color: var(--navy-lift);
}

/* An anchor written into a text widget, not a button widget: it carries the
   classes itself, so no wrapper compatibility is needed. Its colour and
   underline are pinned with the other anchor buttons up in the button
   block. */
.contact-line .btn {
    min-height: 48px;
    padding: 0 22px;
    font-size: .98rem;
}



/* ---------- blocked note ---------- */
.blocked {
    border: 1.5px dashed rgba(168, 29, 41, .42);
    background: rgba(196, 36, 50, .055);
    border-radius: var(--r-md);
}

.blocked:not(.e-con) {
    padding: clamp(26px, 3vw, 36px)
}

.blocked .eyebrow {
    margin-bottom: 14px
}

.blocked p+p {
    margin-top: 14px
}

/* ---------- faq ---------- */
.faq {
    border-top: 1px solid var(--hairline)
}

.faq details {
    border-bottom: 1px solid var(--hairline)
}

.faq summary {
    list-style: none;
    cursor: pointer;
    position: relative;
    padding: 26px 56px 26px 0;
    min-height: 48px;
    font-size: 1.18rem;
    font-weight: 600;
    letter-spacing: -.018em;
    line-height: 1.32;
    color: var(--ink);
}

.faq summary::-webkit-details-marker {
    display: none
}

.faq .ic {
    position: absolute;
    right: 6px;
    top: 50%;
    width: 30px;
    height: 30px;
    margin-top: -15px;
    border-radius: 50%;
    background: rgba(9, 18, 28, .055);
    pointer-events: none
}

.faq .ic::before,
.faq .ic::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    background: var(--ink);
    border-radius: 2px;
    transition: transform .22s var(--ease-out), opacity .22s var(--ease-out);
}

.faq .ic::before {
    width: 11px;
    height: 1.5px;
    margin: -.75px 0 0 -5.5px
}

.faq .ic::after {
    width: 1.5px;
    height: 11px;
    margin: -5.5px 0 0 -.75px
}

.faq details[open] .ic::after {
    transform: scaleY(0);
    opacity: 0
}

.faq .ans {
    padding: 0 12% 30px 0;
    font-size: 1.04rem;
    line-height: 1.6;
    color: var(--ink-2)
}

.faq details[open] .ans {
    animation: ansIn .15s var(--ease-out) both
}

@keyframes ansIn {
    from {
        opacity: 0;
        transform: translateY(-4px)
    }

    to {
        opacity: 1;
        transform: none
    }
}

/* ---------- cta band ---------- */
/* Left-aligned, like every other section on the page. Centring one band at
   the bottom made the eyebrow, which is inline-flex and shrink-wraps, sit at
   the start edge while everything under it was centred. */
.band {
    position: relative;
    overflow: hidden;
    text-align: left;
    background: linear-gradient(160deg, #132C52 0%, #0A1729 58%, #123050 100%);
    color: var(--sage);
}

.band::before {
    content: "";
    position: absolute;
    width: 70vw;
    height: 70vw;
    left: 50%;
    top: -30%;
    transform: translateX(-50%);
    /* dropped from .16 so it does not fight the seal watermark on the right */
    background: radial-gradient(circle, rgba(74, 139, 206, .12), transparent 62%);
    filter: blur(46px);
    pointer-events: none;
}

/* ---------- grain ----------

   Not decoration. The band and the aurora are 46-64px-blurred gradients over
   a dark ground, which is the recipe for visible banding on an 8-bit panel.
   A monochrome noise tile dithers the ramp away; the side effect is a
   printed-paper texture, which suits a practice that issues documents.

   A static data-URI tile, not a live feTurbulence filter: the filter is
   recomputed on paint and costs real time across a full-width band on
   mobile, where a repeating background image costs nothing. */
.band::after,
.aurora::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    opacity: .5;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* on the aurora, not on .hero: an ::after on the section is the last child
   and would lay grain over the headline itself. The aurora sits below the
   hero grid, which is where a texture belongs. */
.aurora::after {
    opacity: .38
}

/* ---------- the seal watermark ----------

   The proof card's seal, oversized and bled off the right edge of the
   closing band, turning once every two and a half minutes. You never catch
   it moving; you notice on a second visit that it has. */
.sealmark {
    position: absolute;
    right: -70px;
    top: 50%;
    width: 340px;
    height: 340px;
    margin-top: -170px;
    z-index: 0;
    pointer-events: none;
    opacity: .16;
    /* Neutral, not an accent. At 16% over the band an accent hue does not
       read as a tint of the accent -- it reads as a wash: the red came out
       dusty pink. The watermark is texture, so it takes the system's neutral
       on-dark tone and lets the band's own ground supply the colour. */
    color: var(--sage);
}

.sealmark svg {
    display: block;
    width: 100%;
    height: 100%;
    transform-origin: 50% 50%;
    animation: turn 150s linear infinite;
}

@keyframes turn {
    to {
        transform: rotate(360deg)
    }
}

@media(max-width:720px) {
    .sealmark {
        right: -140px;
        opacity: .1
    }
}

.band .wrap {
    position: relative;
    z-index: 1
}

.band h2 {
    color: #fff;
    margin: 20px 0 18px;
    max-width: 20ch
}

.band .lede {
    margin: 0;
    color: rgba(241, 244, 248, .82)
}

.band .cta-row:not(.e-con) {
    justify-content: flex-start
}

.band .cap {
    margin-top: 24px;
    color: rgba(241, 244, 248, .62)
}

/* ---------- footer ---------- */
.ft {
    background: var(--deep);
    color: var(--sage);
    padding: clamp(56px, 6vw, 80px) 0 44px
}

.fgrid:not(.e-con) {
    display: grid;
    grid-template-columns: 1.8fr 1fr 1fr 1fr;
    gap: 36px;
    margin-bottom: 52px
}

@media(max-width:860px) {
    .fgrid:not(.e-con) {
        grid-template-columns: 1fr 1fr
    }
}

.ft .logo {
    color: var(--bone)
}

.ft .logo-img {
    height: 72px
}

.ft-blurb {
    margin-top: 16px;
    font-size: .95rem;
    max-width: 34ch;
    color: var(--sage)
}

.ft h4 {
    font-family: var(--mono);
    font-size: .68rem;
    font-weight: 500;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--red-lift);
    margin-bottom: 18px
}

.ft ul {
    list-style: none
}

.ft li {
    margin-bottom: 11px
}

.ft a {
    font-size: .96rem;
    color: var(--sage);
    text-decoration: none;
    transition: color .18s var(--ease-out)
}

@media(hover:hover) and (pointer:fine) {
    .ft a:hover {
        color: var(--bone)
    }
}

.disclaimer {
    border-top: 1px solid var(--hairline-dark);
    padding-top: 28px;
    font-size: .86rem;
    line-height: 1.65;
    color: var(--sage);
    max-width: none
}

/* ---------- mobile call bar ---------- */
.dock {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: 12px;
    z-index: 99;
    display: none;
    align-items: center;
    gap: 6px;
    padding: 6px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .7);
    -webkit-backdrop-filter: blur(22px) saturate(180%);
    backdrop-filter: blur(22px) saturate(180%);
    border: 1px solid rgba(255, 255, 255, .85);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .95), 0 12px 34px -12px rgba(9, 18, 28, .42);
}

.dock a.btn {
    flex: 1;
    padding: 0 10px;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 52px;
    border-radius: var(--r-pill);
    font-weight: 600;
    font-size: 1rem;
    letter-spacing: -.012em;
    text-decoration: none;
    white-space: nowrap;
    transition: transform .1s var(--ease-out);
}

.dock .d-call {
    color: var(--ink);
    background: transparent;
    border-color: transparent
}

.dock .d-go {
    background: var(--navy);
    color: #fff;
    box-shadow: var(--lift-sm)
}

.dock a.press {
    transform: scale(.97)
}

@media(max-width:1040px) {
    .dock {
        display: flex
    }

    body {
        padding-bottom: 82px
    }
}

@media(max-width:430px) {
    .hdr .btn {
        display: none
    }

    .hdr-inner {
        justify-content: flex-start
    }

    .dock {
        left: 8px;
        right: 8px;
        bottom: 8px
    }

    .dock a.btn {
        font-size: .9rem;
        padding: 0 6px;
        min-height: 50px
    }
}

@media(max-width:360px) {
    .dock a.btn {
        font-size: .84rem
    }
}

@media(prefers-reduced-motion:reduce) {
    .dock a.press {
        transform: none
    }
}

/* ---------- scroll reveal ---------- */
.rv {
    opacity: 0;
    transform: translateY(18px) scale(.985)
}

.rv.in {
    opacity: 1;
    transform: none;
    transition: opacity .56s var(--ease-out), transform .56s var(--ease-out)
}

/* Directional variants.
   
   These change only the resting transform. They ride the same .rv contract --
   the same one-shot IntersectionObserver in motion.js, the same .in class, the
   same 60/90ms batch cascade -- so there is no JS to add and nothing new that
   can leave content stranded at opacity 0.

   Direction is used where the content already has one. The can/can't panels
   are a pair being weighed against each other, so they close from opposite
   sides and arrive together: they reveal in the same observer batch, which is
   what makes that read as one gesture rather than two animations. The process
   steps enter from the side their rail is on.

   The travel is long enough to be read as travel -- up to 190px, from outside
   the content column rather than from a few pixels off it. Two things make
   that safe rather than a horizontal scrollbar: `body` carries
   `overflow-x: hidden`, and every `.sec` clips its own overflow for the dot
   field. So a panel starting at -190px is clipped by its section and appears
   to enter from the page edge, which is the point.

   It is viewport-scaled, because the offset has to stay smaller than the gap
   it crosses. On a narrow screen `.duo` collapses to one column and the pair
   stack; a fixed 190px there would throw each panel most of the way off a
   390px screen and bring it back, which is a lurch, not an entrance.

   Opacity is over in .15s against the transform's .72s, and that ratio was
   measured rather than guessed. An element still fading while it travels
   reads as a fade, not a slide -- and --ease-out (cubic-bezier(.23,1,.32,1))
   front-loads distance hard, so a third of the journey is gone in the first
   fifth of the time. Pairing it with a .34s fade meant the panel was still at
   20% opacity with a third of its travel already spent: everything legible
   happened in the last 30px. Fading in over .2s puts the panel on screen at
   roughly -124px with 124px still to run, which is the part worth seeing.

   The easing is gentler than --ease-out for the same reason. --ease-out's
   tail spends 365ms crawling the last 15px, which reads as sluggish rather
   than smooth once the travel is long enough to watch.

   No variant belongs in the conditions rail. .rv is already excluded there --
   the rail measures itself against the viewport and a resting scale() makes
   every measurement short -- and a horizontal offset would fight the track's
   own transform on top of that. */
.rv-l {
    transform: translateX(calc(-1 * var(--rv-x))) scale(.99)
}

.rv-r {
    transform: translateX(var(--rv-x)) scale(.99)
}

/* Travel is a property so context can tune it, because one distance does not
   suit every object. A card is a bounded thing and can afford to come a long
   way; a column of body copy is not, and 190px of horizontal movement under a
   paragraph reads as the page being thrown around rather than assembled. */
.narrow.rv-l,
.narrow.rv-r,
.wrap.rv-l,
.wrap.rv-r {
    --rv-x: clamp(20px, 3.4vw, 56px)
}

/* Cards in a grid travel least of all, and the reason is the gap. A card is
   ~370px wide with ~25px between columns, so the full distance is half a card
   width and seven times the gap -- each card would enter from inside its
   neighbour's column and cross it on the way in, fully opaque, because the
   fade is over in .15s.

   This is why the paired .panel elements are excluded: they sit either side of
   a wide gutter and move apart from each other, so the long travel is exactly
   what makes them read as a pair closing. A grid is a set of peers, and its
   members should not appear to pass through one another. */
.card.rv-l,
.card.rv-r {
    --rv-x: clamp(16px, 2.4vw, 40px)
}

.rv-l.in,
.rv-r.in {
    transform: none
}

.rv-l.in,
.rv-r.in {
    transition: opacity .15s linear,
        transform .72s cubic-bezier(.3, .85, .35, 1)
}


/* A heading rises out of a mask instead of floating up with everything else,
   which reads as typeset rather than animated. Block-level on purpose: the
   usual way to do this is to split the heading into per-line spans, and that
   would take the heading out of the client's hands in the editor.

   The wipe is a mask, NOT clip-path. A fully clipped element reports an empty
   intersection rect, so the IntersectionObserver in motion.js never sees the
   heading it is waiting on, never adds .in, and the h1 stays invisible
   forever. A mask is paint-only and leaves the geometry alone.

   The masked heading gives up `text-box: trim-both`. A mask paints only
   inside the element's box, and the trim ends that box at the baseline, so a
   masked heading lost its descenders -- `mask-clip: no-clip` does not lift
   it. Untrimming this one heading puts the descender space back inside the
   box; the space it adds is absorbed by the container's flex gap. */
.rv-type h1,
.rv-type h2,
.rv-type h3 {
    text-box: normal
}

.rv-type {
    -webkit-mask: linear-gradient(#000 0 0) 0 0 / 100% 0% no-repeat;
    mask: linear-gradient(#000 0 0) 0 0 / 100% 0% no-repeat;
    transform: translateY(.34em);
    opacity: .001;
}

.rv-type.in,
.rv.in .rv-type {
    -webkit-mask-size: 100% 150%;
    mask-size: 100% 150%;
    transform: none;
    opacity: 1;
    transition: -webkit-mask-size .82s var(--ease-out),
        mask-size .82s var(--ease-out),
        transform .82s var(--spring),
        opacity .18s linear;
}

/* ---------- scroll-linked, without the scroll handler ----------

   The process rail is a progress indicator, which is exactly what a scroll
   timeline is for: the browser scrubs it on the compositor and it stays
   correct when the page is resized, zoomed, or scrolled backwards.

   The reveal above deliberately stays on motion.js. A scroll timeline is
   always scrubbed, so a .rv driven by one would re-hide its own text on the
   way back up; one-shot is the right behaviour for body copy.

   Where this is supported, motion.js stops writing rail.style.transform --
   it still toggles .step.hit, which is a class and has no timeline
   equivalent. Where it is not (Firefox stable, mid-2026), nothing here
   matches and the handler keeps doing the whole job. */
@supports (animation-timeline: view()) {
    .rail-wrap {
        view-timeline-name: --rail;
        view-timeline-axis: block;
    }

    .rail-fill {
        animation: rail-fill linear both;
        animation-timeline: --rail;
        animation-range: entry 100% exit 0%;
    }

    @keyframes rail-fill {
        from {
            transform: scaleY(0)
        }

        to {
            transform: scaleY(1)
        }
    }
}


/* ============================================================
   ELEMENTOR COMPATIBILITY LAYER

   Everything above is the design-system vocabulary. This block is what
   lets that vocabulary be *typed into* Elementor — every class below is
   applied by putting its name in an element's "CSS Classes" field, and
   nothing here requires touching a template.

   The one rule that governs this layer: Elementor drives container
   geometry through custom properties (--padding-top, --content-width,
   --row-gap …) which it reads back in its own low-specificity .e-con
   rules. Setting those properties, rather than setting padding and
   max-width directly, means the design system cooperates with
   Elementor's cascade instead of racing it. No !important is needed,
   and — the point of the whole rebuild — a client who nudges padding
   from the editor still wins, because Elementor writes their value on a
   per-element selector that outranks everything here.
   ============================================================ */

/* ---------- sections and measure on containers ---------- */
.e-con.sec {
    --padding-top: var(--pad);
    --padding-bottom: var(--pad);
    --padding-left: var(--gutter);
    --padding-right: var(--gutter);
}

.e-con.wrap {
    --content-width: 1160px
}

.e-con.narrow {
    --content-width: 820px
}

/* ---------- padded surfaces on containers ---------- */
.e-con.panel {
    --padding-top: clamp(30px, 3.4vw, 42px);
    --padding-bottom: clamp(30px, 3.4vw, 42px);
    --padding-left: clamp(30px, 3.4vw, 42px);
    --padding-right: clamp(30px, 3.4vw, 42px);
}

.e-con.card {
    --padding-top: 30px;
    --padding-bottom: 32px;
    --padding-left: 28px;
    --padding-right: 28px;
}

.e-con.tile {
    --padding-top: 20px;
    --padding-bottom: 20px;
    --padding-left: 18px;
    --padding-right: 18px;
}

.e-con.blocked {
    --padding-top: clamp(26px, 3vw, 36px);
    --padding-bottom: clamp(26px, 3vw, 36px);
    --padding-left: clamp(26px, 3vw, 36px);
    --padding-right: clamp(26px, 3vw, 36px);
}

/*
 * A .glass or .card container paints a background; Elementor's default
 * `overflow: visible` would let the sheen pseudo-element escape the
 * rounded corner. .glass already clips itself, so this only covers the
 * surfaces that do not.
 */
.e-con.card,
.e-con.panel,
.e-con.tile {
    --overflow: hidden
}

/* ---------- 404 ---------- */
/*
 * The parent theme's 404 is one sentence, so the footer ends up directly under
 * the header on a tall screen -- which reads as a broken page rather than a
 * missing one. The min-height holds the fold open; the rest gives a reader
 * somewhere to go.
 */
.sec-404 {
    display: flex;
    align-items: center;
    min-height: max(560px, calc(100vh - 320px));
}

.sec-404 h1 {
    margin: 16px 0 20px
}

.find {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 32px;
    max-width: 30rem;
}

.find input {
    flex: 1 1 14rem;
    min-height: 54px;
    padding: 0 20px;
    border-radius: var(--r-pill);
    border: 1px solid var(--hairline);
    background: var(--surface);
    font-family: inherit;
    font-size: 1rem;
    color: var(--ink);
}

.find input::placeholder {
    color: var(--ink-3)
}

.find-more {
    margin-top: clamp(40px, 5vw, 64px);
    padding-top: 28px;
    border-top: 1px solid var(--hairline);
}

.find-more h2 {
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-bottom: 18px;
}

.find-more ul {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 4px 24px;
    list-style: none;
}

@media(max-width:620px) {
    .find-more ul {
        grid-template-columns: 1fr
    }
}

.find-more a {
    display: block;
    padding: 9px 0;
    font-size: 1rem;
    color: var(--ink-2);
    text-decoration: none;
    border-bottom: 1px solid var(--hairline);
    transition: color .18s var(--ease-out);
}

@media(hover:hover) and (pointer:fine) {
    .find-more a:hover {
        color: var(--navy)
    }
}

/* ---------- long-form documents ---------- */
/*
 * The type scale above is built for marketing sections, where an h2 is one
 * statement carrying a whole band. A privacy policy has nineteen of them, and
 * at 3.1rem the numbering reads as nineteen separate pages rather than one
 * document. .doc tightens the scale and lets the headings sit in the reading
 * column with the prose.
 */
.doc h2 {
    font-size: clamp(1.35rem, 2vw, 1.6rem);
    line-height: 1.24;
    letter-spacing: -.02em;
    margin-top: .8em;
}

.doc h3 {
    font-size: 1.08rem;
    margin-top: .6em;
}

.doc :is(p, li) {
    max-width: 72ch
}

/*
 * A policy is dense, so its blockers have to stay findable while the reader
 * scrolls past them. They keep the dashed treatment but lose the emphasis a
 * standalone .blocked panel carries on a marketing page.
 */
.doc .blocked {
    border-width: 1px
}

/* ---------- section heads and the centred band CTA on containers ---------- */
.e-con.sec-head {
    --width: 100%;
    max-width: none;
    margin-bottom: clamp(44px, 5vw, 68px);
}

.band .e-con.cta-row {
    --justify-content: flex-start
}

/* ---------- process steps and condition tiles on containers ---------- */
/*
 * Both were hand-written markup with presentational children -- a <span
 * class="dot">, a <b> and an <em>. Rebuilt as containers so the copy inside is
 * editable, they need those pieces back: the dot becomes a pseudo-element, and
 * the two lines of a tile take classes instead of tag names.
 *
 * motion.js is untouched by this. It toggles .hit on .step and reads .tile from
 * the grid, both of which are still classes on the container.
 */
.e-con.step::before {
    content: "";
    position: absolute;
    left: calc(-14px - 6px);
    top: 6px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--deep);
    border: 2px solid var(--hairline-dark);
    transition: border-color .4s var(--ease-out), background-color .4s var(--ease-out);
}

.e-con.step {
    --position: relative
}

.tile-name {
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -.014em;
    line-height: 1.25;
    color: var(--bone);
}

.tile-note {
    margin-top: auto;
    /* clears the hover chevron in the bottom-right corner */
    padding-right: 20px;
    font-family: var(--mono);
    font-size: .66rem;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--sage);
}

.e-con.tile {
    --justify-content: flex-start;
    text-decoration: none;
}

/* ---------- clearing the fixed header ---------- */
/*
 * .hdr is fixed, so it covers whatever the page starts with. page-home.php
 * solved this inside .hero's own padding; every other page needs the offset
 * from the outside.
 *
 * On an Elementor page the offset is added to the first container's padding
 * rather than to the wrapper, so the section's background still runs up behind
 * the glass -- which is the whole point of a translucent header. A first
 * section that is a .hero is left alone: it already carries the allowance.
 */
#main {
    padding-top: var(--hdr-clear)
}

body.elementor-page #main {
    padding-top: 0
}

body.elementor-page #main>.elementor>.e-con:first-child:not(.hero) {
    --padding-top: calc(var(--pad) + var(--hdr-clear) - 24px)
}

/* ---------- rows ---------- */
/*
 * A .cta-row container lays its buttons out side by side and wraps them on a
 * narrow screen. Elementor drives container layout through --flex-direction
 * and --flex-wrap, so those are what get set; writing `display:flex` here
 * would take the decision away from the editor's own layout controls.
 */
.e-con.cta-row {
    --flex-direction: row;
    --flex-wrap: wrap;
    --align-items: center;
    --justify-content: flex-start;
    --width: auto;
}

.e-con.cta-row>.e-con-inner {
    flex-wrap: var(--flex-wrap)
}

/* ---------- headings ---------- */
/*
 * Elementor binds every heading's colour to the kit's primary global --
 * `.elementor-widget-heading .elementor-heading-title{color:var(--e-global-color-primary)}`
 * -- which scripts/configure-kit.php sets to --ink. That is right on a light
 * surface and wrong on a dark one, and it outranks the .sec-dark rules above,
 * so the dark case is restated here at matching weight.
 */
:is(.sec-dark, .on-dark) .elementor-widget-heading .elementor-heading-title {
    color: var(--bone)
}

/* ---------- buttons ---------- */
/*
 * Core's button widget renders <a class="elementor-button">, and offers
 * no field for putting a class on that anchor — the CSS Classes field
 * lands on the widget wrapper instead. So the anchor takes the .btn
 * shape unconditionally, and the wrapper class selects the variant.
 * Typing `btn-primary` into CSS Classes is therefore all a client does.
 */
.elementor-button {
    border-radius: var(--r-pill)
}

/*
 * The variant classes were written for the anchor, but the CSS Classes field
 * puts them on the widget wrapper — so .btn-primary painted the wrapper too,
 * and every Elementor button sat on a square, shadowed slab of its own
 * colour. The wrapper is layout only; the anchor below carries the surface.
 */
.elementor-widget-button.btn-primary,
.elementor-widget-button.btn-glass,
.elementor-widget-button.btn-glass-dark,
.elementor-widget-button.btn-white {
    background: none;
    border: 0;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.elementor-widget-button .elementor-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    min-height: 54px;
    padding: 0 30px;
    border-radius: var(--r-pill);
    font-family: inherit;
    font-size: 1.02rem;
    font-weight: 600;
    letter-spacing: -.012em;
    text-decoration: none;
    border: 1px solid transparent;
    background: var(--navy);
    color: #fff;
    box-shadow: var(--lift-sm);
    cursor: pointer;
    white-space: nowrap;
    transition: transform .1s var(--ease-out), background-color .22s var(--ease-out),
        border-color .22s var(--ease-out), box-shadow .22s var(--ease-out);
    will-change: transform;
}

.elementor-widget-button.btn-glass .elementor-button {
    background: rgba(255, 255, 255, .55);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    backdrop-filter: blur(20px) saturate(180%);
    border-color: rgba(255, 255, 255, .8);
    color: var(--ink);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .95), var(--lift-sm);
}

.elementor-widget-button.btn-glass-dark .elementor-button {
    background: rgba(241, 244, 248, .09);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    backdrop-filter: blur(20px) saturate(160%);
    border-color: rgba(241, 244, 248, .2);
    color: var(--bone);
    box-shadow: none;
}

.elementor-widget-button.btn-white .elementor-button {
    background: #fff;
    color: var(--navy);
    box-shadow: var(--lift-sm);
}

@media(hover:hover) and (pointer:fine) {
    .elementor-widget-button .elementor-button:hover {
        background: var(--navy-lift);
        box-shadow: var(--lift-md)
    }

    .elementor-widget-button.btn-glass .elementor-button:hover {
        background: rgba(255, 255, 255, .78)
    }

    .elementor-widget-button.btn-glass-dark .elementor-button:hover {
        background: rgba(241, 244, 248, .15)
    }

    .elementor-widget-button.btn-white .elementor-button:hover {
        background: #fff;
        box-shadow: var(--lift-md)
    }
}

.elementor-button.press {
    transform: scale(.97)
}

/* ---------- prose ---------- */
/*
 * The text editor is where the client will actually type. Its output is
 * plain <p>/<ul>/<ol>/<a>/<table>, so the readable defaults live here
 * rather than behind a class nobody will remember to add.
 */
.elementor-widget-text-editor {
    color: var(--ink-2)
}

.elementor-widget-text-editor p+p,
.elementor-widget-text-editor p+ul,
.elementor-widget-text-editor p+ol,
.elementor-widget-text-editor ul+p,
.elementor-widget-text-editor ol+p {
    margin-top: 1.1em
}

.elementor-widget-text-editor :is(ul, ol) {
    padding-left: 1.35em;
    max-width: 64ch
}

.elementor-widget-text-editor li {
    margin-top: .5em
}

.elementor-widget-text-editor li::marker {
    color: var(--red-graphic)
}

.elementor-widget-text-editor strong {
    color: var(--ink);
    font-weight: 600
}

.elementor-widget-text-editor a {
    color: var(--navy);
    text-decoration: underline;
    text-underline-offset: .18em;
    text-decoration-thickness: 1px;
    text-decoration-color: rgba(31, 71, 136, .4);
    transition: text-decoration-color .18s var(--ease-out);
}

@media(hover:hover) and (pointer:fine) {
    .elementor-widget-text-editor a:hover {
        text-decoration-color: currentColor
    }
}

:is(.sec-dark, .on-dark) .elementor-widget-text-editor {
    color: var(--sage)
}

:is(.sec-dark, .on-dark) .elementor-widget-text-editor strong {
    color: var(--bone)
}

:is(.sec-dark, .on-dark) .elementor-widget-text-editor a {
    color: var(--red-lift);
    text-decoration-color: rgba(224, 85, 99, .45)
}

/* ---------- tables ---------- */
/*
 * Rating criteria are tabular data and ship as a real <table> — never a
 * screenshot — so they stay selectable, translatable, and readable to a
 * screen reader. .table-wrap is the horizontal scroller that keeps a
 * five-column rating table from forcing the page sideways at 320px.
 */
.table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--hairline);
    border-radius: var(--r-sm);
}

.table-wrap table,
.elementor-widget-text-editor table {
    width: 100%;
    border-collapse: collapse;
    font-size: .97rem;
    line-height: 1.5;
    text-align: left;
}

.table-wrap :is(th, td),
.elementor-widget-text-editor :is(th, td) {
    padding: 14px 18px;
    border-bottom: 1px solid var(--hairline);
    vertical-align: top;
}

.table-wrap th,
.elementor-widget-text-editor th {
    color: var(--ink);
    font-weight: 600;
    letter-spacing: -.008em;
}

/*
 * Only the column headers get the tint and the nowrap. A <th scope="row">
 * carries a full criterion -- "At shoulder level, flexion and/or abduction
 * limited to 90 degrees" -- and holding that on one line is what pushes a
 * rating table off a 390px screen.
 */
.table-wrap thead th,
.elementor-widget-text-editor thead th {
    background: var(--mist);
    white-space: nowrap;
}

.table-wrap tr:last-child :is(th, td),
.elementor-widget-text-editor tr:last-child :is(th, td) {
    border-bottom: 0
}

.table-wrap caption,
.elementor-widget-text-editor caption {
    padding: 14px 18px 12px;
    color: var(--ink-3);
    font-size: .94rem;
    text-align: left;
}

/* ---------- FAQ accordion ---------- */
/*
 * Elementor's nested accordion renders <details>/<summary>, the same
 * elements page-home.php hand-wrote, so the .faq rules above already
 * match it. What follows only reconciles the two: Elementor's own
 * border and padding are zeroed out so those rules stay in charge, and
 * its icon slot is dressed to look like the hand-written .ic.
 *
 * Questions therefore live in the widget's repeater and answers in real
 * containers — both editable in the builder. Nothing is trapped in an
 * HTML widget, and the widget's own FAQ-schema switch emits the
 * FAQPage JSON-LD.
 */
.elementor-widget-n-accordion.faq {
    --n-accordion-border-width: 0;
    --n-accordion-border-radius: 0;
    --n-accordion-padding: 26px 6px 26px 0;
    --n-accordion-item-title-space-between: 0px;
    --n-accordion-item-title-distance-from-content: 0px;
    --n-accordion-title-justify-content: space-between;
    --n-accordion-title-normal-color: var(--ink);
    --n-accordion-title-hover-color: var(--ink);
    --n-accordion-title-active-color: var(--ink);
    --n-accordion-icon-normal-color: var(--ink);
    --n-accordion-icon-hover-color: var(--ink);
    --n-accordion-icon-active-color: var(--ink);
    --n-accordion-icon-size: 15px;
    --n-accordion-icon-gap: 20px;
}

.faq .e-n-accordion-item-title-text {
    font-size: 1.18rem;
    font-weight: 600;
    letter-spacing: -.018em;
    line-height: 1.32;
}

/* The widget sizes this box from the glyph inside it, which made a 13x30
   oval rather than the circle the hand-written accordion has. min-width and
   min-height hold the box at 30px whatever the icon's aspect ratio is, and
   the inner <span> Elementor wraps each state in has to be told to centre
   too -- it is the actual flex parent of the svg. */
.faq .e-n-accordion-item-title-icon {
    flex: 0 0 30px;
    box-sizing: border-box;
    width: 30px;
    height: 30px;
    min-width: 30px;
    min-height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(9, 18, 28, .055);
}

.faq .e-n-accordion-item-title-icon>span {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}

.faq .e-n-accordion-item-title-icon svg {
    width: 11px;
    height: 11px;
}

.faq .e-n-accordion-item>.e-con {
    --padding-top: 0px;
    --padding-right: 12%;
    --padding-bottom: 30px;
    --padding-left: 0px;
    font-size: 1.04rem;
    line-height: 1.6;
    color: var(--ink-2);
}

.faq .e-n-accordion-item[open]>.e-con {
    animation: ansIn .15s var(--ease-out) both
}

@media(max-width:620px) {
    .faq .e-n-accordion-item>.e-con {
        --padding-right: 0px
    }
}

:is(.sec-dark, .on-dark) .elementor-widget-n-accordion.faq {
    --n-accordion-title-normal-color: var(--bone);
    --n-accordion-title-hover-color: var(--bone);
    --n-accordion-title-active-color: var(--bone);
    --n-accordion-icon-normal-color: var(--bone);
    --n-accordion-icon-hover-color: var(--bone);
    --n-accordion-icon-active-color: var(--bone);
}

:is(.sec-dark, .on-dark) .faq .e-n-accordion-item-title-icon {
    background: rgba(241, 244, 248, .08)
}

:is(.sec-dark, .on-dark) .faq .e-n-accordion-item>.e-con {
    color: var(--sage)
}
