/* ==========================================================================
   23-homepage.css — revamped public homepage (templates/page-landing-v2.php).
   ClickUp 869ebkvbr. v1.0

   NOT @import'd into tool-tracker.css. It is enqueued separately and versioned by
   FILEMTIME in osat_enqueue_assets(), for the same reason as 22-press.css: an
   @import'd child is cached independently of its parent's ?ver=, so an edit here
   would not reach returning visitors. Same trade-off, same fix.

   Every class is prefixed .osat-hp- so nothing here can collide with the v1
   homepage rules in 07-landing-page.css, which is still loaded on this page (the
   hero video component .osat-hero-video is deliberately reused from it).

   Design tokens come from 01-global.css. Phone-first: single column by default,
   two columns from 900px, wider gutters from 1200px. Minimum tap target 44px.
   ========================================================================== */

.osat-hp {
    background: var(--osat-body-bg);
}

/* Shared section furniture ------------------------------------------------- */
.osat-hp-wrap {
    max-width: 1240px;
    margin: 0 auto;
    padding: 0 var(--osat-spacing-md);
    box-sizing: border-box;
}
@media (min-width: 1200px) {
    .osat-hp-wrap { padding: 0 var(--osat-spacing-lg); }
}

.osat-hp-main section {
    padding: clamp(40px, 6vw, 84px) 0;
}
/* Alternating bands so a long scroll reads as distinct chapters rather than one
   endless page — the thing that makes competitors' homepages feel "designed".

   THE WHOLE SEQUENCE, top to bottom, because it only works if you read it as a run:
     hero        white -> #F0F4F8 gradient
     steps       WHITE
     assistant   tint  (--osat-body-bg, the page default; no rule needed)
     shots       WHITE   <- 2026-08-04, round 3
     features    #E8F0F6 -> white gradient (the one deliberate exception, see below)
     benefits    tint
     industries  WHITE
     cmp         tint
     plans       WHITE
     faq         tint
     cta         navy
   No two neighbours share a ground, wrap into the footer included. If you add a
   section, ADD IT TO THIS LIST and to the alternation — a band inserted without
   thinking about it merges with one of its neighbours and the chapter break is lost. */
.osat-hp-steps,
.osat-hp-shots,
.osat-hp-industries,
.osat-hp-plans { background: var(--osat-card-bg); }

/* The assistant demo (CU 869ec75na). The widget itself is styled by the shared
   main/25-chat-demo.css — this rule is only the band it sits in. Nothing else here:
   keep component styling out of this file so the widget looks identical wherever
   else it is dropped.

   [BAND COLOUR, revised 2026-08-04] .osat-hp-assistant is deliberately ABSENT from
   the white list above. It used to be white, because it sat directly under the "Key
   features" gradient, which ends #FFFFFF. The section moved up to sit between the
   steps row and the screenshots (owner's request), and the steps band is white — so
   white here would have run the two together with no visible boundary at exactly the
   point a new chapter starts. It takes the page's default --osat-body-bg tint, which
   also gives the widget's WHITE frame a ground to read as a raised panel against.

   [ROUND 3, same day] .osat-hp-shots below was ALSO tinted, so this band and that one
   ran together and the two only separated because the carousel's dark device frame
   happened to sit between them. Shots is now WHITE (owner's request), which turns that
   accident into a real boundary: assistant is the last tinted band before it, and the
   chat widget's white frame still has a tint to sit on. Nothing else needed changing —
   the alternation above absorbs it cleanly. */
.osat-hp-assistant .osat-cdemo { margin-top: var(--osat-spacing-xl); }

/* ---------------------------------------------------------------------------
   The "Key features" band is the ONE exception to the white/tinted alternation
   (CU 869edb5kc — "get some more colour in here").

   Three restrained things, all brand, none of them an image download:
     1. a soft NAVY-TINT WASH fading to white down the band, instead of flat white;
     2. the cards flipped from --osat-super-light-gray-bg to pure WHITE, so on the
        tinted ground they read as raised panels rather than as faint outlines;
     3. a large, 5%-opacity, zoomed crop of the LOGO MARK (assets/img/logo-icon.svg,
        the globe — never the wordmark) sitting behind the top-right corner.

   The watermark is the EXISTING 25KB logo SVG re-used as a background, not a new
   raster: the hero video was just cut 5.5MB -> 578KB (CU 869ecfynx) and a decorative
   background image is exactly the kind of thing that quietly gives that back.
   `background-size: 210%` is what makes it a zoomed CROP of the mark rather than a
   shrunk copy of the whole logo.

   There is no dark theme on this site (no prefers-color-scheme rule exists anywhere
   in assets/), so these are absolute light-theme values on purpose. If a dark mode is
   ever added, this band and the icon tints below are the two places to revisit.
   --------------------------------------------------------------------------- */
