/* =================================================================
   Echoe — fluid responsive layer
   Loaded LAST, after style.css / upgrades.css / service-page.css /
   mobile-fixes.css, so equal-specificity rules here win.

   Idea: one continuous scale instead of a handful of fixed layouts.
   The root font-size is a single "dial" driven by the viewport, and
   because almost every size in the design system is expressed in rem,
   the whole UI (type, spacing, controls) grows and shrinks together.
   Widths are %, vw, min()/max()/clamp() — never a hard pixel layout.

   Covered: 320px phones · notched iPhones · Android · tablets ·
   laptops · desktops · QHD/4K and curved-LED TVs.
   ================================================================= */


/* -----------------------------------------------------------------
   1. THE DIAL — fluid root type scale
   16px stays flat up to ~1280px (phones/tablets/laptops read best
   there), then grows smoothly and stops at 24px so a 4K TV does not
   turn into a poster. rem units keep the browser's own font-size
   setting working, so accessibility zoom still applies.
   ----------------------------------------------------------------- */
html {
    font-size: clamp(1rem, 0.6rem + 0.5vw, 1.5rem);
}
/* style.css pins this to 16px, which would freeze all body copy */
body {
    font-size: 1rem;
}


/* -----------------------------------------------------------------
   2. FLUID SHELL — container, gutters, header height
   ----------------------------------------------------------------- */
:root {
    --container: 1200px;
    --header-h: 4.5rem;              /* 72px at 16px root, scales up on TV */
}

/* Big screens: stop stranding the content in a 1200px column.
   90vw keeps side breathing room; the cap keeps line lengths sane. */
@media (min-width: 1440px) {
    :root { --container: min(90vw, 1900px); }
}

.container,
.container-narrow {
    max-width: var(--container);
    width: 100%;
    margin-inline: auto;
}
.container-narrow { max-width: min(51rem, var(--container)); }

/* Notch / rounded-corner safe areas (iPhone, some Android, in-car & TV
   browsers with overscan). max() keeps the normal gutter when there is
   no inset to honour. */
@supports (padding: max(0px)) {
    .container,
    .container-narrow {
        padding-left:  max(1.25rem, env(safe-area-inset-left));
        padding-right: max(1.25rem, env(safe-area-inset-right));
    }
}


/* -----------------------------------------------------------------
   3. PIXEL LAYOUTS -> rem, so they scale with the dial
   These mirror style.css declarations; same specificity, later file.
   ----------------------------------------------------------------- */
/* text columns */
.hero-copy     { max-width: 40rem; }
.hero-sub      { max-width: 35rem; }
.section-sub   { max-width: 38.75rem; }
.section-title { max-width: 46rem; }
.section-head  { max-width: 47.5rem; }
.page-lead     { max-width: 45rem; }
.page-hero .container { max-width: min(57.5rem, var(--container)); }
.cta-inner p   { max-width: 34rem; }
.footer-about  { max-width: 22.5rem; }
.service-hero-copy .page-lead { max-width: 36rem; }
.service-body > p,
.service-body > ul { max-width: 45rem; }

/* media & imagery */
.hero-image  { max-height: 34rem; }
.brand-logo  { max-height: 2.75rem; }
.footer-logo { max-height: 3rem; }
.ceo-photo img,
.ceo-photo-placeholder { max-width: 24rem; }
.hero-mock   { min-height: 23.75rem; }
.orb-1 { width: 30rem;    height: 30rem;    top: -7.5rem;  right: -7.5rem; }
.orb-2 { width: 23.75rem; height: 23.75rem; bottom: -6.25rem; left: -5rem; }

/* controls & chrome */
.mobile-nav-inner   { max-width: 30rem; }
.mobile-nav-close   { width: 3rem; height: 3rem; }
.faq-icon           { width: 1.75rem; height: 1.75rem; }
.search-form        { max-width: 30rem; }
.primary-nav .menu .sub-menu { min-width: 13.75rem; }
.contact-form-card textarea  { min-height: 8rem; }
.inquiry-form textarea       { min-height: 7rem; }
.t-avatar,
.benefit-icon,
.process-icon { width: 2.75rem; height: 2.75rem; }
.service-card-body .service-icon { width: 2.375rem; height: 2.375rem; }

@media (min-width: 560px) {
    .hero-mock { min-height: 20rem; }
}

/* Floating action buttons: keep the deliberately smaller phone sizes from
   mobile-fixes.css, add safe-area insets everywhere, and let them scale
   with the dial only on desktop/TV. */
