@charset "UTF-8";
/*
Theme Name:   Handy Web Studio Child
Template:     handy-web-studio
Description:  Child theme of Handy Web Studio -- full visual rebrand and redesign. Parent theme left untouched; see functions.php for the enqueue chain that layers this on top of it.
Author:       Handy Web Studio
Author URI:   https://handywebstudio.co.uk
Version:      1.10.3
License:      GNU General Public License v2 or later
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  hanady-web-studio

--------------------------------------------------------------
>>> CHANGELOG
--------------------------------------------------------------
1.10.3 - 111.html: "the images inside [the portfolio cards] are coming
        out cropped." Confirmed from the audit's own screenshot --
        Alina Beauty's "YOUR BEAUTY PLANS." was cropped down to "ONE
        PLACE.", HomeKind's "Cleaning that" down to "fits your move.",
        and VoltBun's logo had its leading "V" sliced off. Root cause:
        .hws-work-card figure img / .hws-carousel-slide img used
        object-fit:cover, and every one of these portfolio photos is a
        designed marketing graphic at a fixed 4:3 ratio (a logo,
        headline and CTA placed deliberately, not a casual photo with
        forgiving edges) forced into this card's 16:10 box -- cover
        crops ~17% of the image's height to fill that wider box, and
        there was no crop-safe margin on several of these designs.
        Switched both rules to object-fit:contain -- guarantees the one
        thing a portfolio card exists to show off (the client's own
        logo/headline) can never be cropped out, at the cost of a thin
        letterbox bar on two sides for a 4:3 image in a 16:10 box; the
        figure's own --hn-soft background already fills that bar so it
        reads as intentional padding, not a rendering gap. Re-verified
        with a rendered screenshot (not just reading the CSS) -- all
        three logos/headlines now sit fully in frame.
        Also: new, cleaner versions of the Alina Beauty / HomeKind
        Cleaning / VoltBun photos (images/a1-5.png, c1-5.png,
        vb1-5.png) replace the previous set at the same
        assets/images/work/<slug>-<n>.jpg paths -- no template changes
        needed. These have no internal padding/blur border around the
        graphic (the previous set did, on some slides), which was
        likely what caused VoltBun's asymmetric left-edge crop
        specifically. Vehicle History Hub's 5 photos are untouched --
        no new set was provided for it this round.
1.10.2 - Two items from this round.
          (1) handywebstudio-carousel-bug.html: "clicking next/prev/dots
          does nothing" on /work/'s 4 portfolio carousels. This time
          verified in an actual rendered browser (Playwright,
          headless Chromium) rather than re-reading the JS, because the
          JS turned out to be correct in isolation -- the bug was pure
          cascade. Root cause: the parent's style.css has
          `.hws-work-card div { display:flex; flex:1; flex-direction:
          column; padding:24px; }`, a broad descendant selector
          (reads like it means .hws-work-card > div, but has no >, so
          it matches every div anywhere inside a work card) written for
          the card's one content wrapper -- it was also landing on
          .hws-carousel-track and every .hws-carousel-slide (also
          divs), forcing them into a column instead of a row, so the
          JS's horizontal translateX() -- already confirmed correct on
          its own -- moved the track on an axis with no visible effect.
          The same rule also inflated .hws-carousel-dots from ~10px to
          ~103px tall (same flex-direction:column + 24px padding),
          which then physically overlapped and intercepted clicks on
          the prev/next buttons -- confirmed with Playwright's real
          elementFromPoint() hit-testing, not just reading the CSS.
          Fixed with !important on every property that selector sets,
          same pattern as the footer-links bug (1.9.3) and the
          round-btn hover bug (1.9.1) -- another (0,1,1)-beats-(0,1,0)
          specificity trap. Re-verified after the fix: real Playwright
          clicks on next/prev/dots now move the track correctly and
          wrap at both ends, and the dots box no longer overlaps the
          arrow buttons.
          (2) manual audit/images: the 20 portfolio photos were
          previously extracted from work-carousels-5x4-tz.pdf itself
          (~420px wide -- the source files it referenced weren't
          available anywhere at the time, see 1.10.0's changelog).
          Real ~1280x960 versions of the same 20 photos, in the same
          order, are now in this folder -- matched to project/slide by
          content (filenames don't follow the 1v.png-style convention
          this time) and spot-verified against two known captions
          before mapping the rest. Resized to 900px wide and
          re-optimised into the same assets/images/work/<slug>-<n>.jpg
          paths, so no template/function changes were needed -- just
          sharper images. Total for all 20 is ~1.3MB, all but the
          first slide per card lazy-loaded. Note: the 5 Vehicle History
          Hub screenshots are real browser captures that include the
          WordPress admin toolbar ("Howdy, Marta Trucevic", Edit Page,
          etc.) baked into the image -- left as-is rather than risk a
          botched crop (the admin-bar row sits at a slightly different
          pixel position in each of the 5), but a clean re-crop is easy
          to do on request if that polish is wanted.
1.10.1 - User feedback, verbatim: "i thought i have clearly asked to
        remove this page title section!!!" -- on a screenshot of
        Contact showing a tall, mostly-empty "CONTACT" banner above the
        page's real heading. Fair: the 1.9.2 fix only restyled
        traveler_inner_banner()'s output (violet block -> plain
        heading + underline) because the audit text it answered
        ("remove the purple block-fill") read as asking for the fill,
        not the whole section -- wrong call. On Services, Work,
        Pricing, About and Contact (the same 5 pages that audit named),
        the banner repeated a generic page title directly above each
        page's own, more specific heading (e.g. "CONTACT" above "Ready
        for your website to start pulling its weight?") and said
        nothing the real heading didn't already say better -- removed
        outright this time, not restyled. Each page's own
        section-title heading is promoted h2 -> h1 so the page keeps
        exactly one h1 (it was the page's real title in substance
        already, just not marked up as one while the banner held that
        role) -- verified one <h1> per page across all 5. The banner
        CSS (.inner-banner-wrap and friends, section 19) is untouched
        and still needed -- ~25 other templates (archives, 404, FAQ,
        blog, etc.) still call traveler_inner_banner() and weren't
        part of this or the original audit's ask.
1.10.0 - work-carousels-5x4-tz.pdf: a 5-photo swipe carousel in each of
        the 4 Work-page portfolio cards, replacing the honest "still
        building this page" placeholder now that there's real content
        for it -- Vehicle History Hub (a real live client site, badge
        "Real live site" + a "View site" link to vehiclehistoryhub.co.uk)
        plus three labelled design concepts: Alina Beauty (beauty
        salon), HomeKind Cleaning (domestic cleaning), VoltBun (burger
        cafe). Photo order per card follows the brief's numbering
        exactly (1v-5v, 1a-5a, 1c-5c, 1vb-5vb).
          - No Elementor in this theme (the brief's brief assumed
            Elementor's built-in carousel widget), so this is a
            framework-free hand-built equivalent: assets/js/
            hanady-theme.js gained initWorkCarousels() -- Pointer
            Events cover mouse-drag, touch swipe and pen in one code
            path, plus prev/next buttons, dots, and arrow-key support.
            New CSS in section 13 (.hws-carousel and friends).
          - The 20 source images (Marta's own filenames per the brief,
            e.g. 1v.png) weren't present as loose files anywhere in
            this project folder -- they only exist embedded in the PDF
            itself, so they were extracted directly from it (matched to
            filenames by on-page position, spot-checked against two
            captions) rather than asking for a resend. Worth flagging:
            the PDF only carries ~420px-wide copies, not Marta's
            original full-resolution files -- fine at the card's own
            display size, but if she has the source PNGs, dropping
            them into assets/images/work/ (same <slug>-<1-5>.jpg
            naming) with no code changes needed would sharpen them on
            larger screens.
          - New functions.php: hanady_work_portfolio_items() (single
            source of truth for the 4 items' copy/links) and
            hanady_render_work_card() ($carousel=true for the full
            5-photo gallery, false for a lighter single-image card) --
            both traveler_gallery CPT-free, since this dev environment
            has no WordPress database to add real entries to.
            traveler_has_work_items()/traveler_render_work_cards() are
            untouched and still take over automatically the moment
            real CPT entries exist in wp-admin, superseding this
            curated array on both the homepage teaser (3 items, no
            carousel, new "See the full portfolio" link to /work/) and
            this Work-page gallery (all 4, full carousel).
1.9.3 - Footer redesign/fix from a user screenshot ("doesn't look like
        it works together"). Two real, compounding bugs, not a caching
        artefact or a matter of taste -- found by reading the parent's
        CSS line by line rather than assuming:
          - Background: .hws-footer only ever coloured the OUTER
            wrapper. Two elements nested inside it (.top-footer,
            .bottom-footer) paint their OWN opaque backgrounds at
            higher specificity, from the parent, and were never
            touched: var(--hws-ink) (#17201f, a dark GREEN with no
            relation to this theme's violet-navy) behind the columns,
            and a third colour (#111817) behind the copyright bar. The
            "gradient band" in the screenshot was just a sliver of the
            correct violet-navy showing through where those two opaque
            boxes don't quite meet -- three unrelated near-black tones
            stacked, not a deliberate design. All three pinned to the
            same --hn-ink token now.
          - Links: nine footer links (everything except whichever one
            happened to be hover/focus in the screenshot) were fully
            invisible -- not low-contrast, IDENTICAL colour to the
            background. Root cause: the 1.7 fix (finding 05, still
            below) matched the wrong parent selector. The real culprit,
            `.handy-web-studio-theme .widget_text ul li a { color:
            var(--hws-ink) }`, matches this footer's actual markup
            (every link sits inside .widget_text) and is EQUALLY
            specific to the 1.7 fix once its "ul li" type selectors are
            counted -- a specificity trap that looks like a tie on a
            glance at class count alone. Switched to !important rather
            than trusting a hand-counted selector match again.
          - Also added a deliberate on-brand :focus-visible outline for
            footer links (was just the browser's unstyled default ring
            before -- not a bug, but worth owning instead of leaving to
            the browser, and it's what the boxed-looking "Free Audit"
            link in the screenshot actually was).
1.9.2 - Second manual audit (manual audit/handy-web-studio-copy-rewrite
        2.html, three items) plus the real founder photo.
          - Item 1: desktop header "FREE AUDIT" had gone low-contrast --
            a regression from 1.9.1's own !important fix (see that
            entry) beating the header-scoped outline-button override,
            which had never needed !important before. Added !important
            there too. Mobile untouched, as the audit asked.
          - Item 2: the full-bleed violet banner on Services/Work/
            Pricing/About/Contact (traveler_inner_banner(), parent,
            non-pluggable) replaced with a plain heading on the page's
            own paper background plus a short violet accent underline,
            matching the audit's mockup. See the long comment above
            .inner-banner-wrap in section 19 for the three parent rules
            this had to out-fight.
          - Item 3: About page's founder block was calling the parent's
            traveler_founder_block() -- fixed markup that was never
            actually configured for this studio, so it rendered literal
            placeholder copy ("Your name", "I would rather tell you we
            are new.", "Add a real founder photo before launch.") to
            every visitor, plus a name/role line low-contrast enough
            against its dark card to be the audit's circled finding.
            Recolouring that one line would have still left "Your name"
            live on the page, so the call was replaced with the same
            real founder section already used on the homepage instead.
          - New: images/owner.jpg processed into a 4:5 portrait crop
            (assets/images/founder-marta.jpg, 640x800, ~70KB) and wired
            up as the DEFAULT founder photo on both the homepage team
            section and the new About founder section (Customizer
            override still wins if one's ever set) -- resolves the
            "add a real founder photo" placeholder on both pages at
            once.
1.9.1 - Real bug, found from a screenshot of the button HOVER state (not
        caching -- verified by reading the parent's own style.css).
        Symptom: "Get your free audit" got an odd glow/ring on hover, and
        the hero's second button ("See what we do") plus the first
        pricing card's "Book this" button went completely blank on hover
        -- text present in the DOM, just invisible.
        Root cause: the parent theme's style.css defines
        `.handy-web-studio-theme .outline-btn:hover, .handy-web-studio-
        theme .outline-btn-white:hover { background: var(--hws-teal);
        color: var(--hws-white); }` -- an ancestor-class selector,
        specificity (0,3,0), beating this file's plain `.outline-btn:hover`
        (0,2,0) on every property except color (which already carried
        !important here). Result: parent's higher-specificity background
        won (solid violet, via the --hws-teal alias in section 37) while
        this file's !important color also won (violet text) -- violet
        text on a violet fill. Parent's `.handy-web-studio-theme
        .round-btn`/`:hover` rules have the same ancestor-class edge and
        were adding a stray 2px border plus swapping the hover fill to a
        flat teal-dark, which produced the ring/glow on the hero CTA.
        Fix: added !important to every background/border/color
        declaration on .round-btn/.outline-btn/.outline-btn-white and
        their :hover/:focus states (section 4) -- !important wins
        regardless of the parent's selector specificity, so this can't
        recur even if a future parent update changes those numbers
        again. The old "belt-and-suspenders" block near the --hws-teal
        alias (section 37) tried to fix the same class of bug by
        matching the parent's specificity, which this incident proved
        isn't reliable (a source-order tie can still go either way) --
        it's been trimmed since every property it set is now also set,
        with !important, in section 4.
1.9.0 - Copy rewrite pass from manual audit/handy-web-studio-copy-rewrite.html
        (2026-09-13, the "live-tone" rewrite with per-block screenshots).
        No CSS changed -- this bump is pure content, applied to make the
        PHP-templated strings match the document exactly. This is a
        content-only bump so the version number stays a reliable diff
        marker between "design changed" and "copy changed" releases.
          - front-page.php: hero eyebrow/H1/subtitle, What We Do H2 +
            subtitle + all 4 service card blurbs, AI demo H2/subtitle +
            3 side points, Work H2/subtitle/empty-state copy, Why-it-
            pays-for-itself (value) card copy, How-it-works 01/02/03,
            Pricing subtitle, Industries subtitle (cards left as-is per
            the doc's own note that they already read well), the founder
            bio (now first-person, names Marta Trusevic explicitly and
            explains the studio/developer split), all 6 FAQ Q&A pairs,
            and the free-audit section's subtitle + report-foot line.
          - page-about.php: paragraph 1 switched to first-person voice
            ("We build and run..."), the 3 value-prop cards (Builds that
            keep moving / AI with approval / One joined-up rhythm), and
            the free-audit block paragraph (sentence order swapped so
            "isn't a sales call" lands second, not first).
          - page-contact.php: subtitle wording ("what's" instead of
            "what is", em dash instead of colon).
          - Left untouched: text inside the parent's traveler_audit_form()
            (Contact/About/Services/Pricing/Work/FAQ/Industries) has
            minor wording drift from the rewrite doc ("We will" vs.
            "We'll" etc.) -- that markup lives in the parent's non-
            pluggable inc/traveler-dynamic.php, so overriding it means
            duplicating the whole form rather than swapping a string.
            Low value for the wording delta involved; skipped unless
            reconsidered.
1.8.1 - Manual audit (2026-09-13) follow-up. Two things, neither of
        which changes what already rendered correctly in this file:
          - This version bump. The child stylesheet is enqueued with
            get_template_directory_uri()'s sibling call using this
            file's own Version header as its ?ver= cache key (see
            functions.php). Editing style.css without bumping this
            number leaves that query string unchanged, so a browser
            or edge cache that already has ?ver=1.8.0 bytes has no
            signal to fetch fresh ones -- exactly the failure mode
            the audit's rendered snapshot pointed at (stale teal/
            6px-radius buttons despite this source already having
            the violet/pill rules below it). Bump this on every edit
            from here on.
          - Section 37 below: a defensive `--hws-teal` alias plus a
            late, high-specificity `.round-btn`/`.outline-btn`
            override. Belt-and-suspenders for the same finding --
            if any cache layer (or a future parent-theme update that
            reintroduces teal somewhere) ever wins the cascade again,
            these force the rebrand back to violet/pill without
            needing another audit to catch it.
1.8.0 - The real logo file replaces the styled-text wordmark. Source
        was an SVG wrapping a single flat-white-background PNG (a
        mascot + "handy web. STUDIO" wordmark). Processed into four
        assets in assets/images/:
          - handy-web-studio-wordmark(-white).png -- a tight crop of
            just the wordmark, for the header and footer (a full
            square lockup doesn't fit a horizontal nav bar at
            readable size).
          - handy-web-studio-logo(-white).png -- the full mascot +
            wordmark lockup, for roomier spots (the coming-soon page).
        The white-background was chroma-keyed to real transparency
        (the source had none), and since the wordmark's "handy"/
        "STUDIO" text is solid black -- illegible on this theme's
        dark sections (the footer, the coming-soon page) -- a second,
        colour-swapped set was produced: black recoloured to white,
        the blue accent and the mascot's skin tone left untouched, so
        the same logo works on light or dark backgrounds without a
        CSS filter hack.
        hanady_brand_markup() (functions.php) now takes $variant
        (light/dark) and $mark (wordmark/logo) and renders an <img>
        instead of text; has_custom_logo() still wins if a real WP
        custom logo is ever set. Header passes light+wordmark (and
        is the only call marked above-the-fold, so it's the one
        instance that loads eager/high-priority -- footer and
        coming-soon load lazily instead of competing with it).
        Footer and the coming-soon page pass dark (footer keeps the
        compact wordmark; coming-soon's roomier centred layout gets
        the full mascot lockup instead).
1.7.1 - "Handy Web Studio -- visuals.pdf": a design-system brief
        (colour/radius/pricing rules) with its own checklist. Several
        items it flagged (green section eyebrows, teal CTA buttons,
        empty footer columns) were verified against the actual code
        and are already correct there -- v3's confirmed ~2-hour
        LiteSpeed/hCDN cache is the far more likely explanation than
        a regression, so those were left alone rather than "fixed"
        a second time over already-correct CSS. Genuine gaps found
        and fixed:
        * FIX: card radius was inconsistent site-wide (18px/28px
          split across two tokens) against the brief's 12-16px rule
          for content cards. Both tokens single-point-fixed to
          14px/16px -- every card sitewide falls in range from one
          edit, buttons/pills unaffected (separate pill token).
        * FIX: the header's "Free Audit" button and the hero's
          "Get your free audit" button were both solid-filled,
          competing for attention in the same viewport -- the
          brief's rule is one solid primary button per screen.
          Header instance now outline, hero stays the one solid CTA.
        * FIX: .outline-btn's border used --hn-line, a very light
          lavender -- genuinely low contrast against the cream page
          background (confirmed by reading the token's value, not
          assumed from a screenshot). Darkened.
        * FIX: the AI-demo reply bubble used the brand gradient;
          brief's rule is gradient reserved for hero-level moments,
          flat colour for UI chrome like a chat bubble. Now solid.
        * FIX: amber was leaking as a plain text colour on the
          founder-role line (page-about.php's parent-rendered
          founder block) rather than staying scoped to badge/status
          roles (MOST CHOSEN badge, the "Drafted" dot) as the brief
          asks. Matched to the violet already used for this same
          role elsewhere.
        * ADDED: service cards' whole area is now clickable (a
          stretched-link pattern -- same technique as Bootstrap's own
          .stretched-link), not just the small "More on..." text,
          per the brief's UX note.
        * ADDED: a "Book this" secondary CTA on every pricing plan,
          linking to Contact (no real checkout/booking system to
          link to instead).
        * CONTENT: founder name defaults to "Marta Trusevic" (full
          name given in the brief).
        * PRICING RESTRUCTURE (the brief's own price list) on both
          the homepage and /pricing/, kept identical as before:
          founding-client rates (GBP900 website, GBP400 AI setup,
          down from the previous figures), and Content and Social
          Run split into three tiers -- Standard/Growth/Premium --
          instead of one flat monthly price. The brief's separate
          add-on rate card (landing pages, site fix-ups, photo/
          AI-video packages) is deliberately NOT added as visible
          pricing lines -- the brief itself says those sell after a
          conversation, not off the page.
        Not touched (already correct, or not a design/code issue):
        the "selected" state on the audit form's business-type
        buttons already exists (:checked + label, added in an
        earlier version); footer Links/Legal/Contact are already
        populated (also an earlier version) -- both likely read as
        broken in the brief's screenshots for the same caching
        reason as the colour findings above.
1.7.0 - "audit manual v3.pdf": a design + responsive pass, plus the
        three still-open items from the previous round.
        HOSTING (not a code fix, flagging prominently): the audit
        confirmed via response headers (x-litespeed-cache: hit,
        x-hcdn-cache-status: HIT, age: 6501) that the live server
        is caching pages for ~2 hours through LiteSpeed and
        Hostinger's hCDN. No theme change can fix an infrastructure
        cache -- both layers need a full purge after this deploy,
        and the caching plugin should be set to purge on save so
        future edits aren't invisible for hours.
        Real code/contrast bugs found and fixed:
        * FIX: footer links were near-invisible -- rgb(23,32,31)
          text on a rgb(22,19,38) footer, ~1:1 contrast. The
          parent's own `.site-footer .footer-menu ul li a { color:
          white }` never matched this theme's markup (.hws-footer-list,
          not .footer-menu), so a different, higher-specificity
          parent rule was winning instead. Matched the parent's own
          selector shape so this reliably wins now.
        * FIX: the audit-example caption ("An example of the format
          you'll receive.") computed to 2.77:1 contrast on the dark
          section, below the 4.5:1 minimum -- same class of
          specificity leak, fixed the same way.
        * FIX: audit-form inputs rendered at 14px, and iOS Safari
          auto-zooms (and does not un-zoom) any input under 16px on
          focus. Forced to 16px on mobile widths.
        * FIX: four tap targets under the 44px minimum (service
          "More on..." links at 24px, mobile menu items at 26px,
          hero chips at 33px, business-type buttons at 39px) --
          padding/min-height added to each, no visual size change
          otherwise.
        Design pass:
        * FIX: Fraunces (the intended heading face) was only
          actually rendering on ~7 elements sitewide -- most
          headings lost the cascade to the parent's own rules and
          rendered in Barlow Condensed anyway. Now declares Barlow
          Condensed directly (already the dominant face at ~60
          elements, already loaded by the parent), and the separate
          Fraunces Google Fonts request is dropped.
        * FIX: most homepage sections never declared an explicit
          background, so they fell through to whichever of the
          parent's own alternating tones that class happened to
          catch -- three near-identical creams and two near-
          identical greens landing next to each other, reading as a
          rendering glitch. Every section now gets one of exactly
          two tokens, strictly alternating, plus Work (previously
          unset entirely) now has one too.
        * FIX: the container gutter was a flat 15px at every width
          (Bootstrap's default), invisible above 1200px but leaving
          cards sitting 15px from the actual screen edge between
          768 and 1200px. Now scales: 20px / 24px (768px+) / 32px
          (992px+).
        * FIX: the pricing grid dropped to an awkward 2+1 layout at
          768px before reaching a full single column. Now skips
          straight from 3 columns to 1 at 992px.
        * FIX: the hero's six industry chips wrapped one per line on
          a phone, costing ~375px of vertical space. Now a
          horizontal scroll strip below 576px.
        Copy (the three still-open items from the previous round):
        * FIX: the homepage Work section's sub-line still said
          "every one of these is live" while showing the honest
          empty-state placeholder, not real cards -- now conditional
          on whether real entries exist.
        * FIX: /work/ (the page the main nav actually links to) was
          completely empty with a sub-line that read as an internal
          instruction ("every item here should be live, real, and
          shown with permission"). Now carries the same honest
          holding state as the homepage when nothing real exists
          yet, with copy that describes an empty list rather than a
          full one.
        * NOT a code fix: the audit's remaining two points --
          AI still carrying more visual weight than websites/
          content/social, and no Instagram/Facebook in the footer --
          both come down to missing real assets (a founder photo, a
          work screenshot) and unset Customizer values (the social
          URLs), not template code. The footer already shows
          Instagram/Facebook the moment those two theme_mods are
          set; nothing to fix there but setting them.
1.6.3 - FIX: every inner-page banner (Pricing, Services, and every
        other page using traveler_inner_banner()) rendered as three
        horizontal stripes -- violet, then a dark block with the
        page title, then violet again -- instead of one continuous
        gradient band. Cause: that markup nests .inner-baner-container
        [sic, parent's own spelling] one level inside the
        .inner-banner-wrap this file already styles; the parent's own
        CSS separately gives that inner container an opaque
        background (var(--hws-ink)) and min-height:240px, so it
        painted a solid dark box, shorter than the outer wrap's own
        padding, in the middle of the gradient. Neutralised the inner
        container's background/min-height so only the outer gradient
        shows -- a single-file fix that corrects every page using
        this banner at once, which is very likely most of what read
        as "no margins" generally: a jarring stripe at the top of
        every inner page colours the impression of the whole page
        below it.
        On the header nav duplication reported again after 1.6.2:
        re-confirmed header.php now makes one unconditional call to
        traveler_primary_menu_fallback() with no branching left at
        all -- the same 5 items render on every single load, deter-
        ministically. Code that can no longer branch can't produce
        an intermittent ("sometimes") result; that pattern points at
        a page cache (a caching plugin, or a CDN/reverse-proxy layer)
        serving an HTML snapshot generated before 1.6.2 was deployed,
        mixed with fresh loads -- worth a full cache purge (plugin
        and any CDN/host-level cache, not just the browser) rather
        than a further code change here.
1.6.2 - header.php: the desktop nav (Services/Work/Pricing/About/
        Contact, plus Free Audit) was rendering every item twice on
        the live site. Root cause: `if ( has_nav_menu('primary') )
        { wp_nav_menu(...) } else { traveler_primary_menu_fallback()
        }` was trusting whatever menu is actually assigned to the
        Primary location in wp-admin, and that admin-configured menu
        has each page added twice. Exactly the same class of problem
        as the footer Links duplication fixed in 1.6.0 (also an
        admin-menu trust issue, also fixed by dropping the
        has_nav_menu() branch) -- and the mobile menu right below
        this one was never affected, because it already calls
        traveler_primary_menu_fallback() unconditionally rather than
        deferring to wp-admin. Desktop nav now does the same: always
        the curated 5-item list, never the admin-assigned menu.
        (No CSS changes this version -- the "What is included / not
        included / How billing works" cards on Pricing are confirmed
        fixed as of 1.6.1, verified against the live page's own
        devtools output.)
1.6.1 - The 1.5.0 column-stretch fix was incomplete: it reset the
        *column's own* display from flex to block (undoing the
        parent's blanket [class*="col-"] rule), but never accounted
        for the column itself still being stretched by `.row`'s own
        flex behaviour (columns are flex ITEMS of .row regardless of
        their own display property, and still get the browser's
        default align-items:stretch from it). A stretched column
        gives height:100% something real to resolve against, so any
        card that still explicitly declared height:100% kept
        stretching regardless of the 1.5.0 fix -- confirmed live on
        the Pricing page's "What is included / not included / How
        billing works" row. .hws-industry-card dodged this only
        because it happened to get height:auto explicitly in the
        same pass; every other non-equal-height card didn't.
        Switched to explicit height:auto (not just relying on the
        column reset) for every card type that isn't deliberately
        equal-height by design: .hws-proof-card, .hws-work-card,
        .hws-search-card, .team-item, .testimonial-item,
        .career-item, .job-description. Kept height:100% only for
        .hws-service-card (Services, intentionally opted back into
        stretch) and .hws-plan-card/.hws-anchor-card (Pricing, sized
        by this stylesheet's own CSS Grid, not a Bootstrap row, and
        already rendering correctly tight).
1.6.0 - All 10 open findings from "audit manual v2.pdf" (a recheck
        against the live site confirming 21 of 31 original points
        landed correctly). Fix-before-launch items first:
1.6.0 - All 10 open findings from "audit manual v2.pdf" (a recheck
        against the live site confirming 21 of 31 original points
        landed correctly). Fix-before-launch items first:
        * FIX: Work had gone completely missing on the homepage.
          It was gated behind `has_work_items(2) OR is_admin`, so
          with zero real entries it vanished for every ordinary
          visitor -- and once the fabricated Proof section was
          removed in 1.3, that left the homepage with nothing
          proving the studio has built anything. The section now
          always renders: real cards once 2+ entries exist, and
          until then an honest bridge naming the one real,
          verifiable project the audit itself named
          (VehicleHistoryHub) with no invented results and no
          fabricated URL, pointing at the free audit instead. A
          visible admin-only note spells out exactly what to add
          (VehicleHistoryHub live, VoltBun concept, one more
          concept in a non-food niche).
        * FIX: page-package.php called the parent's
          traveler_pricing_anchor(), which prints its own literal
          unset default -- "GBP X to GBP Y" -- live on the pricing
          page, directly contradicting the homepage's real anchor
          figures. Replaced with the same static anchor cards the
          homepage uses, reading the same hanady_price_* settings,
          so the two pages can no longer disagree.
        * FIX: "Add a real founder photo before launch." and the
          footer's "trading details to be confirmed before
          launch." were both internal reminders rendering to every
          visitor. The founder photo fallback is now a branded
          initial avatar with the reminder moved to an admin-only
          note; the footer legal line is now omitted entirely
          until a real value is set, instead of showing the
          parent's placeholder default.
        * FIX: "replies handled" survived on the homepage pricing
          card and the (now-replaced) pricing-page card text after
          being fixed on the service card in 1.5.
        Worth-doing and minor items:
        * ADDED: a sixth industry card, Property & lettings,
          exact audit wording, plus a matching hero chip link --
          also evens the grid to 2 full rows of 3.
        * FIX: footer Links no longer falls back to a real
          wp-admin-assigned nav menu that was duplicating the
          curated Legal column's three links under a different
          name (Privacy Notice vs Privacy Policy). Links is now
          always the same five curated items regardless of menu
          state.
        * ADDED: Instagram and Facebook to the footer Contact
          column (reads the same theme_mods the icon row already
          uses -- both go live once real URLs are set).
        * FIX: the AI demo still read "Saffron Kitchen" after the
          audit example next to it was correctly de-branded to
          "Example website audit -- Restaurant" -- now "Try it ·
          Example Restaurant" throughout.
        * FIX: the services sub-line ("...cannot live inside the
          inbox") still framed the offer as maintenance/automation
          after the headline and all four cards were rewritten to
          lead with building -- replaced so nothing on the page
          contradicts that framing anymore.
1.5.0 - Found and fixed the actual root cause of the card-height
        bug the last two versions failed to fully clear. The
        parent theme's OWN style.css (untouched, but read in full
        this time) carries:
            .hws-equal-grid > [class*="col-"],
            .row > .hws-service-card-col { display:flex; margin-bottom:24px; }
        an attribute-CONTAINS selector matching any class merely
        containing "col-" -- so it turns *every* Bootstrap column
        on the entire site into a flex container, unconditionally,
        stacked on top of `.row` already being flex with the
        browser default align-items:stretch. That combination is
        what stretched a card to match a taller row-mate -- not
        any height property in this stylesheet or the parent's own
        per-card rules (which also exist further down the same
        parent file: .hws-industry-card, .hws-proof-card, and
        .hws-process-item > span all separately carry height/size
        values there too). Clearing height:100% from individual
        child classes in 1.3.1/1.4.0 could never have been enough,
        because the *column wrapping the card* was independently
        forcing its child to stretch regardless of what height the
        card itself declared -- a instance of the general child-
        theme trap (skill "wordpress-child-theme" §6): a same-
        specificity rule you don't fully redeclare stays partially
        in effect no matter how many of ITS properties you patch.
        Fixed at the source instead of per-component:
        * .row > [class*="col-"] reset to display:block, undoing
          the parent's blanket rule everywhere, then re-opted back
          into flex+stretch ONLY for .hws-equal-grid (Services) and
          .hws-service-card-col, matching the one place equal
          height is actually wanted and matches the parent's own
          apparent original intent for that specific grid.
        * row-gap added to .row generally, replacing the vertical
          spacing the removed margin-bottom used to provide when a
          row wraps onto a second line (Industries' five cards at
          three-per-row) -- a no-op on any row that never wraps.
        * .hws-process-item's numeral (01/02/03) had the same
          problem one level deeper: the parent's own same-
          specificity `.hws-process-item > span` rule sets a fixed
          72x72px box, inline-flex, centered, teal -- properties
          this stylesheet's text-only version of that rule never
          touched kept leaking through regardless of font/color
          overrides. Rebuilt as a proper 52px circular gradient
          badge with every property the parent sets now explicitly
          redeclared, so nothing is left to leak.
        * .hws-industry-card also gets explicit height:auto and
          margin-bottom:0 for the same reason, belt-and-suspenders
          on top of the column-level fix above.
        This also very likely explains the "empty footer columns"
        look from an earlier review that was previously (wrongly)
        chalked up to caching -- footer widget columns are
        Bootstrap columns too, and were subject to the exact same
        parent rule.
1.4.0 - Polish pass. NOTE FIRST: a round of screenshots this version
        was built against showed a teal "Free Audit" button and a
        green-tinted footer background -- neither color exists
        anywhere in this stylesheet (verified: one .round-btn color
        rule, gradient violet; --hn-ink is #161326, not green).
        That points to a stale cached stylesheet or the child theme
        not being the fully active one wherever those were captured
        -- see the version's hand-back notes for what to check.
        Design refinements applied on top, independent of that:
        * Hero chip list (industry links under the hero copy)
          restyled from bordered white pills to softer tinted tags
          -- lighter, less "boxy" against the uneven flex-wrap row
          they sit in.
        * Footer widget titles (Links/Contact/Legal) get a small-caps
          treatment with their own underline, so each column reads
          as a defined block even when it has few items -- reduces
          the "empty-looking" impression a short column gives next
          to the longer logo/description column.
        * A 3px gradient accent line added along the top edge of the
          footer, tying it to the same violet identity as buttons
          and badges elsewhere on the page.
1.3.1 - Card-height fixes from desktop screenshot review:
        * FIX: .hws-industry-card kept height:100% on desktop. With
          5 cards at 3-per-row, the last row has only 2 -- flexbox
          stretch operates per wrapped line, so that line stretched
          to match whichever of the two had the longer description,
          leaving visible empty space under the shorter card. Five
          differently-worded category blurbs will never line-wrap
          identically, so these now hug their own content instead
          (kept for service/plan/work cards, whose content lengths
          are close enough by design that stretch reads as tidy
          rather than wasteful). "Professional services" copy also
          shortened so its line count sits closer to its row-mate.
        * FIX: the process steps' numeral (01/02/03) was centered
          against the full row height, so on a two-line card it
          landed between the heading and the paragraph rather than
          level with its own heading. Back to top-aligned, with a
          small margin so it optically lines up with the heading's
          cap-height regardless of paragraph length.
1.3.0 - Rebuilt against "audit manual.pdf" (a full written review):
        * FIX (brand): every visible string previously read "Hanady
          Web Studio" -- a typo carried from an early clarifying
          answer. Corrected to Handy Web Studio (same as the
          parent) everywhere: logo, headings, meta, copy, footer.
          Theme Name changed to "Handy Web Studio Child" so it
          reads correctly in the WP admin theme list without
          colliding with the parent's own name.
        * REMOVED (honesty): the entire v1.1 "Proof" section --
          fabricated stats (14 UK businesses / 6,200 enquiries /
          4h-to-9min) and three named testimonials that never
          existed, and which even contradicted the empty Work
          section right below it. Work's existing behaviour
          (hidden until 2+ real entries exist) is the honest
          version of proof until real case studies are added.
        * FIX (honesty): the sample audit-report card claimed "A
          real audit -- business name and figures changed" for a
          mockup with invented prices. Relabelled as an explicit
          example, genericised, prices replaced with priority
          tags.
        * REWRITE (copy): hero headline + subhead, three of four
          service cards, the value-section cards + heading, the
          industries cards + heading (with matching anchor IDs
          updated in the hero's chip list), the team section's
          intro copy (including a corrected founder bio that no
          longer overstates personal technical involvement), and
          the six-item objections list -- all per specific
          rewrites in the audit. See the inline comment above
          each section in front-page.php for the individual
          rationale.
        * REMOVED: "taking on my first three clients at a reduced
          rate" off the homepage (kept on the dedicated First
          Clients page) -- the audit's read: fine for a personal
          outreach email, undersells positioning as permanent
          homepage copy.
        * FIX: audit-section heading/subhead said "Three fields"
          and "the two details" in the same breath.
        * REMOVED: the footer newsletter block entirely (no
          audience yet for it, and it competed with the page's
          actual conversion goal, the free audit). Footer Links
          rebuilt as its own list (Services/Work/Pricing/Free
          Audit/About) instead of mirroring the primary nav;
          Legal trimmed to Privacy/Cookies/Terms. Footer row gets
          align-items-start so uneven columns don't stretch and
          leave empty space under a shorter one.
        * Orphaned "Proof section stats" Customizer controls
          removed from functions.php along with the section that
          used them.
1.2.2 - More fixes from real mobile screenshots (proof quotes,
        value cards, process steps):
        * FIX: the parent's global `blockquote:before` (a
          FontAwesome quote glyph, z-index:-1, tuned for its own
          pale quote-block background) painted visibly behind
          the opening words on the new dark/violet proof-quote
          cards, since a negative z-index only clears its own
          card's background, not the text above it. Neutralized
          from the child with a higher-specificity selector --
          no parent edit needed.
        * FIX: height:100% on the card grids (proof cards,
          service/work/plan/industry cards, team/testimonial/
          career items) is only meaningful side by side in a
          Bootstrap row -- it stretches every column to the
          tallest one. Below 992px, once everything stacks to a
          single column, that stretch could still size a card to
          match a taller sibling it's no longer next to, leaving
          a slab of empty space under its own text. Auto below
          that breakpoint.
        * IMPROVED: the numbered process steps (01/02/03) now
          center-align against their text instead of pinning to
          the top of a taller row, reading less like leftover
          space next to the number.
1.2.1 - Fixes from a real iPhone screenshot review:
        * FIX: header actions (phone icon + "Free Audit" button
          + hamburger) didn't fit a real ~375-390px screen with
          any room -- the button is also redundant there, since
          .hws-mobile-menu already carries its own full-size
          "Free Audit" CTA. Hidden below 992px.
        * FIX: the hero kicker is a 13-word sentence in a pill
          component; wrapped across 2-3 lines on a phone, the
          pill's background renders as a heavy solid band (a
          wrapped inline background clips per line, not per
          element). Below 576px it drops the pill chrome and
          becomes plain small-caps "eyebrow" text instead.
        * FIX: the hero SVG's embedded text labels are sized for
          its ~600px desktop render; scaled to an actual phone
          width they shrink to ~6-8px and become unreadable.
          The (purely decorative) illustration is now hidden
          below 768px instead of shipping illegible text.
1.2.0 - Responsive + best-practices hardening pass:
        * FIX: .hws-primary-nav (the desktop link list) was
          never hidden below 992px, so it rendered at full
          width alongside the hamburger on every tablet/phone
          -- the main cause of the layout breaking on small
          screens. Now hidden until the desktop breakpoint.
        * FIX: the hamburger icon's three bars had no width,
          so the mobile-menu toggle button was invisible.
        * ADDED: a low-specificity `img, svg, video, iframe {
          max-width:100%; height:auto }` default so any
          unstyled <img> (post thumbnails, inline the_content()
          images) can no longer overflow its container on
          narrow screens -- the theme's own higher-specificity
          cover-fit rules are unaffected.
        * ADDED: horizontal-scroll fallback for tables not
          already wrapped in .table-responsive, animated
          hamburger -> X, 44px touch targets on the mobile
          header buttons, a small-screen (<=480px) header
          tightening pass, and a global :focus-visible ring
          for keyboard navigation.
1.1.0 - Homepage additions from the audit-notes mockup: proof
        section (stats + testimonials replacing the flat proof
        strip), AI-demo chat block, anchor-priced pricing cards
        + trust strip, redesigned audit section with a sample
        findings card, team section with a six-question
        objections list. See section 36 below.
1.0.0 - Initial rebuild.

--------------------------------------------------------------
>>> TABLE OF CONTENTS
--------------------------------------------------------------
1.  Design tokens
2.  Fonts + base typography
3.  Layout primitives (section, container helpers)
4.  Buttons
5.  Motion / scroll-reveal
6.  Site loader
7.  Header + nav
8.  Mobile menu
9.  Hero (front page + Studio Hero template)
10. Proof strip / stat rows
11. Section heading
12. Service cards + service detail
13. Work / gallery cards
14. Value + process
15. Pricing / plan cards + plan detail
16. Industries / destination cards
17. Founder block
18. Final audit / CTA sections + forms
19. Inner banner (page header)
20. Generic page section + proof card
21. About page
22. Contact page
23. Team + testimonials
24. Careers (archive, detail, apply form)
25. FAQ accordion
26. Legal content
27. Search page + search form + archives/blog
28. Confirmation / checklist / cart flow pages
29. 404
30. Coming soon
31. Footer
32. Back to top
33. Tabs / accordion (career detail)
34. Tables
35. Utility + responsive
36. Homepage additions (v1.1): proof, AI demo, pricing anchors,
    audit-on-page, team + objections
--------------------------------------------------------------
*/