.osat-hp-features {
    position: relative;
    overflow: hidden;   /* keeps the oversized watermark inside the band */
    background: linear-gradient(180deg, #E8F0F6 0%, #F4F8FB 52%, #FFFFFF 100%);
}
.osat-hp-features::before {
    content: "";
    position: absolute;
    top: -18%;
    right: -14%;
    width: min(760px, 82vw);
    aspect-ratio: 1 / 1;
    background: url("../../img/logo-icon.svg") no-repeat 34% 40% / 210%;
    opacity: 0.07;
    pointer-events: none;
    /* [CRITICAL] Without the mask this element's own BOX EDGES are visible as two
       hard straight lines across the band (the left and bottom sides — the top and
       right run off-canvas). The mask fades the crop out to nothing before it reaches
       them, which is what makes it read as a watermark rather than as a pasted panel.
       -webkit- prefix kept for older iOS Safari, which is the device target here. */
    -webkit-mask-image: radial-gradient(closest-side, #000 40%, rgba(0, 0, 0, 0) 100%);
            mask-image: radial-gradient(closest-side, #000 40%, rgba(0, 0, 0, 0) 100%);
}
/* Content above the watermark. Also the reason ::before needs no z-index. */
.osat-hp-features > .osat-hp-wrap {
    position: relative;
    z-index: 1;
}

.osat-hp-h2 {
    margin: 0 0 var(--osat-spacing-sm);
    font-size: clamp(1.55rem, 3.6vw, 2.35rem);
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--osat-primary-color);
    text-align: center;
}
.osat-hp-sub {
    margin: 0 auto clamp(24px, 4vw, 44px);
    max-width: 62ch;
    font-size: clamp(1rem, 1.6vw, 1.12rem);
    line-height: 1.55;
    color: var(--osat-secondary-text-color);
    text-align: center;
}
.osat-hp-eyebrow {
    margin: 0 0 var(--osat-spacing-sm);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--osat-accent-color);
}
.osat-hp-more {
    margin: clamp(24px, 4vw, 40px) 0 0;
    text-align: center;
}
.osat-hp-more a {
    color: var(--osat-primary-color);
    font-weight: 600;
    text-decoration: none;
}
.osat-hp-more a:hover,
.osat-hp-more a:focus-visible { text-decoration: underline; }

.osat-hp-ico {
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
}

/* Buttons. Local to this page so the marketing CTAs can be larger and calmer than
   the app's .osat-btn without touching it. */
.osat-hp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 12px 26px;
    border: 2px solid transparent;
    border-radius: var(--osat-border-radius);
    font-size: 1.02rem;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.osat-hp-btn--primary {
    background: var(--osat-accent-color);
    border-color: var(--osat-accent-color);
    color: var(--osat-light-text-color);
}
.osat-hp-btn--primary:hover,
.osat-hp-btn--primary:focus-visible {
    background: var(--osat-accent-hover-color);
    border-color: var(--osat-accent-hover-color);
    color: var(--osat-light-text-color);
    transform: translateY(-1px);
}
.osat-hp-btn--ghost {
    background: transparent;
    border-color: var(--osat-primary-color);
    color: var(--osat-primary-color);
}
.osat-hp-btn--ghost:hover,
.osat-hp-btn--ghost:focus-visible {
    background: var(--osat-primary-color);
    color: var(--osat-light-text-color);
}

/* (The admin-only preview banner was removed with /home-preview/ — CU 869ecewtm.) */

/* 1. Hero ----------------------------------------------------------------- */
.osat-hp-hero {
    background: linear-gradient(180deg, #FFFFFF 0%, var(--osat-body-bg) 100%);
}
.osat-hp-hero__inner {
    display: grid;
    grid-template-columns: 1fr;
    align-items: center;
    gap: clamp(28px, 4vw, 52px);
    max-width: 1240px;
    margin: 0 auto;
    padding: 0 var(--osat-spacing-md);
    box-sizing: border-box;
}
/* PHONE (the default): one column, and source order alone gives the requested
   running order — slogan, explanation, VIDEO, "Start free" button, ticks. No CSS
   reordering is involved, which is why the hero is three grid children rather than
   two (see the note in the template).

   DESKTOP: two columns, with the video spanning both copy rows on the right. */
.osat-hp-hero__inner {
    grid-template-areas:
        "top"
        "media"
        "bottom";
}
.osat-hp-hero__copy--top    { grid-area: top; }
.osat-hp-hero__media        { grid-area: media; }
.osat-hp-hero__copy--bottom { grid-area: bottom; }
@media (max-width: 999px) {
    /* The gap between the three stacked blocks is tighter than the desktop column gap:
       at 52px the video was pushed a long way from the paragraph it illustrates. */
    .osat-hp-hero__inner { gap: clamp(20px, 4vw, 30px); }
}
@media (min-width: 1000px) {
    .osat-hp-hero__inner {
        grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
        grid-template-areas:
            "top    media"
            "bottom media";
        align-items: start;
        gap: clamp(36px, 4vw, 64px) clamp(36px, 4vw, 64px);
        padding: 0 var(--osat-spacing-lg);
    }
    /* Video vertically centred against the full height of the copy column. */
    .osat-hp-hero__media { align-self: center; }
    /* The two copy blocks are one continuous column on desktop, so kill the row gap
       between them — the paragraph's own margin already spaces them. */
    .osat-hp-hero__inner { row-gap: 0; }
    .osat-hp-hero__copy--bottom { padding-top: var(--osat-spacing-sm); }
}
/* The H1 is a two-line SLOGAN, so it can carry proper display weight. The generous
   margins below it and below the lead are deliberate breathing room, asked for so the
   slogan, the explanation and the call to action read as three separate beats rather
   than one block of text. */
.osat-hp-hero__title {
    margin: 0 0 clamp(20px, 2.6vw, 32px);
    font-size: clamp(2rem, 5.2vw, 3.2rem);
    line-height: 1.12;
    letter-spacing: -0.02em;
    color: var(--osat-primary-color);
    /* All the slogans occupy ONE grid cell, so the H1 is as tall as the tallest of
       them and the paragraph beneath never jumps as they rotate. A fixed height would
       have to be re-guessed at every breakpoint; this measures itself. */
    display: grid;
    grid-template-areas: "slogan";
}
.osat-hp-slogan {
    grid-area: slogan;
}
/* Before the script runs, only the first slogan is shown — so with no JS the headline
   is simply that one, sitting still. `.is-rotating` opts into the animated behaviour. */
.osat-hp-slogan:not(.is-active) { visibility: hidden; }
/* The idle state is visibility:hidden, NOT merely opacity:0. An opacity-0 element is
   still rendered, so its text counts towards the H1's innerText and can still be picked
   up as page text — three slogans' worth. visibility is delayed by the transition
   duration so the outgoing slogan stays on screen while it animates away. */
.osat-hp-hero__title.is-rotating .osat-hp-slogan {
    visibility: hidden;
    opacity: 0;
    transform: translateX(-28px);
    transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.5s ease, visibility 0s linear 0.6s;
    pointer-events: none;
}
.osat-hp-hero__title.is-rotating .osat-hp-slogan.is-active,
.osat-hp-hero__title.is-rotating .osat-hp-slogan.is-leaving {
    visibility: visible;
    transition: transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.5s ease, visibility 0s;
}
.osat-hp-hero__title.is-rotating .osat-hp-slogan.is-active {
    opacity: 1;
    transform: translateX(0);
    pointer-events: auto;
}
/* Entering starts off to the LEFT (no transition, so it snaps into place before the
   class swap animates it in); leaving travels out to the RIGHT. */
.osat-hp-hero__title.is-rotating .osat-hp-slogan.is-entering {
    visibility: visible;
    transition: none;
    opacity: 0;
    transform: translateX(-28px);
}
.osat-hp-hero__title.is-rotating .osat-hp-slogan.is-leaving {
    opacity: 0;
    transform: translateX(28px);
}
.osat-hp-hero__lead {
    margin: 0 0 clamp(26px, 3.2vw, 40px);
    max-width: 60ch;
    font-size: clamp(1rem, 1.7vw, 1.14rem);
    line-height: 1.6;
    color: var(--osat-primary-text-color);
}
/* The two lead paragraphs are ONE thought split in two (the owner's requested break
   before "Photograph an item", CU 869edb5kc), so the gap between them is a paragraph
   gap. The full clamp() beat above is what separates the whole lead block from what
   follows it, and using it twice made the hero read as two unrelated blocks. */
.osat-hp-hero__copy--top .osat-hp-hero__lead:not(:last-of-type) {
    margin-bottom: clamp(14px, 1.8vw, 20px);
}
/* Now lives in copy--bottom, between the trust ticks and the sector chips (see the
   note in the template).

   [COPY] It reads as a SECOND HEADLINE, not as a caption for the chips (asked for
   2026-08-04, CU 869edb5kc). That needs a clear blank line on BOTH sides: it used to
   take whatever the ticks left above it and only 8px below, which glued it to the
   chips and lost it. The values are ~1.2x this paragraph's own line box, so what you
   see above and below it is a genuinely empty line at every width in the clamp.

   Margin-top COLLAPSES with .osat-hp-hero__trust's margin-bottom (24px here, 16px on
   phones) — the larger wins, which is why these are stated in full rather than as an
   increment. Keep them above those two numbers or the gap silently stops growing.

   [FOLD] Safe for the phone fold: everything this moves is BELOW .osat-hp-hero__actions
   in source order, so the "Start free" button does not shift. homepage.spec.js guards
   that ("primary call to action is reachable without scrolling on a phone"). */
/* [SPECIFICITY] Doubled class on purpose. This element is ALSO .osat-hp-hero__lead, and
   the phone override of that class further down the file sets margin-bottom:16px at
   the same 0-1-0 specificity — so at <=640px the later rule won and the gap below this
   line silently collapsed back to 16px. Two classes (0-2-0) win at every width. */
.osat-hp-hero__lead.osat-hp-hero__lead--who {
    margin-top: clamp(28px, 3vw, 36px);
    margin-bottom: clamp(28px, 3vw, 36px);
    font-weight: 600;
    color: var(--osat-primary-color);
}
.osat-hp-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--osat-spacing-md);
    margin-bottom: var(--osat-spacing-lg);
}
.osat-hp-hero__actions .osat-hp-btn { flex: 1 1 220px; }
@media (min-width: 600px) {
    .osat-hp-hero__actions .osat-hp-btn { flex: 0 0 auto; }
}
/* One tick per line at every width (asked for 2026-07-30) — as a wrapping row the
   three read as a single run-on line and the individual promises got lost. */
