/* ==========================================================================
   POLY Cleaning — design system foundation
   Tokens, typography, buttons, section shell and motion primitives shared by
   every dc-poly-* widget. Brand colours are sampled from the POLY logo.
   ========================================================================== */

:root {
    /* Brand */
    --poly-brand: #39439B;
    --poly-brand-700: #2C3480;
    --poly-brand-900: #1B2258;
    --poly-accent: #2F86C9;
    --poly-accent-400: #559CD4;
    --poly-accent-200: #7BBCE8;

    /* Ink & neutrals */
    --poly-ink: #0B1130;
    --poly-ink-800: #141B42;
    --poly-title: #10173A;
    --poly-body: #4E5878;
    --poly-muted: #656F8B;
    --poly-line: #E2E7F1;
    --poly-line-strong: #CBD3E4;
    --poly-mist: #F4F7FC;
    --poly-mist-deep: #EAF0F9;
    --poly-white: #FFFFFF;

    /* Typography */
    --poly-font-display: "SUSE", "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
    --poly-font-body: "DM Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

    /* Section headline — the hero's setting, shared by every widget title so the
       page reads as one voice. Retune the scale here and it lands everywhere. */
    --poly-title-size: clamp(2.35rem, 4.15vw, 3.75rem);
    --poly-title-weight: 600;
    --poly-title-leading: .99;
    --poly-title-tracking: -.035em;

    /* Layout */
    --poly-max: 1290px;
    --poly-gutter: clamp(20px, 5.2vw, 72px);
    --poly-section: clamp(72px, 8.6vw, 136px);
    --poly-radius: 4px;
    --poly-radius-lg: 10px;

    /* Eyebrow mark — hairline rule + four point shine, overridable per site.
       Split over two layers so the rule can draw in while the shine twinkles;
       both share the same 34x12 viewBox so they stay in register. */
    --poly-eyebrow-rule: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 12'%3E%3Crect x='0' y='5.5' width='19.5' height='1' rx='.5' fill='%23000'/%3E%3C/svg%3E");
    --poly-eyebrow-shine: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 12'%3E%3Cpath d='M27.6 1.4c.3 2.5 2.1 4.3 4.6 4.6-2.5.3-4.3 2.1-4.6 4.6-.3-2.5-2.1-4.3-4.6-4.6 2.5-.3 4.3-2.1 4.6-4.6Z' fill='%23000'/%3E%3C/svg%3E");
    /* The same shine, cropped to its own bounds for chip and badge eyebrows. */
    --poly-eyebrow-spark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='23 1.4 9.2 9.2'%3E%3Cpath d='M27.6 1.4c.3 2.5 2.1 4.3 4.6 4.6-2.5.3-4.3 2.1-4.6 4.6-.3-2.5-2.1-4.3-4.6-4.6 2.5-.3 4.3-2.1 4.6-4.6Z' fill='%23000'/%3E%3C/svg%3E");

    /* One shared cycle for the mark's idle twinkle, so the rule and the shine
       always breathe on the same clock. */
    --poly-eyebrow-idle: 6.4s;
    /* Travel of the light that runs the rule: two mark widths, so the tiled
       gradient hands off to its next crest exactly where it started. */
    --poly-eyebrow-trace-span: 68px;

    /* Motion */
    --poly-ease: cubic-bezier(.22, .61, .36, 1);
    --poly-ease-out: cubic-bezier(.16, 1, .3, 1);
    /* Leaves fast, lands soft — the light's own curve. */
    --poly-ease-trace: cubic-bezier(.7, 0, .2, 1);
}

/* --------------------------------------------------------------------------
   Widget shell — every POLY widget is edge to edge, spacing lives inside.
   -------------------------------------------------------------------------- */