/* ==========================================================================
   1. Design tokens
   ========================================================================== */
:root {
	--hn-ink: #161326;
	--hn-ink-soft: #2a2545;
	--hn-muted: #5b5770;
	--hn-paper: #faf9f6;
	--hn-soft: #f1eefb;
	--hn-line: #e3ddf5;
	--hn-white: #ffffff;
	--hn-violet: #5b3df0;
	--hn-violet-dark: #4127c4;
	--hn-violet-light: #9b7bff;
	--hn-amber: #f2a541;
	--hn-amber-dark: #d98a26;
	--hn-gradient: linear-gradient(135deg, var(--hn-violet) 0%, #9b5de5 100%);
	--hn-gradient-warm: linear-gradient(135deg, var(--hn-amber) 0%, #f2764a 100%);
	--hn-shadow-sm: 0 2px 10px rgba(22, 19, 38, 0.06);
	--hn-shadow-md: 0 12px 32px rgba(22, 19, 38, 0.10);
	--hn-shadow-lg: 0 24px 60px rgba(22, 19, 38, 0.16);
	--hn-shadow-violet: 0 14px 34px rgba(91, 61, 240, 0.28);
	--hn-radius-sm: 10px;
	/* v1.7.1 (design-system brief): the brief's rule is explicit --
	   buttons/pills stay pill (9999px, unchanged below), but "large
	   content cards (previews, service cards)" should share one soft
	   12-16px radius, not the 18px/28px split these two tokens carried
	   before. Both single-point-fixed here rather than touched per class
	   (36 usages of --hn-radius-lg, 11 of --hn-radius-md) -- every card
	   sitewide now falls inside that range with one edit. */
	--hn-radius-md: 14px;
	--hn-radius-lg: 16px;
	--hn-radius-pill: 999px;
	/* v1.7 (audit v3, finding 10): Fraunces was the intended display face,
	   but it was only actually rendering on ~7 elements sitewide -- most
	   headings were losing the cascade to the parent's own, higher-
	   specificity heading rules and rendering in Barlow Condensed anyway
	   (already dominant at ~60 elements, already loaded by the parent's
	   own font enqueue). Rather than fight that cascade everywhere headings
	   appear, this now names what's actually rendering, and the separate
	   Fraunces Google Fonts request is dropped in functions.php --
	   one fewer render-blocking request, and every heading now reliably
	   matches instead of a handful looking different from the rest. */
	--hn-font-display: "Barlow Condensed", Arial, sans-serif;
	--hn-font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	--hn-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ==========================================================================
   2. Fonts + base typography
   ========================================================================== */

/* Root-cause fix, not a per-component patch: the PARENT theme (its own
   pre-existing style.css, not this child) carries
   `.hws-equal-grid > [class*="col-"], .row > .hws-service-card-col {
   display:flex; margin-bottom:24px; }` -- an attribute-CONTAINS selector
   that turns every Bootstrap column whose class merely contains "col-"
   into a flex container, site-wide, unconditionally. Combined with `.row`
   itself being flex with the browser's default `align-items:stretch`,
   that's what actually stretches a card to match a taller row-mate --
   not any `height` property in this stylesheet or the parent's own
   per-card rules (.hws-industry-card, .hws-proof-card, etc. all also
   carry their own height:100% deeper in the parent's file, but even
   clearing that per class was never enough, because the *column*
   wrapping the card was independently forcing its child to stretch
   regardless of what height the card itself asked for). Same specificity
   (class + attribute selector) and this file loads after the parent's, so
   resetting it here is authoritative -- reset broadly first, then
   opt back in only where equal height is actually wanted (Services). */
.row > [class*="col-"] {
	display: block;
	margin-bottom: 0;
}

.row.hws-equal-grid > [class*="col-"],
.row > .hws-service-card-col {
	display: flex;
	margin-bottom: 1.5rem;
}

/* The removed margin-bottom above was also the only thing providing
   vertical spacing once a .row wraps onto a second line (e.g. Industries'
   five cards at three-per-row). row-gap replaces it correctly -- it only
   ever inserts space *between* wrapped lines, so it's a no-op on any .row
   that never wraps (the hero, header-inner, etc. are unaffected). */
.row {
	row-gap: 1.75rem;
}

html {
	overflow-x: hidden;
}

body,
.handy-web-studio-theme {
	background: var(--hn-paper);
	color: var(--hn-ink);
	font-family: var(--hn-font-body);
	font-size: 16px;
	line-height: 1.65;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

/* Fluid media -- low-specificity default so any unstyled <img> (post
   thumbnails via the_post_thumbnail(), inline the_content() images with
   hardcoded width/height attributes) never overflows its container. The
   theme's own cover-fit treatments (.team-image img, .hws-work-card figure
   img, etc.) all use a class + descendant selector, so their higher
   specificity still wins over this without any !important. */
img,
svg,
video,
iframe {
	max-width: 100%;
	height: auto;
}

/* Any table not already wrapped in a scroll container (most are, via
   .table-responsive; a couple on the confirmation/checklist pages are not)
   gets a horizontal-scroll fallback instead of forcing the page to overflow. */
@media (max-width: 575.98px) {
	table.table {
		display: block;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}
}

/* Visible keyboard-focus ring everywhere interactive, without adding a
   mouse-click outline (:focus-visible only fires for keyboard/programmatic
   focus in evergreen browsers). */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
	outline: 2px solid var(--hn-violet);
	outline-offset: 3px;
}

/* v1.7 (audit v3, finding 06): the parent theme sets a 14px base font-size
   on form controls in several scattered rules (audit panel, form-grid,
   apply-form, inquiry-form...), each of which would need matching or
   higher specificity to override individually. iOS Safari auto-zooms any
   input under 16px on focus and does not zoom back out on blur, leaving a
   visitor stuck on a magnified, sideways-scrolling page mid-form -- a
   real functional bug, not a cosmetic one, so a single !important rule
   scoped to mobile widths (where the zoom behaviour actually happens;
   desktop is untouched) is the pragmatic fix here rather than chasing
   every parent selector's specificity across a dozen different forms. */
@media (max-width: 767.98px) {
	input,
	select,
	textarea {
		font-size: 16px !important;
	}
}

h1, h2, h3, h4, h5, h6,
.section-title,
.banner-title,
.page-title {
	font-family: var(--hn-font-display);
	color: var(--hn-ink);
	font-weight: 600;
	line-height: 1.15;
	letter-spacing: -0.01em;
}

p {
	color: var(--hn-muted);
}

a {
	color: var(--hn-violet);
	text-decoration: none;
	transition: color 0.2s var(--hn-ease);
}

a:hover,
a:focus {
	color: var(--hn-violet-dark);
}

::selection {
	background: var(--hn-violet);
	color: var(--hn-white);
}

.sub-title {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	font-family: var(--hn-font-body);
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--hn-violet);
	margin-bottom: 0.9rem;
}

.sub-title::before {
	content: "";
	width: 22px;
	height: 2px;
	background: var(--hn-gradient);
	border-radius: 2px;
	display: inline-block;
}

.section-title {
	font-size: clamp(1.7rem, 1.2rem + 2vw, 2.6rem);
	margin-bottom: 0.9rem;
}

/* ==========================================================================
   3. Layout primitives
   ========================================================================== */
.container {
	max-width: 1200px;
	/* v1.7 (audit v3, finding 12): Bootstrap's own gutter is a flat 15px at
	   every width -- invisible above 1200px since content is capped and
	   centred there, but between 768 and 1200px there's no cap, so cards
	   sat 15px from the actual screen edge (3px in from the edge at
	   1024px once borders/shadows are accounted for). Scales properly now:
	   20px below 768px, up to 32px from 768px. */
	padding-left: 20px;
	padding-right: 20px;
}

@media (min-width: 768px) {
	.container {
		padding-left: 24px;
		padding-right: 24px;
	}
}

@media (min-width: 992px) {
	.container {
		padding-left: 32px;
		padding-right: 32px;
	}
}

section,
.hws-page-section,
.hws-plans-section,
.hws-services-section,
.hws-work-section,
.hws-value-section,
.hws-process-section,
.hws-sector-section,
.hws-final-audit-section {
	padding: clamp(3.5rem, 3rem + 2vw, 6rem) 0;
}

.hws-soft-section {
	background: var(--hn-soft);
}

.hws-page-section + .hws-page-section {
	padding-top: 0;
}

/* v1.7 (audit v3, finding 11): most homepage sections never declared an
   explicit background, so they fell through to whatever the parent's own
   alternating-section scheme happened to give that particular class --
   sometimes the body's cream, sometimes one of the parent's own mint-
   green tones. The audit's own read: "three near-identical creams, and
   two greens about 2% apart sitting directly on top of each other -- a
   seam that reads as a rendering glitch, not a change of section." Every
   homepage section below now gets one of exactly two tokens (cream/paper
   or lilac/soft), strictly alternating so no two adjacent sections ever
   match, plus the one dark section (audit CTA) at the very end. This also
   gives Work an explicit background for the first time -- it previously
   had none, so it fell through to plain body cream between the lilac AI
   block above it and whatever green the Value block below it happened to
   render. */
.hws-services-section,
.hws-value-section,
.hws-plans-section {
	background: var(--hn-paper);
}

.hws-work-section,
.hws-process-section,
.hws-sector-section {
	background: var(--hn-soft);
}

.hws-demo-section {
	background: var(--hn-paper);
}

/* ==========================================================================
   4. Buttons
   ========================================================================== */
/* v1.9.1: every rule in this section now carries !important on
   background/border/color. Root cause (found from a user screenshot of
   the HOVER state): the parent's own style.css defines
   `.handy-web-studio-theme .outline-btn:hover, .handy-web-studio-theme
   .outline-btn-white:hover { background: var(--hws-teal); color:
   var(--hws-white); }` -- two ancestor+class selectors, specificity
   (0,3,0), beating this file's plain `.outline-btn:hover` (0,2,0) on
   every property EXCEPT color, which already carried !important here.
   Net result: parent's higher-specificity background won (solid violet,
   via the --hws-teal alias below) while this file's !important color
   also won (violet text) -- violet text on a violet fill, i.e. the
   invisible "blank pill" button. Parent's `.handy-web-studio-theme
   .round-btn` rules have the same ancestor-class edge and were adding a
   stray 2px solid border plus swapping the hover fill to a flat
   teal-dark (aliased to violet-dark), which is what produced the odd
   glow/ring around "Get your free audit" on hover. !important on every
   contested property here makes this file win regardless of the
   parent's selector specificity, so the belt-and-suspenders block
   further down (originally added for the same class of bug) has been
   trimmed to just the border-radius alias -- see that section. */
.round-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.95em 1.9em;
	background: var(--hn-gradient) !important;
	color: var(--hn-white) !important;
	font-weight: 700;
	font-size: 0.95rem;
	border: none !important;
	border-radius: var(--hn-radius-pill) !important;
	box-shadow: var(--hn-shadow-violet);
	transition: transform 0.25s var(--hn-ease), box-shadow 0.25s var(--hn-ease), filter 0.25s var(--hn-ease);
	cursor: pointer;
}

.round-btn:hover,
.round-btn:focus {
	transform: translateY(-3px);
	box-shadow: 0 20px 44px rgba(91, 61, 240, 0.36);
	filter: brightness(1.04);
	background: var(--hn-gradient) !important;
	border: none !important;
	color: var(--hn-white) !important;
}

.outline-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.9em 1.85em;
	background: transparent !important;
	color: var(--hn-ink) !important;
	font-weight: 700;
	font-size: 0.95rem;
	/* v1.7.1 (design-system brief): was 2px solid var(--hn-line), a very
	   light lavender (#e3ddf5) border on the cream page background --
	   genuinely low contrast, not a cache artefact (confirmed by reading
	   the token's own value). "SEE WHAT WE DO" was the flagged instance,
	   but this is the shared .outline-btn rule, so every use of the
	   secondary button sitewide gets the fix at once. */
	border: 2px solid var(--hn-ink) !important;
	border-radius: var(--hn-radius-pill) !important;
	transition: border-color 0.2s var(--hn-ease), transform 0.2s var(--hn-ease), background 0.2s var(--hn-ease), color 0.2s var(--hn-ease);
}