.osat-hp-hero__trust {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin: 0 0 var(--osat-spacing-lg);
    padding: 0;
    list-style: none;
}
.osat-hp-hero__trust li {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--osat-primary-text-color);
}
.osat-hp-hero__trust .osat-hp-ico {
    width: 19px;
    height: 19px;
    color: var(--osat-good-color);
}
/* TEN sector chips as of CU 869edb5kc, up from four. They wrap freely — the row is
   a plain wrapping flex, so at 360px they simply stack into more rows and nothing
   can push the document sideways (asserted in homepage.spec.js at 360 and 390). */
.osat-hp-hero__who {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    margin: 0;
    font-size: 0.84rem;
    color: var(--osat-secondary-text-color);
}
.osat-hp-hero__who-plain {
    padding: 4px 10px;
    background: rgba(8, 65, 92, 0.07);
    border-radius: 999px;
    color: var(--osat-primary-color);
    font-weight: 600;
}
.osat-hp-hero__who a {
    color: var(--osat-accent-color);
    font-weight: 700;
    text-decoration: none;
}
.osat-hp-hero__who a:hover,
.osat-hp-hero__who a:focus-visible { text-decoration: underline; }
/* The one LINK in this row gets its own line (flex-basis:100%) and a real 44px tap
   target. Trailing it after ten chips buried it, and at 0.84rem inline it was well
   under the touch minimum in CLAUDE.md. */