.wa-fab {
    bottom: max(1.25rem, env(safe-area-inset-bottom));
    right:  max(1.25rem, env(safe-area-inset-right));
}
.inquiry-cta {
    bottom: max(1.25rem, env(safe-area-inset-bottom));
    left:   max(1.25rem, env(safe-area-inset-left));
}
@media (max-width: 879px) {
    .wa-fab      { bottom: max(1rem, env(safe-area-inset-bottom)); right: max(1rem, env(safe-area-inset-right)); }
    .inquiry-cta { bottom: max(1rem, env(safe-area-inset-bottom)); left:  max(1rem, env(safe-area-inset-left)); }
}
@media (max-width: 600px) {
    .wa-fab      { bottom: max(.875rem, env(safe-area-inset-bottom)); right: max(.875rem, env(safe-area-inset-right)); }
    .inquiry-cta { bottom: max(.875rem, env(safe-area-inset-bottom)); left:  max(.875rem, env(safe-area-inset-left)); }
}
@media (min-width: 880px) {
    .wa-fab { width: 3.5rem; height: 3.5rem; }
}

@media (min-width: 880px) {
    /* were fixed 360px sidebars — now they grow with everything else */
    .ceo-grid     { grid-template-columns: 22.5rem 1fr; }
    .contact-grid { grid-template-columns: 22.5rem 1fr; }
    .faq-grid     { grid-template-columns: 22.5rem 1fr; }
}


/* -----------------------------------------------------------------
   4. NAVIGATION across device classes
   ----------------------------------------------------------------- */

/* Tablets (iPad portrait 768, most Android tablets) previously fell back
   to the phone hamburger even though there is room for the real menu.
   Give them the full nav from 760px, in a compact rhythm. */
@media (min-width: 760px) {
    .primary-nav  { display: block; }
    .menu-toggle  { display: none; }
    .header-cta   { display: inline-flex; }
    .primary-nav .menu > li > a { padding: .55rem .7rem; font-size: .95rem; }
    .header-inner { gap: 1rem; }
}

/* The phone number needs real estate — only bring it back once the row
   comfortably fits logo + 5 links + number + CTA. */
@media (min-width: 760px) and (max-width: 1023px) {
    .header-phone { display: none; }
}
@media (min-width: 1024px) {
    .header-phone { display: inline-flex; }
    .primary-nav .menu > li > a { padding: .6rem .9rem; font-size: 1rem; }
    .header-inner { gap: 1.5rem; }
}

/* Panel branding — the overlay covers the header, so repeat the logo
   inside it or the user loses their bearings. */
.mobile-nav-brand {
    display: inline-flex;
    margin-bottom: 1.5rem;
}
.mobile-nav-brand .brand-logo { max-height: 2.5rem; }

/* Phone menu overlay: never let a short landscape screen trap content,
   and keep the last item clear of the home indicator. */
.mobile-nav { overscroll-behavior: contain; }
@supports (padding: max(0px)) {
    .mobile-nav-inner { padding-bottom: max(3rem, env(safe-area-inset-bottom)); }
}
@media (max-width: 759px) and (orientation: landscape) {
    .mobile-nav-inner { padding-top: 3.5rem; padding-bottom: 2rem; }
    .mobile-menu a    { padding: .7rem .25rem; min-height: 44px; }
    .mobile-cta       { margin-top: 1rem; }
}


/* -----------------------------------------------------------------
   5. TOUCH & REMOTE — tap targets and a visible focus ring
   TV browsers and keyboard users navigate by focus, so every control
   needs a ring. :focus-visible keeps it off for plain mouse clicks.
   ----------------------------------------------------------------- */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 3px;
    border-radius: 6px;
}

/* Coarse pointers (phones, tablets, TV remotes with cursors) get the
   44px minimum target regardless of viewport width. */
@media (pointer: coarse) {
    .menu-toggle,
    .mobile-nav-close,
    .btn { min-height: 44px; }
    .mobile-menu a,
    .footer-list a,
    .contact-list a { min-height: 44px; display: flex; align-items: center; }
}

/* Fine-pointer hover effects shouldn't fire on touch devices */
@media (hover: none) {
    .wa-fab:hover { transform: none; }
}


/* -----------------------------------------------------------------
   6. SMALL PHONES (320–360px) — Galaxy A/S base widths, iPhone SE
   ----------------------------------------------------------------- */