.poly {
    width: 100%;
    max-width: 100%;
    margin: 0;
    padding: 0;
    font-family: var(--poly-font-body);
    color: var(--poly-body);
    font-size: 1rem;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

.poly *,
.poly *::before,
.poly *::after {
    box-sizing: border-box;
}

.poly-section {
    position: relative;
    padding-block: var(--poly-section);
    background: var(--poly-white);
    overflow: clip;
}

.poly-section--mist { background: var(--poly-mist); }

.poly-section--ink {
    background: var(--poly-ink);
    color: rgba(255, 255, 255, .72);
}

.poly-shell {
    width: 100%;
    max-width: var(--poly-max);
    margin-inline: auto;
    padding-inline: var(--poly-gutter);
}

.poly-shell--wide { max-width: 1560px; }

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */

/* Element resets are wrapped in :where() so they carry zero specificity and any
   component class below can override them without !important. */
:where(.poly) :where(h1, h2, h3, h4, h5, h6) {
    margin: 0;
    font-family: var(--poly-font-display);
    font-weight: 600;
    color: var(--poly-title);
    letter-spacing: -.022em;
    line-height: 1.08;
    text-wrap: balance;
}

:where(.poly) :where(p) { margin: 0; font-family: var(--poly-font-body); }
:where(.poly) :where(ul, ol) { margin: 0; padding: 0; list-style: none; }
:where(.poly) :where(img) { display: block; max-width: 100%; height: auto; }
:where(.poly) :where(figure, blockquote, fieldset) { margin: 0; padding: 0; border: 0; }

.poly-section--ink :where(h1, h2, h3, h4) { color: var(--poly-white); }

.poly-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .6em;
    margin: 0 0 1.1rem;
    font-family: var(--poly-font-body);
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .17em;
    text-transform: uppercase;
    color: var(--poly-brand);
}

/* Chip eyebrow — the same voice and the same mark, set inside a pill. Widgets
   supply only the pill's surface through these tokens, so every chip on the
   page inherits one typography and one mark instead of re-inventing them. */
.poly-eyebrow--chip {
    gap: .55em;
    padding: .5em 1.15em .5em 1em;
    border: 1px solid var(--poly-eyebrow-chip-edge, transparent);
    border-radius: 999px;
    background: var(--poly-eyebrow-chip-surface, var(--poly-mist-deep));
    box-shadow: var(--poly-eyebrow-chip-shadow, none);
}

.poly-eyebrow__dot {
    /* Fallback: the original hairline rule for browsers without mask support. */
    width: 24px;
    height: 1px;
    background: currentColor;
    opacity: .55;
    flex: none;
}

/* Brand mark: a hairline rule that resolves into a four point shine — the
   "professionally maintained" signal. Drawn as two masked layers so it always
   inherits the eyebrow colour (brand on light, accent-200 on ink sections) and
   so each half can carry its own motion. */
@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    .poly-eyebrow__dot {
        position: relative;
        width: 34px;
        height: 12px;
        background: none;
        opacity: 1;
    }

    .poly-eyebrow__dot::before,
    .poly-eyebrow__dot::after {
        content: "";
        position: absolute;
        inset: 0;
        background: currentColor;
        -webkit-mask-repeat: no-repeat;
        mask-repeat: no-repeat;
        -webkit-mask-position: center;
        mask-position: center;
        -webkit-mask-size: contain;
        mask-size: contain;
    }

    /* The rule grows out of the text side. */
    .poly-eyebrow__dot::before {
        --poly-eyebrow-rule-alpha: .45;
        -webkit-mask-image: var(--poly-eyebrow-rule);
        mask-image: var(--poly-eyebrow-rule);
        opacity: var(--poly-eyebrow-rule-alpha);
        transform-origin: left center;
        animation: poly-eyebrow-rule-idle var(--poly-eyebrow-idle) var(--poly-ease-trace) infinite;
    }

    /* The shine sits at 81% of the viewBox, so it pivots around its own centre. */
    .poly-eyebrow__dot::after {
        -webkit-mask-image: var(--poly-eyebrow-shine);
        mask-image: var(--poly-eyebrow-shine);
        opacity: .95;
        transform-origin: 81.2% center;
        animation: poly-eyebrow-shine-idle var(--poly-eyebrow-idle) var(--poly-ease-trace) infinite;
    }

    /* A light runs the rule towards the shine. It is painted as a tiled gradient
       behind the rule mask rather than as a second element, so the mark stays one
       span and keeps inheriting the eyebrow colour. At rest the crest sits on the
       text side and the line fades towards the shine, which is the mark's resting
       look; the idle loop then carries that crest across and lands it on the
       shine. Browsers without color-mix keep the flat hairline. */
    @supports (background: color-mix(in srgb, currentColor 50%, transparent)) {
        .poly-eyebrow__dot::before {
            --poly-eyebrow-rule-alpha: .78;
            background-color: transparent;
            background-image: linear-gradient(90deg,
                color-mix(in srgb, currentColor 100%, transparent) 0,
                color-mix(in srgb, currentColor 32%, transparent) 44%,
                color-mix(in srgb, currentColor 32%, transparent) 58%,
                color-mix(in srgb, currentColor 100%, transparent) 100%);
            background-repeat: repeat-x;
            background-size: var(--poly-eyebrow-trace-span) 100%;
        }
    }
}