.osat-hp-hero__who-more {
    flex: 0 0 100%;
    display: inline-flex;
    align-items: center;
    /* inline-flex makes the trailing chevron a FLEX ITEM, which collapses the space
       before it and renders "See your industry>". The gap puts it back. */
    gap: 4px;
    min-height: 44px;
}

/* Phones: tighten the hero so the primary CTA is reachable without a long scroll.
   The public header already eats ~130px above the fold, and this H1 is a full
   sentence rather than a three-word slogan, so every line counts here. */
@media (max-width: 640px) {
    /* Selector deliberately matches the specificity of `.osat-hp-main section` above,
       which sets the shared section padding — otherwise this would lose. */
    .osat-hp-main .osat-hp-hero { padding-top: clamp(20px, 5vw, 32px); }
    .osat-hp-hero__title {
        font-size: clamp(1.85rem, 7.6vw, 2.3rem);
        margin-bottom: var(--osat-spacing-md);
    }
    /* 1.5 rather than 1.55: the lead is eleven lines on a 390px phone since the copy
       grew (CU 869edb5kc), and the hero CTA has to stay inside the fold — see the note
       on the audience line in the template. Worth ~10px, costs nothing in legibility. */
    .osat-hp-hero__lead {
        font-size: 0.99rem;
        line-height: 1.5;
        margin-bottom: var(--osat-spacing-md);
    }
    .osat-hp-hero__media-cap {
        margin-top: 6px;
        font-size: 0.8rem;
    }
    .osat-hp-hero__copy--top .osat-hp-hero__lead:not(:last-of-type) {
        margin-bottom: var(--osat-spacing-sm);
    }
    /* NO .osat-hp-hero__lead--who OVERRIDE HERE — deliberate. The blank line above and
       below it was asked for on phones as much as on desktop, so it takes the base
       rule's clamp minimum (28px, against a ~24px line box at this size). The override
       this replaces re-stated margin-bottom:8px plus a verbatim copy of the weight and
       colour, and the 8px was what flattened the gap on mobile. */
    .osat-hp-hero__actions { margin-bottom: var(--osat-spacing-md); }
    .osat-hp-hero__trust { gap: 7px; margin-bottom: var(--osat-spacing-md); }
    .osat-hp-hero__trust li { font-size: 0.9rem; }
}

.osat-hp-hero__media { min-width: 0; }
.osat-hp-hero__media-cap {
    margin: var(--osat-spacing-sm) 0 0;
    font-size: 0.85rem;
    color: var(--osat-secondary-text-color);
    text-align: center;
}