@media (max-width: 380px) {
    .container,
    .container-narrow { padding-inline: 1rem; }
    /* mobile-fixes.css gives these flex:1 so they share one row; below
       380px that leaves ~150px per button, so stack them instead.
       flex-basis must be reset too, otherwise width is ignored. */
    .hero-ctas        { flex-direction: column; align-items: stretch; gap: .6rem; }
    .hero-ctas .btn   { flex: 0 0 auto; width: 100%; justify-content: center; }
    .eyebrow          { font-size: .7rem; letter-spacing: .08em; }
}


/* -----------------------------------------------------------------
   7. LARGE DISPLAYS — QHD, 4K, curved LED TVs
   The dial already scales type and spacing; these keep proportion.
   ----------------------------------------------------------------- */
@media (min-width: 1600px) {
    .hero-image  { max-height: 40rem; }
    .section     { padding-block: clamp(3rem, 5vw, 7rem); }
    .stats-row   { padding: 2.5rem; }
}

/* Ultra-wide / very tall TV panels: cap how wide a single text column
   can get so headlines stay readable across the room. */
@media (min-width: 2200px) {
    .hero-copy   { max-width: 45rem; }
    .section-sub { max-width: 42rem; }
}

/* TVs are viewed from a distance and often render at 1080p CSS pixels
   regardless of panel size — nudge the floor up when the pointer is
   coarse/absent and the screen is wide. */
@media (min-width: 1600px) and (pointer: coarse),
       (min-width: 1600px) and (pointer: none) {
    html { font-size: clamp(1.15rem, 0.6rem + 0.6vw, 1.65rem); }
}


/* -----------------------------------------------------------------
   8. GUARDS — nothing may push the page sideways at any width

   Deliberately NOT using `overflow-x: clip` on html/body. It hides a
   sideways overflow instead of fixing it: the content is silently cut
   off and unreachable, and scrollWidth stops reporting the problem so
   it never shows up in testing. The decorative wide things already
   clip themselves (.hero, .marquee, .t-track all set overflow), so the
   root element is left honest — if something ever overflows, it shows.
   ----------------------------------------------------------------- */
html, body { max-width: 100%; }
img, svg, video, iframe, table { max-width: 100%; }
pre, code { overflow-x: auto; }

/* THE actual cause of sideways overflow on narrow phones: grid and flex
   items default to min-width:auto, so a card refuses to become narrower
   than its longest word ("Transparent", "Availability", "5,400+") and
   shoves the whole row past the screen edge. min-width:0 lets them wrap. */
.stats-row > *,      .counters-grid > *,  .about-pillars > *,
.team-grid > *,      .office-grid > *,    .post-grid > *,
.card-grid > *,      .card-grid-3 > *,    .card-grid-4 > *,
.value-props > *,    .office-gallery > *, .footer-grid > *,
.benefit-grid > *,   .tech-ind-grid > *,  .process-timeline > *,
.hero-grid-cols > *, .about-grid > *,     .ceo-grid > *,
.contact-grid > *,   .faq-grid > *,       .inquiry-grid > *,
.service-hero-grid > *, .cta-inner > *,   .form-row > *,
.header-inner > *,   .footer-bottom-inner > *,
.hero-ctas > *,      .cta-actions > *,    .service-kpis > * {
    min-width: 0;
}

/* The contact rows are flex (icon + text). Their text child also defaults
   to min-width:auto, so "Info@echoeassistance.com" and the street address
   held the whole footer column open and pushed the page 7px sideways
   between 880–1023px. `anywhere` (not `break-word`) is required: only
   `anywhere` also shrinks the element's min-content size. */
.contact-list li,
.contact-list li > *,
.footer-list li,
.footer-list li > *,
.info-card,
.info-card > * {
    min-width: 0;
}
.contact-list a,
.contact-list span,
.info-card a {
    overflow-wrap: anywhere;
}

/* Four footer columns need real room. Below 1024px the last column got
   ~210px, which is not enough for an address — use two columns instead. */
@media (min-width: 880px) and (max-width: 1023px) {
    .footer-grid { grid-template-columns: 1fr 1fr; gap: 2rem 3rem; }
}

/* Long unbroken strings (emails, URLs, headline words) wrap instead of
   stretching their container. :where() keeps specificity at 0 so no
   component style is disturbed. */
