/*
 * Additions on top of the legacy compiled stylesheet (style.css).
 * These replace behaviour that used to come from jQuery plugins:
 * fullPage.js (section snapping, nav dots positioning context) and
 * jQuery smooth scrolling.
 */

html {
    scroll-behavior: smooth;
}

/* AOS pre-animation states (zoom-out at 120%, fades translated ±100px)
   stick out of the viewport before they trigger and create horizontal
   scroll, most visibly on phones. `clip` (not `hidden`) — hidden turns
   body into a scroll container and breaks the sticky header */
html,
body {
    overflow-x: clip;
}

/* Services page: no CSS scroll-snap at all (2026-09-12). The gentle
   `y proximity` snap that replaced fullPage.js was removed after Cody
   reported the scroll "getting stuck" in the last two sections. Cause
   is geometric: sections are 100vh and the footer is ~314-354px tall,
   so the last section's snap point (its top) and the footer's (its
   end) sit only ~394-444px apart — closer than Chrome's proximity
   range on either side — leaving NO resting position anywhere in the
   Fixes section: every scroll stop there was pulled to one end or the
   other. Sections 1-3 have a free middle third, which is why it felt
   worst at the end. Frame time was ruled out (median 16.7ms/frame in
   every section; the rAF rigs' forced layouts in Research/Fixes cost
   ~3-18ms total over a 3s scroll). Rather than special-case the last
   section, snap is gone entirely: Cody prefers fully manual scrolling
   and the scroll-scrubbed reveals (app.js) already carry the pacing.
   Do not reintroduce snap (`mandatory` or `proximity`) or wheel
   interception. scroll-padding-top below is unrelated and stays — the
   #fp-nav anchor jumps and #contact still need it. */

/* Scroll-driven reveals (app.js adds .scroll-driven and .reveal-block
   when motion is allowed): titles and text follow scroll progress via
   custom properties instead of the legacy one-shot fadeIns */
#fullpage.scroll-driven .section-title {
    animation: none !important;
    transition: none;
    /* floor at 0.35: the solid ribbon shapes read as broken at very low
       opacity in a way body text doesn't */
    opacity: calc(0.35 + var(--reveal, 1) * 0.65);
    transform: translateX(var(--reveal-x, 0px));
    will-change: opacity, transform;
}

#fullpage.scroll-driven .reveal-block {
    animation: none !important;
    transition: none;
    opacity: var(--reveal, 1);
    transform: translateY(var(--reveal-y, 0px));
    will-change: opacity, transform;
}

@media screen and (min-width: 2200px) {
    #fullpage.scroll-driven .section-title {
        transform: translateX(var(--reveal-x, 0px)) scale(1.3);
    }
}

/* fullPage.js used to add .fp-section { position: relative }; the balloon
   and section content rely on sections being a positioning context */
#fullpage .section {
    position: relative;
}

/* the parallax balloon is z-index 10 and travels down the page; text
   blocks and the footer must stack above it */
#fullpage .section__content {
    position: relative;
    z-index: 15;
}

.footer {
    position: relative;
    z-index: 20;
}

/* Scroll-linked balloon (app.js): per-frame transform updates replace the
   legacy .balloon--N class hops, so the class transition must not fight them */
.balloon--parallax {
    transition: none;
    will-change: transform;
}

/* Leak-repair story (app.js drives --patch 0→1 from scroll progress):
   X-mark patches land on the two smoke.gif leak points, each hiss fades
   out once its patch is on, then the balloon lifts. Positions are px in
   the balloon's own box, same coordinate system as .balloon__smoke--N */
.balloon__patch {
    position: absolute;
    width: 85px;
    z-index: 2;
    opacity: var(--patch, 0);
    /* the 3D tilt lays each patch onto the envelope's curvature at the
       base of its leak, instead of floating flat over the drawing */
    transform: perspective(600px)
        rotateX(var(--patch-tilt-x, 0deg))
        rotateY(var(--patch-tilt-y, 0deg))
        rotate(var(--patch-rot, 0deg))
        scale(calc(0.4 + var(--patch, 0) * 0.6));
    filter: drop-shadow(2px 3px 2px rgba(0, 0, 0, 0.3));
    pointer-events: none;
    will-change: transform, opacity;
}