/* 2. Three steps ---------------------------------------------------------- */
.osat-hp-steps__list {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(24px, 3vw, 36px);
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: none;
}
@media (min-width: 760px) {
    .osat-hp-steps__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.osat-hp-step {
    position: relative;
    /* No align-self here: the cards must STRETCH to a common height (grid's default),
       which is what makes the three boxes match even though their body copy runs to
       different numbers of lines. The headlines stay level because all three
       illustrations are the same 660x720 canvas — see capture-home-steps.capture.js. */
    padding: var(--osat-spacing-lg);
    background: var(--osat-super-light-gray-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 14px;
    text-align: center;
}
.osat-hp-step__num {
    position: absolute;
    top: -16px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    background: var(--osat-accent-color);
    border-radius: 50%;
    color: var(--osat-light-text-color);
    font-weight: 700;
    font-size: 1rem;
}
/* Natural height, full card width. The illustrations are purpose-drawn for this box
   (osat-tests/capture-home-steps.capture.js) rather than reused from the articles, so
   they no longer need scaling down to fit a fixed frame — and scaling them down is
   exactly what made their text unreadable. Step 2 is the vertical sequence and so is
   taller than its neighbours; that is intended, and is what lets it fill the column on
   a phone. */
.osat-hp-step__img {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    margin: var(--osat-spacing-sm) auto var(--osat-spacing-md);
}
/* --- Step 1: the SHARED "identify from a photo" illustration -------------- */
/* ClickUp 869edb5ee. Steps 2 and 3 are still step-*.png; step 1 is live HTML so its
   PHOTO and three strings can cycle through kit from different trades without a PNG
   per industry. On 2026-08-04 the whole drawing moved out of this file into the
   reusable component `.osat-idemo` (assets/css/main/26-identify-demo.css, markup in
   templates/parts/global/identify-demo.php, photos in
   includes/config/identify-demo-sets.php) so it can be dropped on any page. Everything
   that used to be here — the container-query scaling, the phone, the viewfinder, the
   swipe — lives there now, and the class prefix changed from .osat-hp-il1 to
   .osat-idemo with it.

   [CRITICAL] IT MUST OCCUPY THE SAME 660x720 BOX THE PNGs DO. The three cards only
   have level headlines because all three illustrations share that canvas — see the
   note by .osat-hp-step, and the assertion in osat-tests/homepage.spec.js. The canvas
   itself is the component's (`.osat-idemo` sets width, aspect-ratio, overflow and
   container-type); all this page adds is the same margin the two <img> steps carry, so
   the row sits level. Keep this rule in step with .osat-hp-step__img above. */
.osat-hp-step__il {
    margin: var(--osat-spacing-sm) auto var(--osat-spacing-md);
}

.osat-hp-step__title {
    margin: 0 0 var(--osat-spacing-sm);
    font-size: 1.2rem;
    color: var(--osat-primary-color);
}
.osat-hp-step p {
    margin: 0;
    font-size: 0.98rem;
    line-height: 1.55;
    color: var(--osat-primary-text-color);
}
.osat-hp-step p a {
    display: inline-block;
    margin-top: 6px;
    color: var(--osat-accent-color);
    font-weight: 600;
    text-decoration: none;
}
.osat-hp-step p a:hover,
.osat-hp-step p a:focus-visible { text-decoration: underline; }

/* 3. Screenshots (auto-rotating carousel) --------------------------------- */
/* Until the script adds .is-carousel every figure is simply stacked and readable —
   see the note in the template. Everything below the base rules assumes JS ran. */
.osat-hp-shot {
    margin: 0 0 var(--osat-spacing-lg);
    padding: 0;
    background: var(--osat-card-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 14px;
    overflow: hidden;
    box-shadow: var(--osat-card-shadow);
}
.osat-hp-shot img {
    display: block;
    width: 100%;
    height: auto;
}
.osat-hp-shot figcaption {
    padding: var(--osat-spacing-md);
    font-size: 0.92rem;
    line-height: 1.5;
    color: var(--osat-secondary-text-color);
    text-align: center;
}

.osat-hp-carousel.is-carousel .osat-hp-carousel__viewport { overflow: hidden; }
.osat-hp-carousel.is-carousel .osat-hp-carousel__track {
    display: flex;
    align-items: flex-start;
    transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
}
.osat-hp-carousel.is-carousel .osat-hp-shot {
    flex: 0 0 100%;
    max-width: 100%;
    margin: 0;
}
/* The screen recording. Hidden entirely above the phone breakpoint — a desktop slide
   shows the wide screenshot, and there is no clip to play (the script checks the same
   width, so it never even assigns a src there). */
.osat-hp-shot__clip { display: none; }

/* Above the phone breakpoint the device wrapper is inert — the desktop slide is a
   plain wide screenshot with no frame. */
.osat-hp-shot__device { display: contents; }

/* PHONE: the clip sits inside a CSS-drawn phone bezel so it reads as a mockup rather
   than as a floating rectangle of UI.
   Deliberately drawn, not an image: a device PNG would be another download, would need
   its own retina variant, and would date the moment the handset it depicts does. The
   recordings are a fixed 780x1320 (from a 1126x2436 phone), so the aspect ratio inside
   the frame is known and the bezel can be a simple padded, rounded, dark box.

   A phone screenshot is portrait and would be ~1300px tall at full column width, which
   is a whole screen of one image — so the height is capped and the frame centred. */
@media (max-width: 760px) {
    .osat-hp-shot { background: var(--osat-super-light-gray-bg); }
    .osat-hp-shot__device {
        display: block;
        position: relative;
        width: fit-content;
        max-width: calc(100% - var(--osat-spacing-lg));
        margin: var(--osat-spacing-lg) auto 0;
        padding: 10px;
        background: #10222E;                 /* deeper than the brand navy, so the frame
                                                reads as hardware, not as UI chrome */
        border-radius: 34px;
        box-shadow:
            0 0 0 2px #29414E,               /* the polished rim */
            0 18px 34px rgba(8, 65, 92, 0.30);
    }
    /* The earpiece / camera notch. Purely decorative, hence aria-hidden by being CSS. */
    .osat-hp-shot__device::before {
        content: "";
        position: absolute;
        top: 15px;
        left: 50%;
        transform: translateX(-50%);
        width: 74px;
        height: 7px;
        background: #060F15;
        border-radius: 999px;
        z-index: 2;
    }
    /* [GOTCHA] NO `display` in this rule. It sets sizing for both the poster and the
       clip, and it is more specific (.osat-hp-carousel.is-carousel .osat-hp-shot__clip)
       than the .is-playing pair below — so a `display: block` here won the cascade and
       left the video rendered UNDERNEATH the poster on every non-playing slide, doubling
       the slide's height and leaving a screen of dead space beneath the carousel.
       Display is decided by the .is-playing rules alone. */
    .osat-hp-carousel.is-carousel .osat-hp-shot img,
    .osat-hp-carousel.is-carousel .osat-hp-shot__clip {
        width: auto;
        max-width: 100%;
        /* Less than the old 68vh: the bezel adds ~20px and the notch needs headroom. */
        max-height: 64vh;
        margin: 0 auto;
        border-radius: 25px;                 /* the screen's own corner radius */
    }
    .osat-hp-shot picture { display: block; }
    /* Swap poster for video only once playback has actually started. Until then the
       poster is what is on screen, so a blocked or failed autoplay degrades to the
       still rather than to an empty box. */
    .osat-hp-shot__clip { display: none; }
    .osat-hp-shot.is-playing picture { display: none; }
    .osat-hp-shot.is-playing .osat-hp-shot__clip { display: block; }
}

.osat-hp-carousel__nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--osat-spacing-sm);
    margin-top: var(--osat-spacing-md);
}
.osat-hp-carousel__arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    padding: 0;
    background: var(--osat-card-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 50%;
    color: var(--osat-primary-color);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.osat-hp-carousel__arrow svg { width: 20px; height: 20px; }
.osat-hp-carousel__arrow:hover,
.osat-hp-carousel__arrow:focus-visible {
    background: var(--osat-primary-color);
    border-color: var(--osat-primary-color);
    color: var(--osat-light-text-color);
}
.osat-hp-carousel__dots {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
/* Named dots on wide screens (the label IS the screen's name, which beats an anonymous
   row of circles), collapsing to plain dots where there is no room for words. */
.osat-hp-carousel__dot {
    min-height: 44px;
    padding: 10px 16px;
    background: none;
    border: 1px solid transparent;
    border-radius: 999px;
    color: var(--osat-secondary-text-color);
    font-family: inherit;
    font-size: 0.93rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.osat-hp-carousel__dot:hover,
.osat-hp-carousel__dot:focus-visible { color: var(--osat-primary-color); }
.osat-hp-carousel__dot.is-active {
    background: var(--osat-primary-color);
    color: var(--osat-light-text-color);
}
@media (max-width: 700px) {
    .osat-hp-carousel__dot {
        width: 12px;
        min-width: 12px;
        height: 12px;
        min-height: 12px;
        padding: 0;
        background: var(--osat-border-color);
        border-radius: 50%;
        /* The label stays in the accessible name via aria-label; only the visible
           text is dropped, so the dots remain announceable. */
        font-size: 0;
    }
    .osat-hp-carousel__dot span { display: none; }
    .osat-hp-carousel__dot.is-active { background: var(--osat-accent-color); }
    /* The dots shrink below the 44px target, so the ARROWS are the touch control —
       plus a swipe, which is what a phone user reaches for anyway. */
    .osat-hp-carousel__dots { gap: 9px; margin: 0 var(--osat-spacing-sm); }
}
@media (prefers-reduced-motion: reduce) {
    .osat-hp-carousel.is-carousel .osat-hp-carousel__track { transition: none; }
}

/* 4. Feature grid --------------------------------------------------------- */
.osat-hp-feat-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--osat-spacing-md);
    margin: 0;
    padding: 0;
    list-style: none;
}
@media (min-width: 620px) {
    .osat-hp-feat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1000px) {
    .osat-hp-feat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.osat-hp-feat { display: flex; }
.osat-hp-feat__link {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    padding: var(--osat-spacing-lg);
    /* WHITE, not --osat-super-light-gray-bg: the band behind them is now tinted
       (see .osat-hp-features), so white is what makes these read as raised cards. */
    background: var(--osat-card-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 12px;
    box-shadow: var(--osat-card-shadow);
    text-decoration: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.osat-hp-feat__link:hover,
.osat-hp-feat__link:focus-visible {
    border-color: var(--osat-primary-color);
    box-shadow: var(--osat-card-hover-shadow);
    transform: translateY(-2px);
}
.osat-hp-feat__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 44px;
    height: 44px;
    margin-bottom: 4px;
    background: rgba(8, 65, 92, 0.09);
    /* Transparent by default so the --ai chip's real border does not make that one
       card's icon 2px bigger than the other eleven. */
    border: 1px solid transparent;
    border-radius: 10px;
    color: var(--osat-primary-color);
}

/* Icon TONES (CU 869edb5kc). Every value is straight from the palette in
   01-global.css — see the mapping note on $hp_feature_cards in page-landing-v2.php.
   Only the chip is tinted; the title, body and card border stay navy/neutral, which
   is what keeps twelve coloured cards looking like a system rather than a fruit bowl.
   The rgba() tints are the palette hexes at low alpha, deliberately written out
   rather than derived — there is no colour-mix support baseline here. */
.osat-hp-feat__icon--navy {
    background: rgba(8, 65, 92, 0.12);
    color: var(--osat-primary-color);
}
.osat-hp-feat__icon--red {
    background: rgba(204, 41, 54, 0.12);
    color: var(--osat-accent-color);
}
.osat-hp-feat__icon--green {
    background: rgba(40, 167, 69, 0.15);
    color: var(--osat-good-color);
}
/* The two AI cards get the product's OWN AI treatment — the cream field and gold
   border used on every AI-populated input in the app — so the homepage flags AI the
   same way the product does. The GLYPH stays navy rather than amber: --osat-warning-color
   on --osat-input-bg-ai is about 2:1 contrast and a 1.6px stroke simply disappears on
   it. The cream + gold border is what carries the signal, exactly as in the app. */
.osat-hp-feat__icon--ai {
    background: var(--osat-input-bg-ai);
    border-color: var(--osat-input-border-ai);
    color: var(--osat-primary-color);
}
.osat-hp-feat__title {
    font-size: 1.08rem;
    font-weight: 700;
    line-height: 1.3;
    color: var(--osat-primary-color);
}
.osat-hp-feat__body {
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--osat-primary-text-color);
}

/* 5. Benefits ------------------------------------------------------------- */
.osat-hp-ben-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--osat-spacing-md);
}
@media (min-width: 620px) {
    .osat-hp-ben-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1000px) {
    .osat-hp-ben-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.osat-hp-ben {
    display: flex;
    flex-direction: column;
    padding: var(--osat-spacing-lg);
    background: var(--osat-card-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 12px;
    box-shadow: var(--osat-card-shadow);
}
.osat-hp-ben__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    margin-bottom: var(--osat-spacing-sm);
    background: rgba(204, 41, 54, 0.09);
    border-radius: 10px;
    color: var(--osat-accent-color);
}
.osat-hp-ben__title {
    margin: 0 0 6px;
    font-size: 1.1rem;
    line-height: 1.3;
    color: var(--osat-primary-color);
}
.osat-hp-ben p {
    margin: 0 0 var(--osat-spacing-md);
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--osat-primary-text-color);
}
.osat-hp-ben__link {
    margin-top: auto;
    color: var(--osat-accent-color);
    font-weight: 600;
    font-size: 0.93rem;
    text-decoration: none;
}
.osat-hp-ben__link:hover,
.osat-hp-ben__link:focus-visible { text-decoration: underline; }

/* 6. Industries ----------------------------------------------------------- */
.osat-hp-ind-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(20px, 3vw, 32px);
}
@media (min-width: 860px) {
    .osat-hp-ind-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.osat-hp-ind {
    display: flex;
    flex-direction: column;
    background: var(--osat-super-light-gray-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 14px;
    overflow: hidden;
}
.osat-hp-ind img {
    display: block;
    width: 100%;
    /* Banner crop on a 16:9 photo — centre, since the subject is mid-frame. */
    height: 220px;
    object-fit: cover;
    object-position: center;
}
.osat-hp-ind__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--osat-spacing-sm);
    padding: var(--osat-spacing-lg);
}
.osat-hp-ind__body h3 {
    margin: 0;
    font-size: 1.3rem;
    color: var(--osat-primary-color);
}
.osat-hp-ind__body p {
    margin: 0 0 var(--osat-spacing-sm);
    font-size: 0.98rem;
    line-height: 1.55;
    color: var(--osat-primary-text-color);
}