.outline-btn:hover,
.outline-btn:focus {
	border: 2px solid var(--hn-violet) !important;
	background: var(--hn-soft) !important;
	transform: translateY(-2px);
	color: var(--hn-violet) !important;
}

.outline-btn-white {
	border: 2px solid rgba(255, 255, 255, 0.4) !important;
	color: var(--hn-white) !important;
}

.outline-btn-white:hover,
.outline-btn-white:focus {
	background: rgba(255, 255, 255, 0.12) !important;
	border: 2px solid var(--hn-white) !important;
	color: var(--hn-white) !important;
}

button.round-btn,
button.outline-btn {
	font-family: inherit;
}

/* ==========================================================================
   5. Motion / scroll-reveal (paired with assets/js/hanady-theme.js)
   ========================================================================== */
[data-reveal] {
	opacity: 0;
	transform: translateY(28px);
	transition: opacity 0.7s var(--hn-ease), transform 0.7s var(--hn-ease);
}

[data-reveal].is-visible {
	opacity: 1;
	transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
	[data-reveal] {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* ==========================================================================
   6. Site loader
   ========================================================================== */
.site-loader {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--hn-ink);
	transition: opacity 0.5s var(--hn-ease), visibility 0.5s var(--hn-ease);
}

.site-loader.is-hidden {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

.preloader-content {
	position: relative;
}

.hws-loader-mark {
	font-family: var(--hn-font-display);
	font-size: 1.4rem;
	font-weight: 700;
	letter-spacing: 0.18em;
	color: var(--hn-white);
	padding: 0.6em 1.1em;
	border: 1px solid rgba(255, 255, 255, 0.25);
	border-radius: var(--hn-radius-pill);
	background: var(--hn-gradient);
	animation: hn-pulse 1.4s var(--hn-ease) infinite;
}

@keyframes hn-pulse {
	0%, 100% { transform: scale(1); }
	50% { transform: scale(1.06); }
}

/* ==========================================================================
   7. Header + nav
   ========================================================================== */
.hws-header {
	position: sticky;
	top: 0;
	z-index: 500;
	background: rgba(250, 249, 246, 0.86);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	border-bottom: 1px solid var(--hn-line);
	transition: box-shadow 0.3s var(--hn-ease);
}

.hws-header.is-stuck {
	box-shadow: var(--hn-shadow-sm);
}

.hws-header-inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	padding: 1rem 0;
}

.site-logo a,
.hws-text-logo {
	display: inline-flex;
	align-items: baseline;
	gap: 0.15em;
	font-family: var(--hn-font-display);
	font-size: 1.4rem;
	font-weight: 700;
	color: var(--hn-ink);
}

.hws-logo-main span {
	background: var(--hn-gradient);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

.custom-logo {
	max-height: 46px;
	width: auto;
}

/* v1.8: the real logo file (hanady_brand_markup(), functions.php) --
   header height by default; .footer-logo and the coming-soon page's
   larger full-lockup context override this below. width/height attributes
   on the <img> itself (1244x260 / 600x600) keep the aspect ratio without
   layout shift; this just caps the rendered height. */
.hws-image-logo img {
	height: 40px;
	width: auto;
	max-width: 100%;
}

.hws-primary-nav {
	display: none;
	flex: 1;
	justify-content: center;
}

/* The desktop link list only ever shows at the desktop breakpoint -- below
   that, the hamburger + .hws-mobile-menu (already built and wired to JS in
   the parent's hws-theme.js) is the only nav, matching the toggle button's
   own visibility rule further down. Without this, the full link list and
   the hamburger both rendered at once below 992px -- the main cause of the
   layout breaking on tablet/phone widths. */
@media (min-width: 992px) {
	.hws-primary-nav {
		display: flex;
	}
}

.hws-nav-list {
	display: flex;
	align-items: center;
	gap: 2rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.hws-nav-list a {
	position: relative;
	font-weight: 600;
	font-size: 0.95rem;
	color: var(--hn-ink-soft);
	padding: 0.3em 0;
}

.hws-nav-list a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 100%;
	bottom: -2px;
	height: 2px;
	background: var(--hn-gradient);
	border-radius: 2px;
	transition: right 0.3s var(--hn-ease);
}

.hws-nav-list a:hover,
.hws-nav-list a:focus,
.hws-nav-list li.current-menu-item a {
	color: var(--hn-violet);
}

.hws-nav-list a:hover::after,
.hws-nav-list a:focus::after,
.hws-nav-list li.current-menu-item a::after {
	right: 0;
}

.hws-header-actions {
	display: flex;
	align-items: center;
	gap: 1rem;
}

/* v1.7.1 (design-system brief): the header's "Free Audit" button used the
   same solid, filled .round-btn as the hero's "Get your free audit" --
   the brief's rule is one solid primary button per screen, and these two
   sit in the same viewport on first load. Scoped to the header context
   only (not the shared .round-btn class, which stays solid everywhere
   else it's used -- forms, other CTAs) so just this one instance drops
   to an outline, leaving the hero's button as the sole solid CTA. */
/* v1.9.2 (manual audit 2, item 1): "FREE AUDIT" in the desktop header
   went low-contrast -- a self-inflicted regression from v1.9.1. That
   fix put !important on .round-btn's base background (to beat the
   parent's higher-specificity hover rule -- see the comment above
   section 4's .round-btn), but this header-scoped override, which
   turns the shared solid .round-btn into an outline button, had never
   needed !important before because its extra .hws-header-actions
   ancestor class already out-specified the old non-important base rule.
   !important always beats a non-important declaration regardless of
   specificity, so the base rule's gradient started winning here too --
   filling this button solid violet while its text stayed violet
   (already !important), same invisible-on-itself effect as the
   original bug. Fixed the same way: !important on every property that
   needs to survive against the base rule. */
.hws-header-actions .round-btn {
	background: none !important;
	border: 2px solid var(--hn-violet) !important;
	color: var(--hn-violet) !important;
	box-shadow: none !important;
}

.hws-header-actions .round-btn:hover,
.hws-header-actions .round-btn:focus {
	background: var(--hn-soft) !important;
	border: 2px solid var(--hn-violet) !important;
	transform: translateY(-2px);
	box-shadow: none !important;
	filter: none;
	color: var(--hn-violet-dark) !important;
}

.hws-phone-link {
	font-weight: 700;
	font-size: 0.9rem;
	color: var(--hn-ink);
	display: none;
}

.hws-mobile-phone {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: var(--hn-radius-pill);
	background: var(--hn-soft);
	color: var(--hn-violet) !important;
	flex-shrink: 0;
}

.hws-menu-toggle {
	display: inline-flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	gap: 5px;
	width: 44px;
	height: 44px;
	flex-shrink: 0;
	border: none;
	background: transparent;
	cursor: pointer;
}

/* :not(.screen-reader-text) matters here: the button's first span is the
   visually-hidden "Open menu" label (header.php), not a hamburger bar --
   without the exclusion this rule would both misdraw that label as a
   visible bar and out-specificity the parent's .screen-reader-text hiding
   (a class+descendant selector beats parent's single-class one). */
.hws-menu-toggle span:not(.screen-reader-text) {
	display: block;
	width: 22px;
	height: 2px;
	background: var(--hn-ink);
	border-radius: 2px;
	transition: transform 0.25s var(--hn-ease), opacity 0.25s var(--hn-ease);
}

/* Animated hamburger -> X once the parent's hws-theme.js flips
   aria-expanded="true" on click (it toggles nothing else, so the visual
   state change has to live entirely in CSS). nth-child counts the sr-only
   label as child 1, so the three bars are children 2-4. */
.hws-menu-toggle[aria-expanded="true"] span:nth-child(2) {
	transform: translateY(7px) rotate(45deg);
}
.hws-menu-toggle[aria-expanded="true"] span:nth-child(3) {
	opacity: 0;
}
.hws-menu-toggle[aria-expanded="true"] span:nth-child(4) {
	transform: translateY(-7px) rotate(-45deg);
}

@media (min-width: 992px) {
	.hws-phone-link { display: inline-flex; }
	.hws-mobile-phone, .hws-menu-toggle { display: none; }
}

/* Below the desktop breakpoint the header's own "Free Audit" button is
   redundant -- .hws-mobile-menu (header.php) already carries the same CTA
   at full size once opened -- and keeping it, alongside the phone icon and
   the hamburger, doesn't leave enough room on a real ~375-390px phone.
   Dropping it here leaves just the phone shortcut (when set) + hamburger. */
@media (max-width: 991.98px) {
	.hws-header-actions > .round-btn {
		display: none;
	}
}

@media (max-width: 480px) {
	.hws-header-inner { gap: 0.65rem; }
	.hws-header-actions { gap: 0.5rem; }
	.site-logo a, .hws-text-logo { font-size: 1.18rem; }
	.hws-image-logo img { height: 32px; }
}

/* ==========================================================================
   8. Mobile menu
   ========================================================================== */
.hws-mobile-menu {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	padding: 1.25rem 0 1.5rem;
	border-top: 1px solid var(--hn-line);
}

.hws-mobile-menu[hidden] {
	display: none;
}

.hws-mobile-nav-list {
	list-style: none;
	margin: 0 0 1rem;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.9rem;
}

.hws-mobile-nav-list a {
	/* v1.7 (audit v3, finding 07): measured at 26px tall, well under the
	   44px touch-target minimum -- padding, not font-size, per the
	   audit's own suggested fix. */
	display: block;
	padding: 12px 0;
	font-weight: 600;
	font-size: 1.05rem;
	color: var(--hn-ink);
}

@media (min-width: 992px) {
	.hws-mobile-menu { display: none !important; }
}

/* ==========================================================================
   9. Hero
   ========================================================================== */
.hws-hero-section {
	position: relative;
	overflow: hidden;
	padding: clamp(3rem, 2rem + 4vw, 6.5rem) 0 clamp(3rem, 2rem + 3vw, 5rem);
}

.hws-hero-section::before {
	content: "";
	position: absolute;
	top: -20%;
	right: -10%;
	width: 46vw;
	height: 46vw;
	max-width: 620px;
	max-height: 620px;
	background: var(--hn-gradient);
	opacity: 0.14;
	border-radius: 50%;
	filter: blur(10px);
	z-index: 0;
}

.hws-hero-section .container {
	position: relative;
	z-index: 1;
}

.hws-kicker {
	display: inline-block;
	font-size: 0.82rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--hn-violet-dark);
	background: var(--hn-soft);
	border-radius: var(--hn-radius-pill);
	padding: 0.5em 1.1em;
	margin-bottom: 1.4rem;
	line-height: 1.5;
}

/* The hero's kicker is a full sentence (13 words) -- fine as a single-line
   pill on desktop, but a wrapped multi-line pill loses its capsule shape
   (a background clips per line, not per element, once text wraps) and
   reads as a heavy solid band on a phone. Below 576px it drops the
   pill chrome entirely and becomes plain small-caps text instead --
   the standard "eyebrow" pattern for longer lead-ins. Other .hws-kicker
   uses elsewhere (short 3-4 word labels) never wrap, so they keep the pill.  */
@media (max-width: 575.98px) {
	.hws-hero-copy .hws-kicker {
		display: block;
		background: none;
		padding: 0;
		font-size: 0.78rem;
	}
}

.banner-title {
	font-size: clamp(2.2rem, 1.6rem + 3vw, 3.6rem);
	margin-bottom: 1.1rem;
}

.hws-hero-copy > p {
	font-size: 1.1rem;
	max-width: 40em;
	margin-bottom: 1.6rem;
}

.banner-btn {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	margin-bottom: 1.1rem;
}

.hws-hero-note {
	font-size: 0.85rem;
	color: var(--hn-muted);
	margin-bottom: 1.5rem;
}

.hws-chip-list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

/* v1.7 (audit v3, finding 14): six chips, several with fairly long labels
   ("Trades & home services", "Property & lettings"), don't fit two per
   line at 375px without fighting the text -- wrapping one per line at
   that width cost 375px of vertical space on its own, close to half a
   screen of scrolling before the first real section. A horizontal scroll
   strip is the standard pattern for this: same chips, same tap targets,
   a fraction of the height. */
@media (max-width: 575.98px) {
	.hws-chip-list {
		flex-wrap: nowrap;
		overflow-x: auto;
		overflow-y: hidden;
		padding-bottom: 0.5rem;
		margin-right: -20px;
		-webkit-overflow-scrolling: touch;
		scroll-snap-type: x proximity;
	}

	.hws-chip-list li {
		flex-shrink: 0;
	}

	.hws-chip-list a {
		white-space: nowrap;
		scroll-snap-align: start;
	}
}

.hws-chip-list a {
	/* v1.7 (audit v3, finding 07): measured at 33px tall -- min-height
	   plus flex-centering guarantees the 44px touch-target minimum
	   regardless of font metrics, rather than tuning em-padding by feel. */
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font-size: 0.78rem;
	font-weight: 600;
	color: var(--hn-violet-dark) !important;
	background: var(--hn-soft);
	border: 1px solid transparent;
	border-radius: var(--hn-radius-pill);
	padding: 0.4em 1em;
	transition: border-color 0.2s var(--hn-ease), transform 0.2s var(--hn-ease);
}

.hws-chip-list a:hover {
	border-color: var(--hn-violet);
	transform: translateY(-2px);
}

.hws-hero-media {
	margin: 0;
	position: relative;
}

.hws-hero-svg {
	width: 100%;
	height: auto;
	display: block;
	filter: drop-shadow(var(--hn-shadow-lg));
}

/* The illustration's embedded <text> labels are sized for its ~600px
   desktop render (roughly 1:1 with the 640-wide viewBox); below 768px it
   stacks full-width but a phone's actual rendered width (~340-400px) scales
   those labels down to ~6-8px, unreadable, and adds scroll length for a
   purely decorative graphic. Hidden below that width; a tablet's ~700px+
   render keeps it, at or above its intended scale. */
@media (max-width: 767.98px) {
	.hws-hero-media {
		display: none;
	}
}

/* ==========================================================================
   10. Proof strip / stat rows
   ========================================================================== */
.hws-proof-strip {
	background: var(--hn-ink);
	color: var(--hn-white);
}

.hws-proof-strip-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 2rem;
}