.balloon__patch img {
    display: block;
    width: 100%;
    height: auto;
}

.balloon__patch--1 {
    /* left leak: the smoke gif's jet originates at balloon-local
       (236, 375) — measured from the gif frames mapped through the
       element's rotate(60deg) — on the envelope's front-left face */
    top: 332px;
    left: 194px;
    --patch-rot: -6deg;
    --patch-tilt-y: 22deg;
    --patch-tilt-x: -6deg;
}

.balloon__patch--2 {
    /* right leak: jet origin at balloon-local (417, 370), nearly
       face-on at the crown's centre */
    top: 328px;
    left: 374px;
    --patch-rot: 9deg;
    --patch-tilt-y: -8deg;
    --patch-tilt-x: -5deg;
}

/* Repair machine arms, cutout-rigged: each arm is three full-canvas
   layers sliced at the drawn joint circles (the circles ride on the
   child layer, covering the rotation seams). app.js pins each base near
   the page edge and FABRIK-bends the joints so the tool tip lands on
   its balloon anchor — at any viewport size, no breakpoints. */
#fullpage.scroll-driven .hypothesis__machine {
    transition: none;
    /* arms are pinned at the true viewport edge, which sits outside the
       centered section box on large screens; page-level overflow-x: clip
       already guards against horizontal scroll */
    overflow: visible;
}

.hypothesis__machine .arm-rig {
    position: absolute;
    top: 0;
    left: 0;
    right: auto;
    transform: none;
    will-change: transform;
}

.hypothesis__gripper.arm-rig {
    width: 639px;
    height: 341px;
}

.hypothesis__painter.arm-rig {
    width: 480px;
    height: 649px;
}

.arm-rig__seg {
    position: absolute;
    inset: 0;
    transform: rotate(var(--a, 0deg));
    will-change: transform;
}

.arm-rig__seg img {
    position: absolute;
    top: 0;
    left: 0;
    max-width: none;
}

/* Health-check measuring crew + researcher (app.js scrubs them from
   scroll progress in scroll-driven mode): the legacy one-shot bounce/
   fade animations must not fight the per-frame transforms, and the
   pieces are re-anchored from 0,0 so the balloon-tracked translate is
   their only placement */
#fullpage.scroll-driven .health-check__ruler-left,
#fullpage.scroll-driven .health-check__ruler-right,
#fullpage.scroll-driven .health-check__ruler-horizontal,
#fullpage.scroll-driven .health-check__extra-dude {
    animation: none !important;
    opacity: 0;
    left: 0;
    right: auto;
    top: 0;
    /* behind the title ribbons and text scrims (negative z within the
       content's stacking context), like the balloon they measure —
       never over the copy */
    z-index: -1;
    will-change: transform, opacity;
}

#fullpage.scroll-driven .research__person {
    animation: none !important;
    opacity: 1;
    will-change: transform;
}

/* hold space for the crew: the text column stops where the measuring
   jig around the balloon begins, instead of running underneath it */
@media screen and (min-width: 769px) {
    .health-check__text-wrap {
        max-width: min(34.375rem, 100vw - 62rem);
    }
}

@media screen and (min-width: 1600px) {
    /* the balloon shifts right: 180px here; the reserve follows */
    .health-check__text-wrap {
        max-width: min(34.375rem, 100vw - 73rem);
    }
}

/* narrow desktops: the balloon overflows the left edge, so the pieces
   that sit left of it (tall ruler, horizontal jig) have no clear lane */
@media screen and (max-width: 1199px) {
    .health-check__ruler-left,
    .health-check__ruler-horizontal {
        display: none;
    }
}

/* The balloon is hidden below 769px; arms reaching for — and rulers
   measuring — a balloon that isn't there read as noise, so both go
   with it (the legacy stylesheet shows the rulers from 481px) */
@media screen and (max-width: 768px) {
    .hypothesis__machine,
    .health-check__ruler {
        display: none;
    }
}

/* Below ~1150px the balloon fills the viewport's right side and the
   gripper's long horizontal boom tangles across it; the painter alone
   (top edge down to the neck) keeps the working-on-it story clean */