/* 7. Price comparison ----------------------------------------------------- */
.osat-hp-cmp__table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--osat-card-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 12px;
    box-shadow: var(--osat-card-shadow);
}
.osat-hp-cmp__table-wrap:focus-visible {
    outline: 2px solid var(--osat-primary-color);
    outline-offset: 2px;
}
.osat-hp-cmp-table {
    width: 100%;
    min-width: 640px;
    border-collapse: collapse;
    font-size: 0.94rem;
}
.osat-hp-cmp-table th,
.osat-hp-cmp-table td {
    padding: 13px var(--osat-spacing-md);
    border-bottom: 1px solid var(--osat-border-color);
    text-align: left;
    vertical-align: top;
}
.osat-hp-cmp-table thead th {
    background: var(--osat-super-light-gray-bg);
    color: var(--osat-primary-color);
    font-size: 0.82rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
}
.osat-hp-cmp-table tbody th {
    font-weight: 700;
    color: var(--osat-primary-color);
    white-space: nowrap;
}
.osat-hp-cmp-table tbody tr:last-child th,
.osat-hp-cmp-table tbody tr:last-child td { border-bottom: none; }
.osat-hp-cmp-table__ag { background: rgba(8, 65, 92, 0.045); }
.osat-hp-cmp-table__ag th,
.osat-hp-cmp-table__ag td { font-weight: 700; }
.osat-hp-cmp-table__us {
    display: inline-block;
    margin-left: 7px;
    padding: 2px 8px;
    background: var(--osat-accent-color);
    border-radius: 999px;
    color: var(--osat-light-text-color);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    vertical-align: middle;
}
.osat-hp-cmp-table__price {
    display: block;
    font-weight: 700;
    color: var(--osat-primary-text-color);
}
.osat-hp-cmp-table__peruser {
    display: block;
    margin-top: 3px;
    font-size: 0.84rem;
    font-weight: 400;
    color: var(--osat-secondary-text-color);
}
.osat-hp-tone-good { color: #17743A; }
.osat-hp-tone-bad  { color: #A3212B; }
/* ≤780px: re-flow the table into one card per provider so the section never scrolls
   sideways. Each cell prints its column heading from data-label (set in the template)
   because the <thead> is hidden here. Semantics are untouched — it is still a table to
   a screen reader, only the visual formatting changes. */
@media (max-width: 780px) {
    .osat-hp-cmp__table-wrap {
        overflow: visible;
        background: none;
        border: none;
        box-shadow: none;
    }
    .osat-hp-cmp-table { min-width: 0; }
    .osat-hp-cmp-table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
    .osat-hp-cmp-table,
    .osat-hp-cmp-table tbody,
    .osat-hp-cmp-table tr,
    .osat-hp-cmp-table th,
    .osat-hp-cmp-table td { display: block; }
    .osat-hp-cmp-table tr {
        margin-bottom: var(--osat-spacing-md);
        background: var(--osat-card-bg);
        border: 1px solid var(--osat-border-color);
        border-radius: 12px;
        overflow: hidden;
        box-shadow: var(--osat-card-shadow);
    }
    .osat-hp-cmp-table tbody th {
        padding: 12px var(--osat-spacing-md);
        background: var(--osat-super-light-gray-bg);
        border-bottom: 1px solid var(--osat-border-color);
        font-size: 1.02rem;
        white-space: normal;
    }
    .osat-hp-cmp-table td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--osat-spacing-md);
        padding: 10px var(--osat-spacing-md);
        border-bottom: 1px solid var(--osat-border-color);
        text-align: right;
    }
    .osat-hp-cmp-table td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        color: var(--osat-secondary-text-color);
        font-size: 0.78rem;
        font-weight: 700;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        text-align: left;
    }
    .osat-hp-cmp-table tr td:last-child { border-bottom: none; }
    .osat-hp-cmp-table__ag {
        border-color: var(--osat-accent-color);
        border-width: 2px;
    }
    /* The price cell holds TWO values (headline price + per-user), which as flex items
       sit beside the label and wrap into a ragged three-column mess. Stack that one
       cell instead: label, then price, then the per-user line. */
    .osat-hp-cmp-table td:first-of-type {
        display: block;
        text-align: left;
    }
    .osat-hp-cmp-table td:first-of-type::before {
        display: block;
        margin-bottom: 3px;
    }
    .osat-hp-cmp-table__price,
    .osat-hp-cmp-table__peruser { text-align: left; }
}