.hws-proof-strip-grid article span,
.hws-proof-strip-grid article > span {
	display: block;
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--hn-violet-light);
	margin-bottom: 0.5rem;
}

.hws-proof-strip-grid article strong {
	display: block;
	font-family: var(--hn-font-display);
	font-size: 1.25rem;
	font-weight: 600;
	color: var(--hn-white);
	line-height: 1.4;
}

/* ==========================================================================
   11. Section heading
   ========================================================================== */
.section-heading {
	margin-bottom: 2.75rem;
}

.section-heading p {
	font-size: 1.05rem;
	max-width: 46em;
}

.text-center .section-heading p,
.section-heading.text-center p {
	margin-left: auto;
	margin-right: auto;
}

/* ==========================================================================
   12. Service cards + service detail
   ========================================================================== */
.hws-service-card {
	/* position:relative anchors the stretched-link ::after below, so the
	   whole card becomes the click/tap target, not just the "More on..."
	   text -- per the design brief: better UX and conversion than a
	   single small text link at the bottom of an otherwise-dead card. */
	position: relative;
	height: 100%;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2.1rem;
	box-shadow: var(--hn-shadow-sm);
	transition: transform 0.3s var(--hn-ease), box-shadow 0.3s var(--hn-ease), border-color 0.3s var(--hn-ease);
}