@media screen and (max-width: 1149px) {
    .hypothesis__gripper {
        display: none;
    }
}

/* Full-viewport cloud backdrop behind the services sections (was sized to
   the whole translated fullPage container before) */
#clouds {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: -1;
}

/* ------------------------------------------------------------------ */
/* Responsive sweep (2026-07): the legacy stylesheet stops adapting at */
/* 1441px and sizes text in rem, so scaling the root font-size carries */
/* the whole type system up on large displays. Content measure is      */
/* capped per the 65–75ch readability guideline.                       */

@media screen and (min-width: 1680px) {
    html { font-size: 17px; }

    /* legacy caps the hero ribbons at 1000px; let them track the type
       scale or the enlarged headline wraps and the ribbons collide */
    .ribbons {
        max-width: 65rem;
    }
}

@media screen and (min-width: 1920px) {
    html { font-size: 18px; }
}

@media screen and (min-width: 2560px) {
    html { font-size: 20px; }
}

@media screen and (min-width: 3400px) {
    html { font-size: 23px; }
}

body {
    font-size: 1.125rem; /* was fixed 18px; now tracks the root scale */
}

/* Readable measure: the legacy %-width containers stretch absurdly wide
   on big screens (60% of 80% of a 4K viewport ≈ 1800px paragraphs) */
@media screen and (min-width: 769px) {
    .intro {
        max-width: 75rem;
        margin-left: auto;
        margin-right: auto;
    }

    .intro .intro__content {
        max-width: 70ch;
    }

    .intro .intro__content p,
    .intro .intro__content strong {
        font-size: 1.0625rem !important; /* legacy pins 1rem !important */
    }

    .intro .intro__content p {
        line-height: 1.6;
    }

    .quote-wrapper {
        max-width: 75rem;
    }

    .quote-wrapper .content {
        max-width: 65ch;
        font-size: 1.0625rem;
    }

    .quote-wrapper .content p {
        line-height: 1.6;
    }
}

@media screen and (min-width: 1024px) {
    .form-heading {
        max-width: 44rem;
    }

    .form {
        max-width: 40rem;
    }
}

/* Services page: measure cap for the wide text blocks only —
   .research__text/.hypothesis__text keep their legacy 30% geometry.
   The ribbon titles are px-built so they scale as one unit below. */
@media screen and (min-width: 769px) {
    .landing-page__text,
    .health-check__text-wrap {
        max-width: 62ch;
    }
}

/* Readability scrim: the theme's own below-481px pattern, extended to
   all viewports now that the parallax balloon and clouds drift behind
   copy anywhere. 0.92 (not the legacy 0.87) so the orange lead-ins
   hold 4.5:1 over pure-white artwork; near-invisible over the #333 bg */
.landing-page__text,
.research__text,
.hypothesis__text {
    background-color: rgba(51, 51, 51, 0.92);
    padding: 0.5em 1em;
}

@media screen and (min-width: 481px) {
    .landing-page__text {
        /* legacy used padding-right: 150px to hold off the stripe; as
           padding it would become a long empty scrim tail */
        margin-right: 150px;
    }
}

/* Homepage copy sits over the drifting cloud canvases — same scrim */
.intro .intro__content .content,
.quote-wrapper .content,
.form {
    background-color: rgba(51, 51, 51, 0.92);
    padding: 1em 1.25em;
}

@media screen and (min-width: 2200px) {
    .section-title {
        transform: scale(1.3);
        transform-origin: center bottom;
    }
}

/* Small screens: the legacy ribbon is unconstrained below 769px
   (absolute, right: -1.5rem, no left) and its text runs off-screen */
@media screen and (max-width: 768px) {
    .ribbons {
        left: 0;
        right: 0;
        width: 100%;
    }

    .ribbons .ribbon__top {
        padding: 0.75rem 1rem;
    }

    .ribbons .ribbon__top p {
        font-size: 1rem;
    }
}

/* Small screens: keep the hero CTA comfortable on narrow phones */
@media screen and (max-width: 480px) {
    .hero-cta__button {
        padding: 0.9rem 1.5rem;
        font-size: 1rem;
    }
}