/* Motion — the mark waits inside any revealing block and resolves with it, so
   every widget gets the same entrance without extra markup. Without JS (no
   .poly-js) the mark simply renders at rest. */
@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    .poly-js [data-poly-reveal] .poly-eyebrow__dot::before {
        opacity: 0;
        transform: scaleX(.12);
        animation: none;
    }

    .poly-js [data-poly-reveal] .poly-eyebrow__dot::after {
        opacity: 0;
        transform: scale(.2) rotate(-60deg);
        animation: none;
    }

    .poly-js [data-poly-reveal].is-revealed .poly-eyebrow__dot::before {
        animation: poly-eyebrow-rule .7s var(--poly-ease-out) both,
                   poly-eyebrow-rule-idle var(--poly-eyebrow-idle) 1.3s var(--poly-ease-trace) infinite;
    }

    .poly-js [data-poly-reveal].is-revealed .poly-eyebrow__dot::after {
        animation: poly-eyebrow-shine .9s .22s var(--poly-ease-out) both,
                   poly-eyebrow-shine-idle var(--poly-eyebrow-idle) 1.3s var(--poly-ease-trace) infinite;
    }
}

/* Chip and badge eyebrows sit inside a pill, where the hairline rule has no
   room to breathe — they carry the shine on its own. */
.poly-eyebrow__dot--shine {
    /* Fallback: the round dot these pills used before the mark landed. */
    width: 7px;
    height: 7px;
    border-radius: 50%;
}

@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    .poly-eyebrow__dot--shine {
        width: 12px;
        height: 12px;
        border-radius: 0;
    }

    .poly-eyebrow__dot--shine::before { display: none; }

    .poly-eyebrow__dot--shine::after {
        -webkit-mask-image: var(--poly-eyebrow-spark);
        mask-image: var(--poly-eyebrow-spark);
        transform-origin: center;
    }
}

@keyframes poly-eyebrow-rule {
    from { opacity: 0; transform: scaleX(.12); }
    to   { opacity: var(--poly-eyebrow-rule-alpha); transform: none; }
}

@keyframes poly-eyebrow-shine {
    0%   { opacity: 0; transform: scale(.2) rotate(-60deg); }
    55%  { opacity: 1; transform: scale(1.22) rotate(10deg); }
    100% { opacity: .95; transform: none; }
}

/* Idle — the mark rests for most of the cycle, then a light runs the rule and
   lands on the shine, which catches it and settles a quarter turn on. Both
   halves start and end on their resting values, which lets the loop pick up
   seamlessly where the entrance animation leaves off. */
@keyframes poly-eyebrow-rule-idle {
    0%, 54%   { background-position: 0 center; }
    76%, 100% { background-position: var(--poly-eyebrow-trace-span) center; }
}