.hws-service-card:hover {
	transform: translateY(-6px);
	box-shadow: var(--hn-shadow-md);
	border-color: var(--hn-violet-light);
}

.hws-service-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border-radius: var(--hn-radius-md);
	background: var(--hn-gradient);
	color: var(--hn-white);
	font-size: 1.3rem;
	margin-bottom: 1.2rem;
}

.hws-service-card h3 {
	font-size: 1.25rem;
	margin-bottom: 0.6rem;
}

.hws-service-card p {
	margin-bottom: 1rem;
}

.hws-service-card > a {
	/* v1.7 (audit v3, finding 07): the worst offender at 24px tall --
	   min-height + flex-centering, same approach as the hero chips above. */
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font-weight: 700;
	font-size: 0.9rem;
	position: relative;
	z-index: 1;
}

/* Standard "stretched link" pattern (the same technique Bootstrap's own
   .stretched-link utility uses): an invisible pseudo-element on the link
   itself, sized to its positioned ancestor (.hws-service-card above), so
   a click anywhere on the card activates this one link. z-index:1 on the
   link's own text (above) keeps it visually/hit-test above this overlay
   for anyone tabbing to the real link text. */
.hws-service-card > a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.hws-service-detail-section {
	display: flex;
	flex-direction: column;
	gap: 1.5rem;
}

.hws-service-detail {
	display: grid;
	grid-template-columns: minmax(200px, 280px) 1fr;
	gap: 2rem;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2.25rem;
}

.hws-service-detail h3 {
	font-size: 1.3rem;
	margin-top: 0.4rem;
}

.hws-service-detail dl {
	display: grid;
	gap: 0.9rem;
	margin: 0;
}

.hws-service-detail dt {
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--hn-violet);
}

.hws-service-detail dd {
	margin: 0.15rem 0 0;
	color: var(--hn-muted);
}

.hws-data-summary {
	background: var(--hn-soft);
	border-radius: var(--hn-radius-lg);
	margin: 3rem 0;
}

.hws-data-summary article {
	max-width: 60em;
}

.hws-card-kicker {
	display: inline-block;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--hn-violet);
	margin-bottom: 0.5rem;
}

@media (max-width: 767.98px) {
	.hws-service-detail { grid-template-columns: 1fr; }
}

/* ==========================================================================
   13. Work / gallery cards
   ========================================================================== */
.hws-work-card,
.hws-search-card {
	/* auto, not 100%: these sit in a plain .row (not .hws-equal-grid), so
	   the column is display:block internally (see the global reset near
	   the top of this file) -- but .row itself is still flex, and its
	   columns are still stretched by the browser's default
	   align-items:stretch as flex ITEMS regardless of their own display.
	   A stretched column gives height:100% something real to resolve
	   against, so it was still winning here even after that reset. Auto
	   sidesteps the question entirely: the card just sizes to its own
	   content no matter what height its column ends up with. */
	height: auto;
	margin-bottom: 0;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	box-shadow: var(--hn-shadow-sm);
	transition: transform 0.3s var(--hn-ease), box-shadow 0.3s var(--hn-ease);
}

.hws-work-card:hover {
	transform: translateY(-6px);
	box-shadow: var(--hn-shadow-md);
}

.hws-work-card figure {
	margin: 0;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	background: var(--hn-soft);
}

/* v1.10.3 (111.html, "images inside them are coming out cropped"): was
   object-fit:cover. Every portfolio photo here is a designed marketing
   graphic (a logo, a headline, a CTA button placed deliberately, not a
   casual photo with forgiving edges) at a fixed 4:3 ratio, forced into
   this figure's 16:10 box -- cover crops ~17% of the image's height to
   fill that wider box, and depending on where each graphic places its
   text there was no safe amount to lose (a center-crop clipped "YOUR
   BEAUTY PLANS." down to "ONE PLACE.", cut "Cleaning that" down to
   "fits your move.", and, on one image with a different internal
   layout, sliced the "V" off "VOLTBUN"). contain guarantees nothing
   this portfolio exists to show off -- the client's own logo and
   headline -- can ever be cropped out of frame, at the cost of a
   letterboxing bar on two sides for a 4:3 image in this 16:10 box;
   the figure's own --hn-soft background (above) fills that bar rather
   than leaving it blank. */
.hws-work-card figure img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	transition: transform 0.5s var(--hn-ease);
}

.hws-work-card:hover figure img {
	transform: scale(1.05);
}

/* v1.10 (work-carousels-5x4-tz.pdf): a 5-photo swipe carousel inside the
   same .hws-work-card figure box (still the 16/10 aspect-ratio box
   above -- the carousel only changes what's INSIDE it). The card's own
   hover zoom above is for a single static image and would fight a
   carousel the visitor is actively dragging, so it's switched off here. */
.hws-work-card:hover figure.hws-carousel img {
	transform: none;
}

.hws-carousel {
	position: relative;
	touch-action: pan-y;
}

/* v1.10.2 (handywebstudio-carousel-bug.html): "clicking next/prev/dots
   does nothing" -- root cause found by actually rendering this in a
   browser and hit-testing it (Playwright), not by re-reading the JS,
   which was correct on its own (verified separately: the click
   handlers fire and DO set track.style.transform). The parent's own
   style.css has `.hws-work-card div { display:flex; flex:1;
   flex-direction:column; padding:24px; }` -- a broad descendant
   selector (.hws-work-card div, not the direct-child .hws-work-card >
   div it reads like it means), so it matches every <div> anywhere
   inside a work card, not just the card's one content wrapper it was
   clearly written for. That includes .hws-carousel-track and every
   .hws-carousel-slide (also <div>s): flex-direction:column forces the
   slides to stack VERTICALLY instead of side-by-side, so the JS's
   horizontal translateX() -- completely correct in isolation -- moves
   the track in an axis that no longer has any visible effect. It also
   caught .hws-carousel-dots (also a <div>), inflating it from ~10px to
   ~103px tall via the same flex-direction:column + 24px padding --
   tall enough to physically overlap and intercept clicks on the
   prev/next buttons, confirmed via Playwright's real hit-testing
   (elementFromPoint() at the next-button's own screen position
   returned the dots div, not the button). Two symptoms, one cause.
   Specificity: `.hws-work-card div` is (0,1,1) [class + type], beating
   these plain single-class rules' (0,1,0) regardless of load order --
   the same trap as the footer-links bug (1.9.3) and the round-btn
   hover bug (1.9.1). !important on every property that selector sets. */
.hws-carousel-track {
	display: flex !important;
	flex-direction: row !important;
	width: 100%;
	height: 100%;
	padding: 0 !important;
	transition: transform 0.4s var(--hn-ease);
}

.hws-carousel-slide {
	display: block !important;
	flex: 0 0 100% !important;
	width: 100%;
	height: 100%;
	padding: 0 !important;
}

.hws-carousel-slide img {
	width: 100%;
	height: 100%;
	object-fit: contain; /* v1.10.3: same reasoning as .hws-work-card figure img above -- these designed graphics should never lose their logo/headline to a crop */
	display: block;
	pointer-events: none; /* dragging the track shouldn't trigger native image-drag/ghosting */
}

.hws-carousel-prev,
.hws-carousel-next {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 30px;
	height: 30px;
	border-radius: 50%;
	border: none;
	background: rgba(22, 19, 38, 0.5);
	color: var(--hn-white);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 0.75rem;
	cursor: pointer;
	z-index: 2;
	transition: background 0.2s var(--hn-ease);
}

.hws-carousel-prev { left: 0.6rem; }
.hws-carousel-next { right: 0.6rem; }

.hws-carousel-prev:hover,
.hws-carousel-next:hover,
.hws-carousel-prev:focus-visible,
.hws-carousel-next:focus-visible {
	background: var(--hn-violet);
}

.hws-carousel-dots {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0.7rem;
	display: flex !important;
	flex-direction: row !important;
	padding: 0 !important;
	justify-content: center;
	align-items: center;
	gap: 0.4rem;
	z-index: 2;
}

.hws-carousel-dot {
	width: 6px;
	height: 6px;
	padding: 0;
	border: none;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.55);
	cursor: pointer;
	transition: background 0.2s var(--hn-ease), transform 0.2s var(--hn-ease);
}

.hws-carousel-dot.is-active {
	background: var(--hn-white);
	transform: scale(1.35);
}

.hws-work-card > div,
.hws-search-card .entry-content {
	padding: 1.5rem;
}

.hws-work-badge {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	padding: 0.3em 0.75em;
	border-radius: var(--hn-radius-pill);
	margin-bottom: 0.6rem;
}

/* Matches this file's existing --hn-soft/--hn-violet-dark pill treatment
   used for .hws-audit-tag-worth -- same visual language, new context. */
.hws-work-badge-concept {
	background: var(--hn-soft);
	color: var(--hn-violet-dark);
}

.hws-work-badge-live {
	background: #e5f6ec;
	color: #1c7a44;
}

.hws-work-card .hws-work-link {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	font-weight: 700;
	font-size: 0.9rem;
	color: var(--hn-violet-dark);
}

.hws-work-card .hws-work-link:hover { color: var(--hn-violet); }

.hws-work-more {
	text-align: center;
	margin-top: 2.5rem;
}

.hws-work-card h3 {
	font-size: 1.1rem;
	margin-bottom: 0.4rem;
}

.hws-work-placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 100%;
	padding: 1.5rem;
	text-align: center;
	font-size: 0.85rem;
	color: var(--hn-muted);
}

.hws-admin-note {
	background: #fff4e0;
	border: 1px dashed var(--hn-amber);
	border-radius: var(--hn-radius-md);
	padding: 1.25rem;
	color: var(--hn-ink);
	font-size: 0.9rem;
	margin-top: 1.5rem;
}

/* Honest empty state for Work when no real entries exist yet (see
   front-page.php, audit-recheck point 01) -- a bordered panel rather than
   a bare card grid, so it reads as a deliberate "not yet" rather than a
   broken/empty section. */
.hws-work-empty {
	max-width: 44em;
	margin: 0 auto;
	text-align: center;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: clamp(2rem, 1.6rem + 2vw, 3rem);
	box-shadow: var(--hn-shadow-sm);
}

.hws-work-empty .hws-card-kicker {
	display: inline-block;
	margin-bottom: 0.75rem;
}

.hws-work-empty h3 {
	font-size: 1.3rem;
	margin-bottom: 0.9rem;
}

.hws-work-empty p {
	margin-bottom: 1.5rem;
}

.gallery-container.grid,
.grid.grid-item,
.row.grid {
	row-gap: 2rem;
}

.button-container .button-text {
	font-weight: 700;
	font-size: 0.9rem;
}

/* ==========================================================================
   14. Value + process
   ========================================================================== */
.hws-proof-card {
	/* auto, not 100% -- same reasoning as .hws-work-card above: this
	   card's column is still stretched by .row's own flex behaviour
	   regardless of the column's own display property, so height:100%
	   was still resolving and stretching this specific card even after
	   the global column-display reset (that's exactly what was still
	   visible on the Pricing page's "What is included" row). */
	height: auto;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-left: 3px solid var(--hn-violet);
	border-radius: var(--hn-radius-md);
	padding: 1.75rem;
	box-shadow: var(--hn-shadow-sm);
}

.hws-soft-section .hws-proof-card {
	background: var(--hn-white);
}

.hws-proof-card h3 {
	font-size: 1.1rem;
	margin-bottom: 0.5rem;
}

.hws-process-list {
	display: grid;
	gap: 1.5rem;
}

.hws-process-item {
	display: grid;
	grid-template-columns: 52px 1fr;
	/* center is correct now that the numeral is a fixed-size badge (below)
	   rather than raw text -- a self-contained shape reads fine vertically
	   centered against a row of any height, unlike bare text trying to
	   stay level with a heading. */
	align-items: center;
	gap: 1.5rem;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 1.75rem 2rem;
}

.hws-process-item span {
	/* The parent theme's own style.css carries a same-specificity
	   `.hws-process-item > span` rule (72x72px, inline-flex, centered,
	   border-radius:8px, teal background) that this file's earlier,
	   text-only version of this rule never fully overrode -- properties
	   it didn't redeclare (display/width/height/align-items/
	   justify-content/border-radius) kept leaking through from the
	   parent regardless. Every property the parent sets is now
	   explicitly redeclared here, so nothing can leak: a proper 52px
	   circular gradient badge, fully owned by this rule. */
	display: flex;
	align-items: center;
	justify-content: center;
	width: 52px;
	height: 52px;
	border-radius: 50%;
	background: var(--hn-gradient);
	flex-shrink: 0;
	box-shadow: var(--hn-shadow-violet);
	font-family: var(--hn-font-display);
	font-size: 1.05rem;
	font-weight: 700;
	line-height: 1;
	color: var(--hn-white);
}

.hws-process-item h3 {
	font-size: 1.15rem;
	margin-bottom: 0.35rem;
}

/* ==========================================================================
   15. Pricing / plan cards + plan detail
   ========================================================================== */
.hws-plan-grid,
.hws-plan-archive-wrap .container > .row {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: 1.75rem;
	margin-bottom: 2rem;
}

/* v1.7 (audit v3, finding 13): auto-fit alone drops from 3 columns to 2
   around 896px of available width, landing squarely in the 768px tablet
   range -- "Content and Social Run" ends up alone on its own row with an
   empty half-row beside it. Forcing 1 column below the point 3 columns
   stop fitting comfortably (992px, matching where the featured card's
   hover-lift is also disabled) skips that awkward 2+1 state entirely:
   3 columns above it, 1 below, never 2. */
@media (max-width: 991.98px) {
	.hws-plan-grid,
	.hws-plan-archive-wrap .container > .row {
		grid-template-columns: 1fr;
	}
}

.hws-plan-card {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	height: 100%;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	box-shadow: var(--hn-shadow-sm);
	transition: transform 0.3s var(--hn-ease), box-shadow 0.3s var(--hn-ease);
}

.hws-plan-card:hover {
	transform: translateY(-6px);
	box-shadow: var(--hn-shadow-md);
}

.hws-plan-card-body {
	padding: 2rem 2rem 0.5rem;
}

.hws-plan-card-body h3 {
	font-size: 1.3rem;
	margin: 0.35rem 0 0.6rem;
}

.hws-plan-card-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 1.5rem 2rem;
	margin-top: 1.5rem;
	background: var(--hn-soft);
}

.hws-plan-card-foot strong {
	font-family: var(--hn-font-display);
	font-size: 1.05rem;
}

.hws-check-list {
	list-style: none;
	margin: 0 0 1rem;
	padding: 0;
	display: grid;
	gap: 0.55rem;
}

.hws-check-list li {
	position: relative;
	padding-left: 1.6em;
	font-size: 0.92rem;
	color: var(--hn-ink-soft);
}

.hws-check-list li::before {
	content: "\2713";
	position: absolute;
	left: 0;
	top: 0.05em;
	color: var(--hn-violet);
	font-weight: 700;
}

.hws-pricing-anchor,
.hws-scope-section {
	max-width: 60em;
}

.hws-pricing-anchor {
	background: var(--hn-soft);
	border-radius: var(--hn-radius-lg);
	padding: 1.75rem 2rem;
	margin-top: 1rem;
}

.hws-plan-detail-wrap .single-packge-wrap {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2.5rem;
}

.hws-plan-head {
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 1rem;
	border-bottom: 1px solid var(--hn-line);
	padding-bottom: 1.5rem;
	margin-bottom: 1.5rem;
}

.hws-plan-title h2 { font-size: 1.5rem; margin-bottom: 0.4rem; }
.rating-start { position: relative; width: 90px; height: 1em; background: var(--hn-line); border-radius: 999px; overflow: hidden; }
.rating-start span { position: absolute; inset: 0; background: var(--hn-amber); }
.hws-plan-price .price-list { color: var(--hn-violet); font-family: var(--hn-font-display); }

.hws-plan-meta ul {
	display: flex;
	flex-wrap: wrap;
	gap: 1.4rem;
	list-style: none;
	margin: 0 0 1.5rem;
	padding: 0;
}

.hws-plan-meta li {
	display: flex;
	align-items: center;
	gap: 0.5em;
	font-size: 0.88rem;
	font-weight: 600;
	color: var(--hn-ink-soft);
}