body :where(p, li, h1, h2, h3, h4, h5, h6, span, strong, em, a,
            blockquote, dd, dt, figcaption, label, td, th) {
    overflow-wrap: break-word;
}


/* -----------------------------------------------------------------
   9. PRINT
   ----------------------------------------------------------------- */
@media print {
    .site-header, .wa-fab, .mobile-nav, .scroll-progress, .cta-banner { display: none !important; }
    .section { padding: 1rem 0; }
    a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; }
}


/* =================================================================
   10. HOME REFRESH
   Appended last on purpose: responsive.css already loads after
   style.css / upgrades.css / service-page.css / mobile-fixes.css,
   so equal-specificity rules here win without editing those files.
   Every value is rem / % / ch / clamp() so it rides the fluid root
   font size from section 1 — 320px phone to 4K TV.
   ================================================================= */

:root {
    /* Two-layer elevation: a tight contact shadow + a wide ambient one.
       The navy is a literal, NOT var(--c-primary): header.php re-declares
       --c-primary from the DB after every stylesheet, so a derived shadow
       would follow a brand-colour change and tint every shadow on the site. */
    --e-1: 0 1px 2px rgba(10,37,64,.05),
           0 2px 6px -2px rgba(10,37,64,.06);
    --e-2: 0 2px 4px -2px rgba(10,37,64,.07),
           0 8px 20px -8px rgba(10,37,64,.10);
    --e-3: 0 4px 8px -4px rgba(10,37,64,.09),
           0 16px 36px -12px rgba(10,37,64,.15);

    /* Legacy aliases so the existing components upgrade for free.
       --shadow-lg is deliberately NOT re-aliased: it lands on .hero-image,
       .ceo-photo img and .mock-card across eight page types. */
    --shadow-sm: var(--e-1);
    --shadow:    var(--e-2);

    /* How deep the navy stats card sits into the hero. One value drives
       both the hero padding-bottom and the card negative margin, so the
       two can never drift apart. */
    --hero-seat: clamp(2rem, 3.5vw, 4rem);

    /* Mirrors the .section padding, so a band opener can restore the top
       gap that ".section + .section { padding-top: 0 }" removes. */
    --band-top: clamp(3rem, 7vw, 6rem);
}
@media (max-width: 600px)  { :root { --band-top: 2rem; } }
@media (min-width: 1600px) { :root { --band-top: clamp(3rem, 5vw, 7rem); } }


/* ---- Headline: its own measure, and an unbreakable accent phrase --- */
.hero-title {
    max-width: min(21ch, 100%);   /* font-relative: same character count at every size */
    text-wrap: balance;           /* purely decorative; ignored where unsupported */
    letter-spacing: -.022em;
}
/* The accent phrase is span-wrapped by the CMS. inline-block makes it
   atomic: it may START a line, it can never be SPLIT across two. */
.hero-title span { display: inline-block; }
.hero-sub { max-width: min(46ch, 100%); }


/* ---- Hero proof rail ----------------------------------------------
   The three bullets stop being a ragged tail on the left column and
   become a full-width rail. Its hairline is the hero bottom edge and
   the shared baseline both columns land on. */
.hero-bullets {
    display: grid;
    grid-template-columns: 1fr;
    gap: .6rem;
    font-size: clamp(.85rem, .8rem + .18vw, .95rem);
    align-items: start;
}
.hero-bullets > *  { min-width: 0; }
.hero-bullets li   { align-items: flex-start; gap: .5rem; }
.hero-bullets svg  { flex: 0 0 auto; margin-top: .15em; }

@media (min-width: 880px) {
    .hero-grid-cols {
        grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
        column-gap: clamp(2rem, 3.5vw, 4rem);
        row-gap: 0;              /* the style.css "gap" shorthand would otherwise
                                    add 48px on top of the rail margin-top */
        align-items: center;
    }
    /* Explicit placement so DOM order (copy, proof, visual) and visual
       order agree at every width — no "order", so tab order stays correct. */
    .hero-copy    { grid-column: 1; grid-row: 1; }
    .hero-visual  { grid-column: 2; grid-row: 1; }
    .hero-bullets {
        grid-column: 1 / -1; grid-row: 2;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: clamp(1rem, 2vw, 2rem);
        margin-top: clamp(1.75rem, 3vw, 2.75rem);
        padding-top: clamp(1.25rem, 2vw, 1.75rem);
        border-top: 1px solid var(--c-line);
    }
}