/* Hero sizing (settled 2026-07-17 after three rounds with Cody): the
   artwork is 1903×1465 — 1.30:1, squarer than any monitor — so it
   CANNOT fill a wide screen without either cropping (100vh cap: cut
   people at the fold, or bottom-aligned, the whole balloon on ~2:1
   browser windows) or shrinking (the drawing's edges "just end"
   against the background). Decision: show it full-width at natural
   aspect and let the page scroll past a taller-than-viewport hero.
   Do not reintroduce a height cap; the real fix is a wide-format hero
   from the illustrator. */

/* Sticky navigation */
.page-header {
    position: sticky;
    top: 0;
    z-index: 100;
}

/* keep snap targets and the #contact anchor clear of the sticky header */
html.page-services {
    scroll-padding-top: 5rem;
}

#contact {
    scroll-margin-top: 5rem;
}

/* Mobile fixes (from the ux-review):
   - the banner's min-height:100vh left ~half a screen of dead space
     between the short mobile artwork and the hero CTA
   - the burger became a real <button> but legacy CSS only styled the
     old anchor, so UA button chrome leaked through
   - the hero's orange emphasis was locked inside the desktop media query */
@media screen and (max-width: 768px) {
    .home-banner {
        min-height: 0;
    }
}

.navbar-burger {
    background: transparent;
    border: 0;
    padding: 0;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
}

.ribbons p span {
    color: #ff9933;
}

/* Tuck the "More calls" bar up against the headline ribbon — the tall
   fold-shadow triangle otherwise leaves a ~40px empty band between them */
@media screen and (min-width: 769px) {
    .ribbons .ribbon__btm--wrap {
        margin-top: -45px;
    }
}

/* ------------------------------------------------------------------ */
/* Homepage additions (2026-07): hero CTA, audience strip, steps band, */
/* founder note. Palette/typography follow the legacy stylesheet:      */
/* #333 body, #ff9933 accent, Oswald headings, Raleway body.           */

/* CTA band: a compact strip, button horizontally + vertically centered
   within its own padding. Reversed 2026-09-12 — the original spec
   (min-height: 100vh on desktop, "its own full-screen stage") put a
   whole screen of dark background behind one button before the
   visitor had read any argument for it; that reads as an interstitial,
   not a call to action. The competitor research that justified an
   early hero CTA never justified a full-screen band — that was a
   layout side-effect of uncapping the hero height (2026-07-18). Now
   sized the same on every breakpoint, matching what phones already
   had; this component repeats verbatim after the steps section. */
.hero-cta-band {
    display: flex;
    align-items: center;
    justify-content: center;
}

.hero-cta {
    text-align: center;
    padding: 3rem 1rem;
}

.hero-cta__button {
    display: inline-block;
    background-color: #ff9933;
    color: #fff;
    padding: 0.9rem 3rem;
    font-family: 'Raleway', sans-serif;
    font-size: 1.1rem;
    font-weight: bold;
    text-transform: uppercase;
    text-decoration: none;
    box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.4);
    transition: transform 0.15s, box-shadow 0.15s;
}

.hero-cta__button:hover {
    transform: translate(-2px, -2px);
    box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.4);
}

.hero-cta__phone {
    display: block;
    margin-top: 1rem;
    color: #fff;
    text-decoration: none;
}

.hero-cta__phone:hover {
    color: #ff9933;
}

.audience__inner,
.steps__inner,
.founder__inner {
    max-width: 56rem;
    margin: 0 auto;
    text-align: center;
    color: #fff;
    position: relative;
    z-index: 1;
    background-color: rgba(51, 51, 51, 0.92);
    padding: 1em 1.25em;
}

.audience__title,
.steps__title {
    font-family: 'Oswald', sans-serif;
    font-weight: 600;
    font-size: 1.9rem;
    text-transform: uppercase;
    color: #fff;
    margin: 0 0 1.5rem;
}

.audience__list {
    list-style: none;
    margin: 0 0 1.5rem;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem 0;
}

.audience__list li {
    font-family: 'Oswald', sans-serif;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0 1.1rem;
}

.audience__list li + li {
    border-left: 2px solid #ff9933;
}