.hws-plan-meta i { color: var(--hn-violet); }

.hws-plan-summary span {
	display: inline-block;
	background: var(--hn-soft);
	color: var(--hn-violet-dark);
	font-size: 0.85rem;
	font-weight: 700;
	border-radius: var(--hn-radius-pill);
	padding: 0.4em 1em;
	margin-bottom: 1rem;
}

.hws-plan-content-detail article {
	margin-bottom: 1.75rem;
}

.hws-plan-include.bg-light-grey {
	background: var(--hn-soft);
	border-radius: var(--hn-radius-md);
	padding: 1.5rem 1.75rem;
}

.hws-plan-include ul,
.hws-plan-process ul {
	list-style: none;
	margin: 0.75rem 0 0;
	padding: 0;
	display: grid;
	gap: 0.6rem;
}

.hws-plan-include li i { color: var(--hn-violet); margin-right: 0.5em; }

.hws-plan-process li {
	display: flex;
	align-items: baseline;
	gap: 0.6em;
}

.hws-plan-process span {
	font-family: var(--hn-font-display);
	font-weight: 700;
	color: var(--hn-violet);
}

.hws-inquiry-form-wrap { margin-bottom: 1.5rem; }

.hws-inquiry-form-inner.primary-bg {
	background: var(--hn-ink);
	background-image: var(--hn-gradient);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	color: var(--hn-white);
}

.hws-inquiry-form-inner h3 { color: var(--hn-white); }
.hws-inquiry-form-inner p { color: rgba(255,255,255,0.82); margin-bottom: 1.25rem; }

.hws-inquiry-form input,
.hws-inquiry-form textarea {
	width: 100%;
	border: none;
	border-radius: var(--hn-radius-sm);
	padding: 0.85em 1em;
	margin-bottom: 0.85rem;
	font-family: inherit;
	background: rgba(255, 255, 255, 0.95);
	color: var(--hn-ink);
}

.hws-service-list {
	position: relative;
	background: var(--hn-ink);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	color: var(--hn-white);
}

.hws-service-list h4 { color: var(--hn-white); margin-bottom: 1rem; }

.hws-service-list ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0.75rem;
}

.hws-service-list a {
	color: rgba(255, 255, 255, 0.85) !important;
	font-weight: 600;
	display: flex;
	align-items: center;
	gap: 0.5em;
}

.hws-service-list a:hover { color: var(--hn-white) !important; }

/* ==========================================================================
   16. Industries / destination cards
   ========================================================================== */
.hws-industry-card {
	/* The parent's own style.css carries `.hws-industry-card { height:100%;
	   margin-bottom:24px; padding:28px; }` deeper in its file (same
	   selector, same specificity) -- explicit height:auto and
	   margin-bottom:0 here so neither can leak through. With 5 cards at
	   3-per-row, the last row only has 2; forced equal-height would
	   stretch whichever of those two has the shorter description to
	   match the longer one, leaving visible empty space under it. Five
	   real, differently-worded category blurbs will never line-wrap
	   identically, so cards here hug their own content instead
	   (spacing between them comes from the row's own gx-4 gutter, not
	   a per-card margin). */
	height: auto;
	margin-bottom: 0;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	box-shadow: var(--hn-shadow-sm);
	transition: transform 0.3s var(--hn-ease), box-shadow 0.3s var(--hn-ease);
}

.hws-industry-card:hover {
	transform: translateY(-6px);
	box-shadow: var(--hn-shadow-md);
}

.hws-industry-card h3 { font-size: 1.15rem; margin: 0.3rem 0 0.5rem; }

.hws-industry-detail-list {
	display: grid;
	gap: 1.25rem;
}

.hws-industry-detail {
	background: var(--hn-white);
	border-radius: var(--hn-radius-md);
	padding: 1.75rem 2rem;
	border: 1px solid var(--hn-line);
	scroll-margin-top: 6rem;
}

.hws-industry-detail h3 { font-size: 1.15rem; margin-bottom: 0.4rem; }

/* ==========================================================================
   17. Founder block
   ========================================================================== */
.hws-founder-section {
	background: var(--hn-ink);
	color: var(--hn-white);
	border-radius: var(--hn-radius-lg);
	margin: 0 auto;
	max-width: 1200px;
}

.hws-founder-section .section-title,
.hws-founder-section h3 { color: var(--hn-white); }
.hws-founder-section .sub-title,
.hws-founder-section .hws-kicker { color: var(--hn-violet-light); }
.hws-founder-section p { color: rgba(255, 255, 255, 0.78); }

.hws-founder-photo {
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	aspect-ratio: 4 / 5;
	background: var(--hn-ink-soft);
}

.hws-founder-photo img { width: 100%; height: 100%; object-fit: cover; }

.hws-founder-photo-placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	padding: 2rem;
	color: rgba(255, 255, 255, 0.6);
	font-size: 0.9rem;
}

/* v1.7.1 (design-system brief): amber reserved for badge/status roles
   only (the MOST CHOSEN badge, the "Drafted" dot) -- this is the parent's
   own traveler_founder_block(), still called on page-about.php, and was
   the one remaining place amber showed up as a plain text accent rather
   than a badge. .hws-founder-section (above) has a dark ink background,
   so the light variant is used here for contrast -- violet-dark (used for
   this same role on the homepage's light-background team section) would
   read poorly against it. */
.hws-founder-role { color: var(--hn-violet-light) !important; font-weight: 700; margin-bottom: 1rem; }
.hws-signature { font-family: var(--hn-font-display); font-style: italic; margin-top: 1.5rem; }

/* ==========================================================================
   18. Final audit / CTA sections + forms
   ========================================================================== */
.hws-final-audit-section {
	background: var(--hn-white);
	border-top: 1px solid var(--hn-line);
}

.hws-audit-card,
.hws-audit-form {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2.25rem;
	box-shadow: var(--hn-shadow-md);
}

.hws-form-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 1rem 1.25rem;
	margin-bottom: 1.5rem;
}

.hws-form-grid label,
.hws-audit-side h3 {
	display: block;
	font-size: 0.85rem;
	font-weight: 700;
	margin-bottom: 0.4rem;
	color: var(--hn-ink-soft);
}

.hws-form-grid input,
.hws-form-grid select,
.hws-audit-form input,
.hws-audit-form textarea,
.apply-form input,
.apply-form textarea {
	width: 100%;
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-sm);
	padding: 0.8em 1em;
	font-family: inherit;
	background: var(--hn-paper);
	transition: border-color 0.2s var(--hn-ease), box-shadow 0.2s var(--hn-ease);
}

.hws-form-grid input:focus,
.hws-form-grid select:focus,
.hws-audit-form textarea:focus {
	outline: none;
	border-color: var(--hn-violet);
	box-shadow: 0 0 0 3px rgba(91, 61, 240, 0.15);
}

.hws-form-expectation,
.hws-form-privacy {
	font-size: 0.82rem;
	color: var(--hn-muted);
	margin-top: 0.75rem;
}

.hws-form-success {
	background: var(--hn-soft);
	border-radius: var(--hn-radius-md);
	padding: 2rem;
	text-align: center;
}

.hws-form-error {
	background: #fdeceb;
	color: #b3261e;
	border-radius: var(--hn-radius-sm);
	padding: 0.85em 1em;
	margin-bottom: 1rem;
	font-size: 0.88rem;
}

.traveler-alert {
	border-radius: var(--hn-radius-md);
	padding: 1rem 1.5rem;
	margin: 1.5rem 0;
	font-weight: 600;
}

.hws-alert-success { background: var(--hn-soft); color: var(--hn-violet-dark); }
.hws-alert-error { background: #fdeceb; color: #b3261e; }

.hws-audit-side { margin-top: 1.75rem; }

.hws-final-cta,
.bg-color-callback {
	background: var(--hn-ink);
	background-image: var(--hn-gradient);
	border-radius: var(--hn-radius-lg);
	color: var(--hn-white);
	text-align: center;
	margin: 0 auto;
	max-width: 1200px;
}

.hws-final-cta .section-title,
.bg-color-callback .section-title { color: var(--hn-white); }
.hws-final-cta p,
.bg-color-callback p { color: rgba(255, 255, 255, 0.85); }
.hws-final-cta .callback-btn,
.bg-color-callback .callback-btn {
	display: flex;
	justify-content: center;
	gap: 1rem;
	flex-wrap: wrap;
	margin-top: 1.5rem;
}

/* ==========================================================================
   19. Inner banner
   ========================================================================== */
/* v1.9.2 (manual audit 2, item 2): the full-bleed violet gradient band
   (previous fix below this comment, kept in the 1.6.3 changelog entry
   for history) repeated identically on Services/Work/Pricing/About/
   Contact and read as heavy and repetitive page over page. Replaced
   with a plain in-flow heading on the page's own paper background plus
   a short accent underline -- matches the audit's own mockup, which
   reused this site's existing "What We Do" H2 treatment as the target
   look. Three things had to be beaten to get a plain light heading
   here, all from the parent's non-pluggable traveler_inner_banner()
   CSS: (1) .inner-baner-container's own opaque ink fill + 240px
   min-height (the 1.6.3 fix below), (2) a full-cover ::before overlay
   meant to darken a background photo -- currently a no-op only because
   two same-specificity parent rules happen to tie in the parent's own
   favour (last one sets it transparent); pinned explicitly here rather
   than depending on that, and (3) the title colour/size, which the
   parent sets at .handy-web-studio-theme .inner-banner-content
   .page-title specificity (2 classes) -- one class more specific than
   this file's old .inner-banner-content .page-title rule, so that
   rule was quietly losing the colour fight even before this redesign
   (both sides happened to use white, so it went unnoticed). Matched
   the parent's selector shape so source order (this file loads after
   the parent's) decides it, plus !important as the same belt-and-
   suspenders this file now uses everywhere else it fights the parent
   on colour. */
.inner-banner-wrap {
	background: var(--hn-paper);
	background-image: none;
	padding: clamp(2.75rem, 2.35rem + 2vw, 3.75rem) 0 clamp(1.75rem, 1.45rem + 1.5vw, 2.5rem);
}

.handy-web-studio-theme .inner-baner-container {
	background: none;
	min-height: 0;
	text-align: center;
}

.handy-web-studio-theme .inner-baner-container::before {
	content: none;
}

.handy-web-studio-theme .inner-banner-content .page-title,
.handy-web-studio-theme .inner-banner-content .inner-title {
	color: var(--hn-ink) !important;
	margin: 0;
	font-size: clamp(1.8rem, 1.4rem + 2vw, 2.7rem) !important;
}

.inner-banner-content .page-title::after,
.inner-banner-content .inner-title::after {
	content: "";
	display: block;
	width: 70px;
	height: 4px;
	background: var(--hn-violet);
	border-radius: 2px;
	margin: 1rem auto 0;
}

/* ==========================================================================
   20. Generic page section + proof card grid spacing
   ========================================================================== */
.traveler-page-content {
	padding: 3rem 0 0;
	max-width: 70em;
}

.hws-about-summary {
	background: var(--hn-soft);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	position: sticky;
	top: 6rem;
}

.hws-about-summary span {
	display: block;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--hn-violet);
	margin-bottom: 0.6rem;
}

.hws-about-summary strong {
	display: block;
	font-family: var(--hn-font-display);
	font-size: 1.2rem;
	margin-bottom: 0.75rem;
}

/* ==========================================================================
   22. Contact page
   ========================================================================== */
.hws-contact-direct {
	display: flex;
	flex-direction: column;
	gap: 0.85rem;
	margin: 1.5rem 0;
}

.hws-contact-direct a,
.hws-contact-direct span {
	display: flex;
	align-items: center;
	gap: 0.7em;
	font-weight: 600;
	color: var(--hn-ink-soft);
}

.hws-contact-direct i {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border-radius: var(--hn-radius-pill);
	background: var(--hn-soft);
	color: var(--hn-violet);
}

.hws-social-list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

.hws-social-list a {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--hn-ink-soft) !important;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-pill);
	padding: 0.5em 1em;
}

/* ==========================================================================
   23. Team + testimonials
   ========================================================================== */
.team-item {
	/* auto, not 100% -- same column-stretch issue as .hws-proof-card
	   above; real WP bios will vary in length unpredictably. */
	height: auto;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	box-shadow: var(--hn-shadow-sm);
}

.team-image {
	margin: 0;
	aspect-ratio: 4 / 5;
	background: var(--hn-soft);
}

.team-image img { width: 100%; height: 100%; object-fit: cover; }
.team-content { padding: 1.5rem; }
.team-content h3 { font-size: 1.1rem; margin-bottom: 0.2rem; }
.team-content .job-title { display: block; color: var(--hn-violet); font-weight: 700; font-size: 0.85rem; margin-bottom: 0.6rem; }

.testimonial-item {
	/* auto, not 100% -- same column-stretch issue as .hws-proof-card
	   above; real testimonial quotes will vary in length unpredictably. */
	height: auto;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	box-shadow: var(--hn-shadow-sm);
}

.testimonial-content p {
	font-family: var(--hn-font-display);
	font-size: 1.1rem;
	color: var(--hn-ink-soft);
	margin-bottom: 1.5rem;
}

.author-content { display: flex; align-items: center; gap: 1rem; }
.testimonial-img { width: 52px; height: 52px; border-radius: 50%; overflow: hidden; margin: 0; background: var(--hn-soft); flex-shrink: 0; }
.testimonial-img img { width: 100%; height: 100%; object-fit: cover; }
.author-name h5 { font-size: 1rem; margin: 0; }
.author-name span { font-size: 0.82rem; color: var(--hn-violet); font-weight: 700; }

/* ==========================================================================
   24. Careers
   ========================================================================== */
.career-item {
	/* auto, not 100% -- same column-stretch issue as .hws-proof-card
	   above; real role descriptions will vary in length unpredictably. */
	height: auto;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	box-shadow: var(--hn-shadow-sm);
}

.career-image { margin: 0; aspect-ratio: 3 / 2; background: var(--hn-soft); }
.career-image img { width: 100%; height: 100%; object-fit: cover; }
.career-content { padding: 1.5rem; }
.career-content h3 { font-size: 1.1rem; margin-bottom: 0.5rem; }
.career-content .job-desc { display: block; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--hn-violet); margin-bottom: 0.5rem; }

.apply-form-container {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2.25rem;
	margin-top: 1rem;
}

.apply-form-container .subtitle {
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--hn-violet);
}

.apply-form { display: grid; gap: 0; margin-top: 1.25rem; }
.apply-form p { margin-bottom: 0.9rem; }
.apply-form input[type="submit"] {
	width: auto;
	background: var(--hn-gradient);
	color: var(--hn-white);
	font-weight: 700;
	border: none;
	border-radius: var(--hn-radius-pill);
	padding: 0.9em 2em;
	cursor: pointer;
}

.job-description {
	/* auto, not 100% -- same column-stretch issue as .hws-proof-card
	   above; the three career-detail blocks (SUMMARY / HOW TO REGISTER /
	   REGISTER INTEREST) are deliberately different lengths. */
	height: auto;
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
}

.job-description.bg-light-grey { background: var(--hn-soft); }
.job-description.primary-bg { background: var(--hn-ink); background-image: var(--hn-gradient); color: var(--hn-white); }
.job-description.primary-bg h4,
.job-description.primary-bg h5 { color: var(--hn-white); }
.job-description.primary-bg span { opacity: 0.75; font-size: 0.8rem; }
.job-description ul { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: 0.6rem; }
.job-description.bg-image {
	position: relative;
	background: var(--hn-ink);
	background-image: linear-gradient(160deg, rgba(91,61,240,0.92), rgba(22,19,38,0.95));
	color: var(--hn-white);
}
.job-description.bg-image h3 { color: var(--hn-white); }
.job-description.bg-image .overlay { display: none; }
.hws-role-email a {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	color: var(--hn-white) !important;
	font-weight: 700;
	margin: 0.6rem 0 1.25rem;
}

/* ==========================================================================
   25. FAQ accordion
   ========================================================================== */
.hws-faq-list {
	display: grid;
	gap: 1rem;
	max-width: 56em;
	margin: 0 auto;
}

.hws-faq-item {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-md);
	overflow: hidden;
}

.hws-faq-item h3 { margin: 0; font-size: 1rem; }

.hws-faq-item button {
	width: 100%;
	text-align: left;
	background: transparent;
	border: none;
	padding: 1.35rem 1.6rem;
	font-family: var(--hn-font-display);
	font-weight: 600;
	font-size: 1.02rem;
	color: var(--hn-ink);
	cursor: pointer;
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 1rem;
}

.hws-faq-item button::after {
	content: "+";
	font-size: 1.3rem;
	color: var(--hn-violet);
	transition: transform 0.25s var(--hn-ease);
	flex-shrink: 0;
}

.hws-faq-item button[aria-expanded="true"]::after {
	transform: rotate(45deg);
}

.hws-faq-item .collapse > p {
	padding: 0 1.6rem 1.4rem;
	margin: 0;
}