/* ---- Hero CTAs: stack on every phone, not just tiny ones -----------
   mobile-fixes.css gives them flex:1 up to 600px, so 390-430px phones
   were getting two ~169px buttons. Scoped to .hero because .hero-ctas
   is reused on two other page types. */
@media (max-width: 559px) {
    .hero .hero-ctas      { flex-direction: column; align-items: stretch; gap: .6rem; }
    .hero .hero-ctas .btn {
        flex: 0 0 auto; width: 100%; justify-content: center;
        white-space: normal; text-align: center;   /* labels are admin-editable */
    }
}


/* ---- The seat: hero padding becomes depth the stats card straddles -
   Gated to 880px and up: below that the hero is single-column and there
   is no dead zone to reclaim. */
@media (min-width: 880px) {
    .hero {
        padding-top:    clamp(2.5rem, 4vw, 4.25rem);
        padding-bottom: calc(clamp(2rem, 3vw, 3rem) + var(--hero-seat));
    }
    /* show_stats off in admin means nothing to seat. Where :has() is
       unsupported the selector is dropped and the hero keeps the LARGER
       padding: it degrades toward extra space, never toward a collision. */
    .hero:not(:has(+ .stats-strip)) { padding-bottom: clamp(2rem, 3vw, 3rem); }

    .hero + .stats-strip {
        margin-top: calc(var(--hero-seat) * -1);
        padding-bottom: clamp(1.75rem, 3vw, 3rem);
    }
}
.hero + .stats-strip { position: relative; z-index: 2; }  /* above .hero::before */

/* Light from above, using white transparency over the existing token.
   NOT color-mix(): a var()-bearing declaration that goes invalid at
   computed-value time resets "background" to transparent, which would
   put white text on white in older browsers. */
.stats-row {
    background:
        radial-gradient(120% 160% at 15% -30%,
            rgba(255,255,255,.16), rgba(255,255,255,0) 62%),
        var(--c-primary);
    box-shadow: 0 1.5rem 3rem -1rem rgba(10,37,64,.38),
                inset 0 1px 0 rgba(255,255,255,.10);
}
/* Hairlines turn four numbers into one instrument panel. stats_json is
   admin-editable, so reset every row-opening cell or a 5th stat would
   get a divider hanging in space. */
@media (min-width: 560px) {
    .stats-row > .stat + .stat           { box-shadow: inset 1px 0 0 rgba(255,255,255,.12); }
    .stats-row > .stat:nth-child(4n + 1) { box-shadow: none; }
}


/* ---- Band 1: one arrival atmosphere -------------------------------
   The hero used to fade to pure white, then add white padding, then a
   navy card landed on that white. Resolve the gradient into --c-soft
   and keep the strip and marquee on the same tint, so the top of the
   page has exactly one surface change — at .about-intro. */
.hero        { background: linear-gradient(180deg, #eef3fa 0%, var(--c-soft) 100%); }
.stats-strip { background: var(--c-soft); }

.marquee {
    border-block: 0;                                   /* hard borders made it a slab */
    box-shadow: inset 0 1px 0 var(--c-line),
                inset 0 -1px 0 var(--c-line);          /* on-tint hairlines: a rail */
}


/* ---- Band 2: services + counters, cards raised ---------------------
   .service-card and .counter are #fff with a 1px #e6ebf2 border on a
   white page — zero luminance separation. Tint the band and raise the
   cards: twelve cards go from dissolving into the page to lit surfaces. */
.services { background: var(--c-soft); }
.counters { border-top: 0; }        /* that line is now INSIDE one band */

/* Band openers get their top gap back — ".section + .section" zeroes it.
   .counters deliberately keeps 0 so it merges with .services. */
.section + .services,
.section + .ceo-message { padding-top: var(--band-top); }

/* The rule: elevation follows surface. On tint, cards are raised. */
.services .service-card,
.counters .counter            { box-shadow: var(--e-1); }
.services .service-card:hover { box-shadow: var(--e-3); }
.counters .counter:hover      { box-shadow: var(--e-2); }


/* ---- About pillars: stop the 2x2 grid stretching to the copy column -
   .about-grid stretches its columns, so the four pillar cards were being
   pulled to 182px each while their content is only 75px — 65px of dead
   space inside every card, which reads as a mistake rather than padding.
   Centre the block instead and let the cards be content-height. */
@media (min-width: 880px) {
    .about-grid    { align-items: center; }
    .about-pillars { align-content: center; }
}