.osat-hp-cmp__note {
    margin: var(--osat-spacing-md) 0 0;
    font-size: 0.84rem;
    line-height: 1.55;
    color: var(--osat-secondary-text-color);
    text-align: center;
}
.osat-hp-cmp__note a { color: var(--osat-primary-color); font-weight: 600; }
.osat-hp-cmp__note-link {
    display: block;
    margin-top: 6px;
}

/* 8. Plans ---------------------------------------------------------------- */
.osat-hp-plan-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--osat-spacing-md);
}
@media (min-width: 620px) {
    .osat-hp-plan-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1000px) {
    .osat-hp-plan-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.osat-hp-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--osat-spacing-sm);
    padding: var(--osat-spacing-lg);
    background: var(--osat-super-light-gray-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 14px;
    text-align: center;
}
.osat-hp-plan--rec {
    background: var(--osat-card-bg);
    border-color: var(--osat-accent-color);
    box-shadow: var(--osat-card-hover-shadow);
}
.osat-hp-plan__badge {
    position: absolute;
    top: -13px;
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 13px;
    background: var(--osat-accent-color);
    border-radius: 999px;
    color: var(--osat-light-text-color);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
}
.osat-hp-plan__name {
    margin: 0;
    font-size: 1.15rem;
    color: var(--osat-primary-color);
}
.osat-hp-plan__price {
    margin: 0;
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.15;
    color: var(--osat-primary-text-color);
}
.osat-hp-plan__limits {
    margin: 0 0 var(--osat-spacing-sm);
    padding: 0;
    list-style: none;
    font-size: 0.94rem;
    line-height: 1.7;
    color: var(--osat-primary-text-color);
}
.osat-hp-plan .osat-hp-btn {
    width: 100%;
    margin-top: auto;
}