/* ==========================================================================
   26. Legal content
   ========================================================================== */
.hws-legal-content {
	max-width: 70em;
}

.hws-legal-content h2 {
	font-size: 1.25rem;
	margin: 2rem 0 0.6rem;
}

.hws-legal-content h2:first-of-type { margin-top: 1rem; }

/* ==========================================================================
   27. Search page + archives / blog
   ========================================================================== */
.hws-search-panel {
	background: var(--hn-ink);
	background-image: var(--hn-gradient);
	border-radius: var(--hn-radius-lg);
	padding: clamp(2rem, 1.6rem + 2vw, 3.5rem);
	color: var(--hn-white);
	margin-bottom: 3rem;
}

.hws-search-panel h4 { color: rgba(255,255,255,0.8); font-size: 0.95rem; font-weight: 600; }
.hws-search-panel h2 { color: var(--hn-white); }

.hws-search-panel .search-form {
	display: flex;
	gap: 0.75rem;
	max-width: 34em;
	margin: 1.5rem auto 0;
}

.hws-search-panel .search-form input {
	flex: 1;
	border: none;
	border-radius: var(--hn-radius-pill);
	padding: 0.85em 1.3em;
}

.search-form {
	display: flex;
	gap: 0.6rem;
}

.search-form .search-field {
	flex: 1;
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-pill);
	padding: 0.75em 1.2em;
	font-family: inherit;
}

.archive-section .post,
.blog-archive .post {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	margin-bottom: 2rem;
	box-shadow: var(--hn-shadow-sm);
}

.archive-section .feature-image { margin: 0; aspect-ratio: 16/9; overflow: hidden; }
.archive-section .feature-image img { width: 100%; height: 100%; object-fit: cover; }
.archive-section .entry-content { padding: 1.75rem; }
.archive-section .entry-content h3 { font-size: 1.3rem; margin-bottom: 0.6rem; }

.single-page-section .entry-content { max-width: 70em; }
.single-page-section .feature-image { border-radius: var(--hn-radius-lg); overflow: hidden; margin-bottom: 2rem; }

/* ==========================================================================
   28. Confirmation / checklist / cart flow pages
   ========================================================================== */
.success-notify {
	display: flex;
	align-items: center;
	gap: 1.5rem;
	background: var(--hn-soft);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	margin-bottom: 2.5rem;
}

.success-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 60px;
	height: 60px;
	border-radius: 50%;
	background: var(--hn-gradient);
	color: var(--hn-white);
	font-size: 1.4rem;
	flex-shrink: 0;
}

.success-content h3 { font-size: 1.1rem; letter-spacing: 0.04em; margin-bottom: 0.3rem; }

.confirmation-details,
.hws-checklist-table {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
}

.confirmation-details h3 { font-size: 1rem; letter-spacing: 0.04em; margin-bottom: 1rem; }
.confirmation-details table td { padding: 0.6rem 0; border-color: var(--hn-line); }
.confirmation-details .details { margin-top: 1.5rem; }

.price-table-summary.hws-audit-summary,
.widget-bg.widget-support-wrap {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: 1.75rem;
	margin-bottom: 1.5rem;
}

.price-table-summary .bg-title { font-size: 0.95rem; margin-bottom: 1rem; }
.price-table-summary table td { padding: 0.5rem 0; }
.price-table-summary tr.total td { border-top: 1px solid var(--hn-line); font-weight: 700; padding-top: 0.75rem; }

.widget-support-wrap { text-align: center; }
.widget-support-wrap .icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border-radius: 50%;
	background: var(--hn-soft);
	color: var(--hn-violet);
	margin-bottom: 0.75rem;
}

.cart-list-inner .hws-checklist-table thead th {
	background: var(--hn-soft);
	color: var(--hn-violet-dark);
}

.checkBtnArea { margin-top: 1.5rem; }

/* ==========================================================================
   29. 404
   ========================================================================== */
.hws-404-panel {
	text-align: center;
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-lg);
	padding: clamp(2.5rem, 2rem + 2vw, 4rem);
}

.hws-404-panel > span {
	display: block;
	font-family: var(--hn-font-display);
	font-size: clamp(3.5rem, 3rem + 3vw, 6rem);
	font-weight: 700;
	line-height: 1;
	background: var(--hn-gradient);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	margin-bottom: 0.5rem;
}

.hws-404-actions {
	display: flex;
	justify-content: center;
	gap: 1rem;
	flex-wrap: wrap;
	margin-top: 1.5rem;
}

/* ==========================================================================
   30. Coming soon
   ========================================================================== */
.hws-coming-soon-section {
	min-height: 100vh;
	display: flex;
	align-items: center;
	background: var(--hn-ink);
	background-image: radial-gradient(circle at 20% 20%, rgba(155,93,229,0.35), transparent 55%), radial-gradient(circle at 80% 80%, rgba(242,165,65,0.25), transparent 55%);
	color: var(--hn-white);
	text-align: center;
	padding: 4rem 0;
}

.hws-coming-soon-section .site-title a,
.hws-coming-soon-section .hws-text-logo { color: var(--hn-white); justify-content: center; }
.hws-coming-soon-section .hws-logo-main { font-size: 1.8rem; }
/* v1.8: the roomy, centered full-lockup logo (hanady_brand_markup('dark','logo')). */
.hws-coming-soon-section .hws-image-logo img { height: 220px; }

.comming-soon-content h3 {
	font-size: 0.85rem;
	letter-spacing: 0.14em;
	color: var(--hn-violet-light);
	margin: 2rem 0 0.75rem;
}

.comming-soon-content h2 { color: var(--hn-white); margin-bottom: 2rem; }

.search-form-wrap form {
	display: flex;
	gap: 0.75rem;
	max-width: 30em;
	margin: 0 auto;
}

.search-form-wrap input {
	flex: 1;
	border: none;
	border-radius: var(--hn-radius-pill);
	padding: 0.9em 1.4em;
}

.comming-soon-footer { margin-top: 3rem; }
.comming-soon-footer .social-icons ul { list-style: none; display: flex; justify-content: center; gap: 1rem; padding: 0; margin: 0 0 1.5rem; }
.comming-soon-footer .social-icons a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: rgba(255,255,255,0.1);
	color: var(--hn-white) !important;
}
.comming-soon-footer .copy-right { color: rgba(255,255,255,0.55); font-size: 0.85rem; }

/* ==========================================================================
   31. Footer
   ========================================================================== */
/* v1.9.3: the footer was three different near-black tones stacked on top
   of each other, not one cohesive panel -- this .hws-footer rule only
   ever coloured the OUTER wrapper. Two elements nested inside it paint
   their own opaque backgrounds with higher specificity and were never
   touched: .hws-footer .top-footer (parent, (0,2,0)) fills with
   var(--hws-ink) (#17201f, a dark GREEN, no relation to this theme's
   violet-navy --hn-ink/#161326) behind the logo/Links/Contact/Legal
   columns, and .hws-footer .bottom-footer (also (0,2,0)) fills with a
   third colour, #111817, behind the copyright bar. Visually: a sliver
   of the correct violet-navy showing only where those two opaque boxes
   don't quite cover, reading as a stray gradient seam above a
   green-black block above a slightly-different near-black bar --
   three tones that were never meant to be different, not a deliberate
   multi-tone design. Pinned all three to the same token below. */
.hws-footer { background: var(--hn-ink); color: rgba(255, 255, 255, 0.75); position: relative; }
.hws-footer::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	background: var(--hn-gradient);
}
.hws-footer .top-footer { background: var(--hn-ink) !important; padding: 4rem 0 2.75rem; }
.hws-footer .bottom-footer { background: var(--hn-ink) !important; }
.hws-footer .widget-title {
	color: var(--hn-white);
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	margin-bottom: 1.25rem;
	padding-bottom: 0.75rem;
	border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.hws-footer .footer-logo { margin-bottom: 1rem; }
.hws-footer .footer-logo .hws-text-logo,
.hws-footer .footer-logo .hws-logo-main { color: var(--hn-white); }
.hws-footer .footer-logo .hws-logo-main span { color: var(--hn-violet-light); background: none; -webkit-background-clip: unset; background-clip: unset; }
/* v1.8: hanady_brand_markup('dark') here -- the -white asset variant
   already handles colour, this just sizes it for the footer column. */
.hws-footer .footer-logo .hws-image-logo img { height: 34px; }
.hws-footer p { color: rgba(255,255,255,0.65); }
.hws-footer a { color: rgba(255,255,255,0.75); }
.hws-footer a:hover { color: var(--hn-white); }

/* v1.7 (audit v3, finding 05) -- and its real root cause found in v1.9.3.
   The parent theme colours its own footer nav white via
   `.site-footer .footer-menu ul li a` -- a selector this theme's markup
   never matches (the widgets here use .hws-footer-list, not
   .footer-menu), so that parent rule never helped. The 1.7 fix below
   assumed THAT was the rule to beat and matched its "two classes + tag
   + tag" shape, which is (0,2,3) -- but the actual winning parent rule
   was a different one entirely: `.handy-web-studio-theme .widget_text
   ul li a { color: var(--hws-ink) }` (this footer's markup wraps every
   link in <aside class="widget widget_text">, which that selector does
   match), ALSO (0,2,3) once its two "ul li" type selectors are counted
   -- a specificity trap, since a plain read of "two classes" makes
   these two rules look tied when they're actually equal, and equal
   means source order decides... which should still favour this file
   (loads after the parent's), so on paper this should have worked. It
   didn't reliably enough to trust twice in the same theme, so this now
   uses !important instead of relying on re-deriving the parent's exact
   selector shape correctly every time -- var(--hws-ink) (#17201f) is
   also nearly identical to the footer's own background colour, so this
   wasn't just low-contrast, it was 9 links rendering fully invisible. */
.site-footer .hws-footer-list a {
	color: rgba(255, 255, 255, 0.85) !important;
}

.site-footer .hws-footer-list a:hover,
.site-footer .hws-footer-list a:focus-visible {
	color: var(--hn-white) !important;
}

/* The boxy outline around a single footer link in a keyboard-focus
   screenshot wasn't a bug -- it's the browser's own default :focus
   ring (this theme never styled one for footer links, so the browser
   fell back to its square, accent-coloured default). Still worth a
   deliberate, on-brand version instead of leaving it to the browser. */
.site-footer .hws-footer-list a:focus-visible {
	outline: 2px solid var(--hn-violet-light);
	outline-offset: 3px;
	border-radius: 3px;
}

.hws-footer-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }

.hws-footer-newsletter {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	background: rgba(255, 255, 255, 0.06);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	margin-top: 2.5rem;
}

.hws-footer-newsletter h3 { color: var(--hn-white); font-size: 1.15rem; margin-bottom: 0.4rem; }
.hws-footer-newsletter p { max-width: 28em; }

.hws-newsletter-form {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	align-items: center;
}

.hws-newsletter-form input[type="email"] {
	border: none;
	border-radius: var(--hn-radius-pill);
	padding: 0.75em 1.2em;
	min-width: 220px;
}

.hws-consent-line {
	display: flex;
	align-items: center;
	gap: 0.5em;
	font-size: 0.78rem;
	color: rgba(255,255,255,0.6);
}

.hws-footer-socials ul { list-style: none; display: flex; gap: 0.75rem; padding: 0; margin: 2rem 0 0; }
.hws-footer-socials a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.08);
}
.hws-footer-socials a:hover { background: var(--hn-gradient); }

.bottom-footer {
	border-top: 1px solid rgba(255, 255, 255, 0.1);
	padding: 1.5rem 0;
}

.bottom-footer .container {
	display: flex;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 0.5rem;
	font-size: 0.82rem;
}

/* ==========================================================================
   32. Back to top
   ========================================================================== */
.to-top-icon {
	position: fixed;
	right: 1.5rem;
	bottom: 1.5rem;
	width: 46px;
	height: 46px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: var(--hn-gradient);
	color: var(--hn-white) !important;
	box-shadow: var(--hn-shadow-violet);
	opacity: 0;
	visibility: hidden;
	transform: translateY(12px);
	transition: opacity 0.3s var(--hn-ease), transform 0.3s var(--hn-ease), visibility 0.3s;
	z-index: 400;
}

.to-top-icon.is-visible {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

/* ==========================================================================
   33. Tabs / accordion (career detail)
   ========================================================================== */
.responsive-tabs .nav-tabs {
	border: none;
	gap: 0.5rem;
	margin-bottom: 1.25rem;
}

.responsive-tabs .nav-link {
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-pill);
	color: var(--hn-ink-soft);
	font-weight: 600;
	padding: 0.55em 1.3em;
}

.responsive-tabs .nav-link.active {
	background: var(--hn-gradient);
	border-color: transparent;
	color: var(--hn-white);
}

.responsive-tabs .card {
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-md);
	margin-bottom: 0.75rem;
	overflow: hidden;
}

.responsive-tabs .card-header { background: var(--hn-soft); border: none; padding: 0; }
.responsive-tabs .card-header a { display: block; padding: 1rem 1.25rem; font-weight: 700; color: var(--hn-ink); }
.responsive-tabs .card-body { padding: 1.25rem; }

/* ==========================================================================
   34. Tables
   ========================================================================== */
table.table,
.hws-checklist-table table {
	width: 100%;
	border-collapse: collapse;
}

table.table th,
table.table td {
	padding: 0.75rem 1rem;
	border-bottom: 1px solid var(--hn-line);
	text-align: left;
}

table.table thead th {
	font-size: 0.78rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--hn-violet);
}

/* ==========================================================================
   35. Utility + responsive
   ========================================================================== */
.bg-light-grey { background: var(--hn-soft); }

/* height:100% is now unconditional-auto for every card type except these
   two -- .hws-service-card (Services, opted back into equal-height via
   .hws-equal-grid/.hws-service-card-col) and .hws-plan-card/.hws-anchor-card
   (Pricing, sized by this stylesheet's own CSS Grid, not a Bootstrap row).
   Both are intentionally equal-height on desktop, where 3-4 similarly
   short cards sit side by side and stretch reads as tidy, not wasteful --
   but once they stack to a single column below 992px that justification
   is gone, so auto here too. */
@media (max-width: 991.98px) {
	.hws-service-card,
	.hws-plan-card,
	.hws-anchor-card {
		height: auto;
	}
}

@media (max-width: 991.98px) {
	.hws-hero-media { margin-top: 2.5rem; }
	.hws-founder-section .col-lg-5 { margin-bottom: 2rem; }
	.hws-about-summary { position: static; margin-top: 2rem; }
	.hws-plan-detail-wrap .single-packge-wrap { padding: 1.75rem; }
}

@media (max-width: 575.98px) {
	.hws-header-inner { gap: 1rem; }
	.hws-footer-newsletter { flex-direction: column; align-items: flex-start; }
	.hws-newsletter-form { width: 100%; }
	.hws-newsletter-form input[type="email"] { flex: 1; min-width: 0; }
}

/* ==========================================================================
   36. Homepage additions (v1.1)
   ========================================================================== */

/* --- Proof: stats + testimonials (replaces the old flat proof strip) --- */
.hws-proof-section {
	background: var(--hn-ink);
	color: var(--hn-white);
	position: relative;
	overflow: hidden;
}

.hws-proof-section::before {
	content: "";
	position: absolute;
	inset: 0;
	background: radial-gradient(circle at 85% 0%, rgba(155, 93, 229, 0.28), transparent 55%);
	pointer-events: none;
}

.hws-proof-section .container { position: relative; z-index: 1; }
.hws-proof-section .sub-title { color: var(--hn-violet-light); }
.hws-proof-section .sub-title::before { background: var(--hn-gradient-warm); }
.hws-proof-section .section-title { color: var(--hn-white); }

.hws-proof-metrics {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
	gap: 1px;
	background: rgba(255, 255, 255, 0.1);
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	margin-bottom: 2.5rem;
}

.hws-proof-metric {
	background: var(--hn-ink);
	padding: 1.75rem 1.5rem;
	text-align: center;
}

.hws-proof-metric strong {
	display: block;
	font-family: var(--hn-font-display);
	font-size: clamp(1.6rem, 1.3rem + 1vw, 2.1rem);
	font-weight: 700;
	color: var(--hn-white);
	margin-bottom: 0.35rem;
}

.hws-proof-metric span {
	display: block;
	font-size: 0.78rem;
	color: rgba(255, 255, 255, 0.6);
	line-height: 1.4;
}

.hws-proof-metric-highlight strong {
	background: var(--hn-gradient-warm);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

.hws-proof-quote-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: 1.5rem;
}

/* The parent's global `blockquote:before` (style.css:321) paints a large
   FontAwesome quote glyph at left:30px/top:30px, z-index:-1 -- meant to sit
   almost invisibly behind pale quote blocks on the parent's own light
   background. Within these violet/dark cards it paints on top of the card
   background but behind the text (negative z-index only clears the
   stacking context's own background, not everything above it), producing
   a pale mark visibly colliding with the opening words. A class selector
   for :before out-specifies the parent's bare-element one, so this needs
   no parent edit. */
.hws-proof-quote::before {
	content: none;
}