/* A quarter turn is a rest position for a four point mark, so the shine keeps
   turning the same way every cycle instead of snapping back to zero. */
@keyframes poly-eyebrow-shine-idle {
    0%, 56%   { opacity: .95; transform: rotate(0deg) scale(1); }
    64%       { opacity: 1;   transform: rotate(26deg) scale(1.3); }
    74%       { opacity: .88; transform: rotate(68deg) scale(.97); }
    84%, 100% { opacity: .95; transform: rotate(90deg) scale(1); }
}

.poly-section--ink .poly-eyebrow { color: var(--poly-accent-200); }

.poly-head { max-width: 62ch; }
.poly-head--center { max-width: 64ch; margin-inline: auto; text-align: center; }
.poly-head--center .poly-eyebrow { justify-content: center; }

/* Every section headline is set like the hero title: the same display face,
   weight, tight leading and negative tracking. Widget stylesheets load after
   this file, so they only add what is theirs — colour, width, layout — and
   leave the typography alone. */
.poly-head__title,
.poly-hero__title,
.poly-intro__title,
.poly-services__title,
.poly-service-detail__title,
.poly-specialists__title,
.poly-usp__title,
.poly-process__title,
.poly-projects__title,
.poly-testimonials__title,
.poly-faq__title,
.poly-cta__title,
.poly-contact__title,
.poly-quote__title,
.poly-features__title,
.poly-gallery__title,
.poly-prose__title {
    font-family: var(--poly-font-display);
    font-size: var(--poly-title-size);
    font-weight: var(--poly-title-weight);
    line-height: var(--poly-title-leading);
    letter-spacing: var(--poly-title-tracking);
    text-wrap: balance;
}

/* A phone has no room for the vw step, so the whole set drops together. */
@media (max-width: 600px) {
    :root { --poly-title-size: clamp(2.2rem, 10.5vw, 3rem); }
}

.poly-head__intro {
    margin-top: 1.35rem;
    font-size: clamp(1rem, 1.25vw, 1.125rem);
    line-height: 1.7;
    color: var(--poly-body);
    max-width: 56ch;
}

.poly-head--center .poly-head__intro { margin-inline: auto; }
.poly-section--ink .poly-head__intro { color: rgba(255, 255, 255, .7); }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.poly-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .7em;
    padding: 1.05em 1.85em;
    border: 1px solid transparent;
    border-radius: var(--poly-radius);
    font-family: var(--poly-font-body);
    font-size: .9375rem;
    font-weight: 600;
    letter-spacing: .005em;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .3s var(--poly-ease), color .3s var(--poly-ease),
                border-color .3s var(--poly-ease), box-shadow .3s var(--poly-ease);
}

.poly-btn__icon {
    width: 17px;
    height: 17px;
    flex: none;
    transition: transform .35s var(--poly-ease-out);
}

.poly-btn:hover .poly-btn__icon { transform: translateX(4px); }

.poly-btn--primary {
    background: var(--poly-brand);
    color: var(--poly-white);
    box-shadow: 0 10px 26px -14px rgba(57, 67, 155, .85);
}

.poly-btn--primary:hover,
.poly-btn--primary:focus-visible {
    background: var(--poly-brand-700);
    box-shadow: 0 16px 34px -14px rgba(57, 67, 155, .95);
}

.poly-btn--ghost {
    background: transparent;
    border-color: var(--poly-line-strong);
    color: var(--poly-title);
}

.poly-btn--ghost:hover,
.poly-btn--ghost:focus-visible {
    border-color: var(--poly-brand);
    color: var(--poly-brand);
    background: rgba(57, 67, 155, .04);
}

.poly-btn--light {
    background: var(--poly-white);
    color: var(--poly-brand-900);
}

.poly-btn--light:hover,
.poly-btn--light:focus-visible { background: var(--poly-accent-200); color: var(--poly-brand-900); }