/* 9. FAQ ------------------------------------------------------------------ */
.osat-hp-faq__list {
    max-width: 900px;
    margin: 0 auto;
    background: var(--osat-card-bg);
    border: 1px solid var(--osat-border-color);
    border-radius: 12px;
    overflow: hidden;
    box-shadow: var(--osat-card-shadow);
}
.osat-hp-faq-item + .osat-hp-faq-item { border-top: 1px solid var(--osat-border-color); }
.osat-hp-faq-item__q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--osat-spacing-md);
    min-height: 44px;
    padding: var(--osat-spacing-md);
    font-size: 1.02rem;
    font-weight: 600;
    color: var(--osat-primary-color);
    cursor: pointer;
    list-style: none;
}
.osat-hp-faq-item__q::-webkit-details-marker { display: none; }
.osat-hp-faq-item__q::after {
    content: '+';
    flex: 0 0 auto;
    font-size: 1.4rem;
    font-weight: 400;
    line-height: 1;
    color: var(--osat-accent-color);
}
.osat-hp-faq-item[open] .osat-hp-faq-item__q::after { content: '\2212'; }
.osat-hp-faq-item__q:hover { background: var(--osat-super-light-gray-bg); }
.osat-hp-faq-item__a {
    padding: 0 var(--osat-spacing-md) var(--osat-spacing-md);
}
.osat-hp-faq-item__a p {
    margin: 0;
    font-size: 0.97rem;
    line-height: 1.65;
    color: var(--osat-primary-text-color);
}
.osat-hp-faq-item__a a { color: var(--osat-accent-color); font-weight: 600; }

/* 10. Closing CTA --------------------------------------------------------- */
.osat-hp-cta {
    background: var(--osat-primary-color);
    color: var(--osat-light-text-color);
}
.osat-hp-cta__inner {
    display: grid;
    grid-template-columns: 1fr;
    align-items: start;
    gap: clamp(28px, 4vw, 52px);
}
@media (min-width: 960px) {
    .osat-hp-cta__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 480px); }
}
.osat-hp-cta__copy h2 {
    margin: 0 0 var(--osat-spacing-md);
    font-size: clamp(1.55rem, 3.4vw, 2.2rem);
    line-height: 1.2;
    color: var(--osat-light-text-color);
}
.osat-hp-cta__copy p {
    margin: 0 0 var(--osat-spacing-lg);
    max-width: 56ch;
    font-size: 1.03rem;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.88);
}
.osat-hp-cta__list {
    margin: 0;
    padding: 0;
    list-style: none;
}
.osat-hp-cta__list li {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: var(--osat-spacing-sm);
    font-size: 0.99rem;
    font-weight: 600;
}
.osat-hp-cta__list .osat-hp-ico {
    width: 20px;
    height: 20px;
    color: var(--osat-ai-button-color);
}
/* The shared sign-up box (components/signup-box.css) is styled for a light page;
   these overrides sit it on the dark CTA band without touching the partial. */
.osat-hp-cta .osat-signupbox {
    margin: 0;
    background: var(--osat-card-bg);
    color: var(--osat-primary-text-color);
}
.osat-hp-cta .osat-signupbox--loggedin {
    padding: var(--osat-spacing-lg);
    border-radius: var(--osat-border-radius);
    text-align: center;
}

/* Reduced motion: drop the button lift/hover translate. */
@media (prefers-reduced-motion: reduce) {
    .osat-hp-btn,
    .osat-hp-feat__link {
        transition: none;
    }
    .osat-hp-btn--primary:hover,
    .osat-hp-btn--primary:focus-visible,
    .osat-hp-feat__link:hover,
    .osat-hp-feat__link:focus-visible {
        transform: none;
    }
}

/* Divider between the closing CTA and the shared footer — see the note in the template.
   Full-bleed and outside .osat-hp-wrap on purpose: a contained rule would stop short of
   the edges and read as a design element rather than as a separation. */
.osat-hp-endrule {
    height: 6px;
    background: var(--osat-light-gray-bg);
}