.audience__sub {
    color: #ccc;
    max-width: 620px;
    margin: 0 auto;
}

.steps__list {
    list-style: none;
    margin: 0 0 2rem;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 2.5rem;
}

.step {
    flex: 1 1 220px;
    max-width: 280px;
}

.step__num {
    display: block;
    font-family: 'Oswald', sans-serif;
    font-weight: 700;
    font-size: 3.2rem;
    line-height: 1;
    color: #ff9933;
    margin-bottom: 0.5rem;
}

.step h3 {
    font-family: 'Oswald', sans-serif;
    font-weight: 600;
    font-size: 1.15rem;
    text-transform: uppercase;
    margin: 0 0 0.5rem;
    color: #fff;
}

.step p {
    font-size: 0.95rem;
    color: #ccc;
    margin: 0;
}

.steps__link {
    display: inline-block;
    color: #ff9933;
    font-weight: bold;
    text-decoration: none;
    text-transform: uppercase;
    font-family: 'Oswald', sans-serif;
    letter-spacing: 0.04em;
}

.steps__link:hover {
    color: #fff;
}

.founder__inner {
    max-width: 42rem;
}

/* Founder portrait: a real photograph held inside the drawn world —
   white polaroid frame, slight tilt, the site's hard-offset shadow.
   Illustrator tape strips overlay the top corners when they land. */
.founder__photo {
    width: 11rem;
    margin: 0.5rem auto 1.75rem;
    padding: 0.55rem 0.55rem 1.9rem;
    background-color: #fff;
    box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.4);
    transform: rotate(-2deg);
}

.founder__photo img {
    display: block;
    width: 100%;
    height: auto;
}

.founder__lead {
    font-family: 'Oswald', sans-serif;
    font-size: 1.5rem;
    font-weight: 500;
    color: #ff9933;
    margin: 0 0 1.25rem;
}

.founder__sig {
    color: #ccc;
    font-style: italic;
    margin-top: 1.25rem;
}

/* Cap the page frame on very wide screens: nav row and footer columns
   share one width so the chrome tracks the centered content column
   (95rem rides the root font-size steps — ~1710px at 1920) instead of
   pinning to the viewport corners. Backgrounds stay full-bleed. */
.page-header .navbar .container.is-fluid,
.footer .widget-area {
    max-width: 95rem;
    margin-inline: auto;
}

/* The legacy stylesheet predates the optional tel field: it styles
   input[type=text|email|password] only, so type=tel rendered unstyled.
   Mirror those rules (style.css:4237-4255) here. */
input[type=tel] {
    background-color: rgba(51, 51, 51, 0.658);
    border: solid 1px white;
    border-radius: 3px;
    color: white;
    padding: 0 1rem;
    font-size: 1.1rem;
    max-width: 100%;
    height: 2.5rem !important;
    line-height: 3rem;
}

/* Contact form: breathing room between fields (labels were colliding
   with the previous field), and inline submit feedback (app.js) */
.form__single {
    margin-bottom: 1.25rem;
}

.form__single label {
    display: block;
    margin-bottom: 0.35rem;
}

.form__success {
    color: #fff;
    font-size: 1.1rem;
    line-height: 1.6;
    margin: 0;
}

.form__success a,
.form__error a {
    color: #ff9933;
}

.form__error {
    color: #ff6b6b;
    margin: 0 0 1rem;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    /* the .fp-completely artwork reveals are legacy CSS animations in
       the vendored stylesheet; neutralize them for reduced motion */
    #fullpage *,
    .home-banner__wrapper * {
        animation-duration: 0.01ms !important;
        animation-delay: 0ms !important;
        transition-duration: 0.01ms !important;
    }

    /* no scrubbed leak-repair story: show the resolved state — a
       perpetually hissing static balloon would tell the wrong story.
       --patch: 1 drives both the opacity and the scale to their
       landed values (app.js never sets it under reduced motion) */
    .balloon__smoke {
        display: none;
    }

    .balloon__patch {
        --patch: 1;
    }

    /* arms and rulers are composed statically by app.js
       (initStaticScene): same contact poses and measuring positions as
       the animated page, placed instantly around the parked balloon */
}