.hws-proof-quote {
	background: rgba(255, 255, 255, 0.04);
	border: 1px solid rgba(255, 255, 255, 0.12);
	border-radius: var(--hn-radius-lg);
	padding: 1.85rem;
	margin: 0;
}

.hws-proof-quote-featured {
	background: var(--hn-gradient);
	border-color: transparent;
}

.hws-proof-quote p {
	font-family: var(--hn-font-display);
	font-size: 1.02rem;
	color: rgba(255, 255, 255, 0.92);
	line-height: 1.55;
	margin-bottom: 1.5rem;
}

.hws-proof-quote footer {
	display: flex;
	align-items: center;
	gap: 0.85rem;
	font-size: 0.85rem;
	color: rgba(255, 255, 255, 0.7);
}

.hws-proof-quote footer strong { color: var(--hn-white); font-weight: 700; }

.hws-proof-avatar {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.14);
	font-size: 0.75rem;
	font-weight: 700;
	color: var(--hn-white);
	flex-shrink: 0;
}

.hws-proof-quote-featured .hws-proof-avatar { background: rgba(255, 255, 255, 0.24); }

/* --- AI demo --- */
/* background moved to the section-3 alternation block (v1.7, finding 11)
   -- this used to duplicate/contradict it, since an identical-specificity
   rule later in the file always wins regardless of what the earlier one
   said. */

.hws-demo-chat {
	background: var(--hn-white);
	border-radius: var(--hn-radius-lg);
	box-shadow: var(--hn-shadow-lg);
	overflow: hidden;
	border: 1px solid var(--hn-line);
}

.hws-demo-chat-head {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.9rem 1.25rem;
	background: var(--hn-ink);
}

.hws-demo-dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(255, 255, 255, 0.25); }
.hws-demo-dot:nth-child(1) { background: #f2764a; }
.hws-demo-dot:nth-child(2) { background: #f2a541; }
.hws-demo-dot:nth-child(3) { background: #9b5de5; }

.hws-demo-chat-label {
	margin-left: 0.75rem;
	font-size: 0.78rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.65);
}

.hws-demo-chat-body { padding: 1.75rem 1.5rem 1.25rem; }

.hws-demo-bubble {
	max-width: 85%;
	padding: 0.85em 1.1em;
	border-radius: var(--hn-radius-md);
	font-size: 0.92rem;
	line-height: 1.5;
	margin-bottom: 0.9rem;
}

.hws-demo-bubble-customer {
	background: var(--hn-soft);
	color: var(--hn-ink-soft);
	border-bottom-left-radius: 4px;
}

.hws-demo-bubble-reply {
	/* v1.7.1 (design-system brief): solid primary, not the gradient --
	   the gradient is reserved for hero-level moments (the CTA button,
	   badges); a chat bubble reads as one flat colour like any real
	   messaging UI. */
	background: var(--hn-violet);
	color: var(--hn-white);
	margin-left: auto;
	border-bottom-right-radius: 4px;
}

.hws-demo-status {
	display: inline-flex;
	align-items: center;
	gap: 0.45em;
	font-size: 0.76rem;
	font-weight: 700;
	color: var(--hn-violet-dark);
}

.hws-demo-status i { font-size: 0.5em; color: var(--hn-amber); }

.hws-demo-chat-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	padding: 1rem 1.5rem 1.5rem;
	border-top: 1px solid var(--hn-line);
}

.hws-demo-chat-chips span {
	font-size: 0.78rem;
	font-weight: 600;
	color: var(--hn-ink-soft);
	background: var(--hn-soft);
	border-radius: var(--hn-radius-pill);
	padding: 0.4em 0.9em;
}

.hws-demo-points {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 1.5rem;
}

.hws-demo-points li {
	position: relative;
	padding-left: 1.4rem;
	border-left: 3px solid var(--hn-violet);
}

.hws-demo-points h3 { font-size: 1.05rem; margin-bottom: 0.35rem; }
.hws-demo-points p { margin: 0; font-size: 0.94rem; }

@media (max-width: 991.98px) {
	.hws-demo-points { margin-top: 2.5rem; }
}

/* --- Pricing anchors (homepage) --- */
.hws-anchor-card { position: relative; overflow: visible; }

.hws-anchor-card-featured {
	background: var(--hn-ink);
	background-image: var(--hn-gradient);
	color: var(--hn-white);
	transform: scale(1.02);
}

.hws-anchor-card-featured .hws-card-kicker,
.hws-anchor-card-featured h3,
.hws-anchor-card-featured p,
.hws-anchor-card-featured .hws-anchor-price { color: var(--hn-white); }

.hws-anchor-card-featured .hws-check-list li { color: rgba(255, 255, 255, 0.85); }
.hws-anchor-card-featured .hws-check-list li::before { color: var(--hn-amber); }

.hws-anchor-badge {
	position: absolute;
	top: -12px;
	right: 1.75rem;
	background: var(--hn-gradient-warm);
	color: var(--hn-white);
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	padding: 0.4em 0.9em;
	border-radius: var(--hn-radius-pill);
	box-shadow: 0 8px 18px rgba(242, 118, 74, 0.35);
}

.hws-anchor-price {
	display: flex;
	align-items: baseline;
	gap: 0.4em;
	font-family: var(--hn-font-display);
	font-size: 1.9rem;
	font-weight: 700;
	color: var(--hn-ink);
	margin: 0.6rem 0 1rem;
}

.hws-anchor-price small {
	font-family: var(--hn-font-body);
	font-size: 0.72rem;
	font-weight: 600;
	color: var(--hn-muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.hws-anchor-card-featured .hws-anchor-price small { color: rgba(255, 255, 255, 0.7); }

/* v1.7.1 (design-system brief): the founding-client pricing restructure --
   a compact three-tier breakdown for Content and Social Run (Standard/
   Growth/Premium) instead of one flat price, a "Book this" secondary CTA
   on every plan, and a shared caption explaining why the figures are
   introductory. */
.hws-tier-list {
	display: grid;
	gap: 0.75rem;
	margin: 1.25rem 0;
}

.hws-tier-row {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: baseline;
	gap: 0.4rem 0.75rem;
	padding: 0.85rem 1rem;
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-sm);
}

.hws-tier-row-featured {
	border-color: var(--hn-violet);
	background: var(--hn-soft);
}

.hws-tier-name {
	font-weight: 700;
	font-size: 0.92rem;
	color: var(--hn-ink);
}

.hws-tier-detail {
	grid-column: 1 / -1;
	font-size: 0.8rem;
	color: var(--hn-muted);
	line-height: 1.5;
}

.hws-tier-price {
	font-family: var(--hn-font-display);
	font-weight: 700;
	font-size: 1rem;
	color: var(--hn-violet-dark);
	white-space: nowrap;
}

.hws-tier-price small {
	font-family: var(--hn-font-body);
	font-weight: 600;
	font-size: 0.68rem;
	color: var(--hn-muted);
	text-transform: uppercase;
}

.hws-plan-note {
	font-size: 0.78rem;
	color: var(--hn-muted);
	margin-bottom: 1.25rem;
}

.hws-anchor-card-featured .hws-plan-note { color: rgba(255, 255, 255, 0.75); }

.hws-plan-card-cta {
	display: block;
	width: calc(100% - 4rem);
	margin: 0 2rem 2rem;
	text-align: center;
	justify-content: center;
}

.hws-trust-strip {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.6rem 1rem;
	margin-top: 2rem;
	padding: 1.25rem 1.5rem;
	background: var(--hn-soft);
	border-radius: var(--hn-radius-pill);
	text-align: center;
}

.hws-trust-strip span {
	font-size: 0.76rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	color: var(--hn-violet-dark);
	position: relative;
	padding: 0 1rem 0 0;
}

.hws-trust-strip span:not(:last-child)::after {
	content: "";
	position: absolute;
	right: -0.5rem;
	top: 50%;
	transform: translateY(-50%);
	width: 4px;
	height: 4px;
	border-radius: 50%;
	background: var(--hn-violet);
}

/* --- Audit on the page --- */
.hws-audit-demo-section { background: var(--hn-ink); color: var(--hn-white); }
.hws-audit-demo-section .sub-title { color: var(--hn-violet-light); }
.hws-audit-demo-section .section-title { color: var(--hn-white); }
.hws-audit-demo-section .section-heading p { color: rgba(255, 255, 255, 0.72); }

.hws-audit-panel {
	background: rgba(255, 255, 255, 0.04);
	border: 1px solid rgba(255, 255, 255, 0.12);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
}

.hws-audit-panel label {
	display: block;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.55);
	margin-bottom: 0.5rem;
}

.hws-audit-panel input[type="text"],
.hws-audit-panel input[type="email"],
.hws-audit-panel input[type="url"] {
	width: 100%;
	border: 1px solid rgba(255, 255, 255, 0.18);
	background: rgba(255, 255, 255, 0.06);
	color: var(--hn-white);
	border-radius: var(--hn-radius-sm);
	padding: 0.85em 1em;
	margin-bottom: 1.5rem;
	font-family: inherit;
	transition: border-color 0.2s var(--hn-ease), background 0.2s var(--hn-ease);
}

.hws-audit-panel input::placeholder { color: rgba(255, 255, 255, 0.35); }

.hws-audit-panel input:focus {
	outline: none;
	border-color: var(--hn-violet-light);
	background: rgba(255, 255, 255, 0.1);
}

.hws-business-type-group {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
	margin-bottom: 1.5rem;
}

.hws-business-type-group input {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	pointer-events: none;
}

.hws-business-type-group label {
	/* v1.7 (audit v3, finding 07): measured at 39px, closest of the four
	   to the 44px minimum but still short -- align-items on the group
	   plus min-height here closes the gap. */
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	margin: 0;
	text-transform: none;
	letter-spacing: 0;
	font-size: 0.85rem;
	font-weight: 600;
	color: rgba(255, 255, 255, 0.8);
	background: rgba(255, 255, 255, 0.06);
	border: 1px solid rgba(255, 255, 255, 0.16);
	border-radius: var(--hn-radius-pill);
	padding: 0.55em 1.15em;
	cursor: pointer;
	transition: background 0.2s var(--hn-ease), border-color 0.2s var(--hn-ease), color 0.2s var(--hn-ease);
}

.hws-business-type-group input:checked + label {
	background: var(--hn-gradient);
	border-color: transparent;
	color: var(--hn-white);
}

.hws-business-type-group input:focus-visible + label {
	outline: 2px solid var(--hn-violet-light);
	outline-offset: 2px;
}

.hws-audit-panel-note {
	font-size: 0.8rem;
	color: rgba(255, 255, 255, 0.55);
	margin-top: 1rem;
}

.hws-audit-report {
	background: var(--hn-white);
	border-radius: var(--hn-radius-lg);
	padding: 2rem;
	color: var(--hn-ink);
	box-shadow: var(--hn-shadow-lg);
}

.hws-audit-report-head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 1rem;
	border-bottom: 1px solid var(--hn-line);
	padding-bottom: 1rem;
	margin-bottom: 1.25rem;
}

.hws-audit-report-head h3 { font-size: 1.1rem; margin: 0; }
.hws-audit-report-head span { font-size: 0.78rem; color: var(--hn-violet); font-weight: 700; white-space: nowrap; }

.hws-audit-finding {
	display: grid;
	grid-template-columns: 32px 1fr;
	gap: 0.9rem;
	margin-bottom: 1.25rem;
}

.hws-audit-finding-number {
	font-family: var(--hn-font-display);
	font-weight: 700;
	font-size: 1.15rem;
	color: var(--hn-violet);
}

.hws-audit-finding h4 { font-size: 0.98rem; margin: 0 0 0.3rem; }
.hws-audit-finding p { margin: 0; font-size: 0.88rem; }

.hws-audit-tag {
	display: inline-block;
	font-size: 0.72rem;
	font-weight: 700;
	padding: 0.15em 0.55em;
	border-radius: 5px;
	margin-left: 0.4em;
	white-space: nowrap;
}

.hws-audit-tag-urgent { background: #fdeceb; color: #b3261e; }
.hws-audit-tag-worth { background: var(--hn-soft); color: var(--hn-violet-dark); }
.hws-audit-tag-later { background: #eef1ee; color: #5b5770; }

.hws-audit-report-foot {
	border-top: 1px solid var(--hn-line);
	padding-top: 1.1rem;
	font-size: 0.85rem;
	color: var(--hn-muted);
	font-style: italic;
}

/* v1.7 (audit v3, finding 08): the plain rgba(255,255,255,.5) declared
   here computed to rgb(83,96,93) on the dark section -- a higher-
   specificity parent rule (some p{color:var(--hws-muted)} scoped to this
   section) was winning instead, at 2.77:1 contrast against a 4.5:1
   minimum. `.hws-audit-demo-section` prefix matches that specificity and
   lightens the value per the audit's own suggested figure. */
.hws-audit-demo-section .hws-audit-report-caption {
	text-align: center;
	font-size: 0.78rem;
	color: rgba(255, 255, 255, 0.62);
	margin-top: 1rem;
}

/* --- Team + objections --- */
.hws-team-objections-section { background: var(--hn-paper); }

.hws-team-photo {
	border-radius: var(--hn-radius-lg);
	overflow: hidden;
	aspect-ratio: 4 / 5;
	background: var(--hn-soft);
}

.hws-team-photo img { width: 100%; height: 100%; object-fit: cover; }

/* Branded initial avatar -- a deliberate, finished-looking placeholder
   (not a diagonal-hatch "missing asset" pattern) for when no real founder
   photo has been set yet. See front-page.php's audit-recheck point 03. */
.hws-team-photo-placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--hn-gradient);
}

.hws-team-photo-initial {
	font-family: var(--hn-font-display);
	font-size: 5rem;
	font-weight: 700;
	color: rgba(255, 255, 255, 0.92);
}

.hws-team-intro { margin-top: 1.75rem; }
.hws-team-intro h3 { font-size: 1.2rem; margin-bottom: 0.2rem; }
.hws-team-intro .hws-founder-role { color: var(--hn-violet-dark) !important; }

/* v1.9.2: page-about.php's founder section sits photo/text side-by-side
   (col-lg-5 / col-lg-7) instead of stacked in one narrow column like the
   homepage's #team block -- the 1.75rem top margin above is meant for
   the stacked case (spacing the intro below the photo in the same
   column) and would just misalign the two columns' vertical centring
   here. */
.hws-about-founder .hws-team-intro { margin-top: 0; }

.hws-objection-list { display: grid; gap: 0.9rem; margin-top: 1.75rem; }

.hws-objection-item {
	background: var(--hn-white);
	border: 1px solid var(--hn-line);
	border-radius: var(--hn-radius-md);
	padding: 1.35rem 1.6rem;
}

.hws-objection-item h4 {
	font-size: 0.98rem;
	margin: 0 0 0.4rem;
	display: flex;
	align-items: baseline;
	gap: 0.5em;
}

.hws-objection-item h4::before {
	content: "Q";
	font-family: var(--hn-font-body);
	font-size: 0.68rem;
	font-weight: 800;
	color: var(--hn-white);
	background: var(--hn-gradient);
	width: 20px;
	height: 20px;
	border-radius: 50%;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
}

.hws-objection-item p { margin: 0; font-size: 0.9rem; }

@media (max-width: 991.98px) {
	.hws-anchor-card-featured { transform: none; }
	.hws-team-photo { margin-bottom: 1rem; }
}

@media (max-width: 767.98px) {
	.hws-proof-metrics { grid-template-columns: repeat(2, 1fr); }
	.hws-audit-report-head { flex-direction: column; align-items: flex-start; }
}

/* ==========================================================================
   37. Teal-to-violet compat (v1.8.1, audit 2026-09-13)
   ========================================================================== */

/* The parent stylesheet's own `.handy-web-studio-theme` rule (its
   style.css, not this one) still defines --hws-teal/--hws-teal-dark as an
   actual teal (#14796f / #0d5e56) and several parent-only components read
   those tokens directly rather than this child's --hn-violet ones. Same
   selector, same specificity, and this file loads after the parent's, so
   redeclaring the two variables here repoints every one of those
   consumers at violet with a single edit -- no need to chase each parent
   rule that happens to reference --hws-teal today, or the next one a
   parent-theme update adds tomorrow. */
.handy-web-studio-theme {
	--hws-teal: var(--hn-violet);
	--hws-teal-dark: var(--hn-violet-dark);
}

/* v1.9.1: this block used to redeclare round-btn/outline-btn background
   and border-color at `.handy-web-studio-theme .x` specificity as a
   cache/regression guard. It's now retired -- a real hover-state bug
   (see section 4's comment above .round-btn) showed that matching the
   parent's specificity isn't reliable, because the parent's own hover
   rules live at that same `.handy-web-studio-theme .x:hover`
   specificity and a source-order tie could still go either way. Section
   4 now uses !important on every contested property instead, which wins
   regardless of specificity or source order. Nothing here still does
   anything (every property it set is now also set, with !important, in
   section 4), so the redundant declarations were removed rather than
   left to contradict the real fix and confuse the next read-through. */