.poly-btn--outline-light {
    background: transparent;
    border-color: rgba(255, 255, 255, .3);
    color: var(--poly-white);
}

.poly-btn--outline-light:hover,
.poly-btn--outline-light:focus-visible {
    border-color: var(--poly-white);
    background: rgba(255, 255, 255, .08);
}

.poly-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .85rem;
    margin-top: 2.25rem;
}

/* Text link with a moving underline. */
.poly-link {
    display: inline-flex;
    align-items: center;
    gap: .5em;
    font-weight: 600;
    font-size: .9375rem;
    color: var(--poly-brand);
    text-decoration: none;
}

.poly-link .poly-icon {
    width: 16px;
    height: 16px;
    transition: transform .35s var(--poly-ease-out);
}

.poly-link:hover .poly-icon { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   Shared primitives
   -------------------------------------------------------------------------- */

.poly-icon { width: 24px; height: 24px; flex: none; }

.poly-check {
    display: grid;
    gap: .9rem;
}

.poly-check__item {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: start;
    gap: .85rem;
    font-size: 1rem;
    color: var(--poly-body);
}

.poly-check__mark {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    margin-top: .15em;
    border-radius: 50%;
    background: var(--poly-mist-deep);
    color: var(--poly-brand);
}

.poly-check__mark .poly-icon { width: 13px; height: 13px; stroke-width: 2.4; }

.poly-media {
    position: relative;
    overflow: hidden;
    background: var(--poly-mist-deep);
}

/* `.poly .` prefix outranks Elementor's `.elementor img { height: auto }`. */
.poly .poly-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Accessible focus ring, used everywhere. */
.poly a:focus-visible,
.poly button:focus-visible,
.poly input:focus-visible,
.poly textarea:focus-visible,
.poly select:focus-visible {
    outline: 2px solid var(--poly-accent);
    outline-offset: 3px;
    border-radius: 2px;
}

.poly-section--ink a:focus-visible,
.poly-section--ink button:focus-visible { outline-color: var(--poly-accent-200); }

.poly-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* --------------------------------------------------------------------------
   Motion — opt in via [data-poly-reveal], switched on by poly-motion.js
   -------------------------------------------------------------------------- */

.poly-js [data-poly-reveal] {
    opacity: 0;
    transform: translate3d(0, 22px, 0);
    transition: opacity .85s var(--poly-ease-out), transform .85s var(--poly-ease-out);
    transition-delay: calc(var(--poly-delay, 0) * 80ms);
    will-change: opacity, transform;
}

.poly-js [data-poly-reveal="fade"] { transform: none; }
.poly-js [data-poly-reveal="left"] { transform: translate3d(-26px, 0, 0); }
.poly-js [data-poly-reveal="right"] { transform: translate3d(26px, 0, 0); }

.poly-js [data-poly-reveal].is-revealed {
    opacity: 1;
    transform: none;
    will-change: auto;
}

/* Image reveal: the picture scales back to rest as it enters the viewport. */
.poly-js [data-poly-reveal="media"] { opacity: 1; transform: none; }

.poly-js [data-poly-reveal="media"] img {
    transform: scale(1.08);
    opacity: 0;
    transition: transform 1.25s var(--poly-ease-out), opacity .9s var(--poly-ease-out);
}

.poly-js [data-poly-reveal="media"].is-revealed img { transform: none; opacity: 1; }

/* Sideways reveals push past the viewport edge on narrow screens (and read as
   jitter on a phone), so they become plain lifts below the tablet breakpoint. */
@media (max-width: 760px) {
    .poly-js [data-poly-reveal="left"],
    .poly-js [data-poly-reveal="right"] {
        transform: translate3d(0, 18px, 0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .poly *,
    .poly *::before,
    .poly *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }

    .poly-js [data-poly-reveal],
    .poly-js [data-poly-reveal="media"] img {
        opacity: 1 !important;
        transform: none !important;
    }
}
