/* The pre-port design system, lifted out of base.html's inline <style>.

   This is not new code. It is the 839 lines base.html used to emit inline,
   moved to a file so the surfaces that have not been ported yet -- cart,
   orders, accounts, allauth, and every cms/ page template still awaiting its
   turn -- keep rendering while the port is in progress.

   It is scheduled for deletion. Every rule in here is superseded the moment
   the template that depends on it is ported, and the last commit of the port
   removes the file. Do not add to it; new work belongs in
   static/css/src/thusa.css.

   Loaded BEFORE tailwind.css in base.html so the ported design wins every
   collision. */


        * { box-sizing: border-box; }
        html, body {
            margin: 0;
            padding: 0;
            background: var(--canvas);
            color: var(--fg);
            font-family: var(--font-body);
            -webkit-font-smoothing: antialiased;
            text-rendering: optimizeLegibility;
        }
        body {
            font-size: 17px;
            line-height: 1.6;
            font-weight: 400;
        }
        /* `color` is deliberately NOT reset here. Tailwind's preflight already
           does it, and does it inside @layer base, where a text-* utility can
           still win. This rule is unlayered, so an unlayered `color` here beats
           every layered utility regardless of specificity -- which is what made
           .text-ink lose and rendered white-on-white buttons. */
        a { text-decoration: none; }
        /* Same rule, same reason: `font` and `color` are left to preflight.
           The `font` shorthand here made every <button> render at the body's
           17px/400 no matter what text-* or font-* utility it carried, which
           is why the two mega-menu triggers sat larger and lighter than the
           plain nav links beside them. */
        button { background: none; border: 0; cursor: pointer; }
        .mono { font-family: var(--font-mono); font-weight: 400; letter-spacing: 0.04em; }
        .accent { color: var(--mag); }

        /*
        Shared container + section utilities (used across all page templates).

        90vw with a 1280px floor, not a flat 1280px. The reporter of this was on a
        2560px viewport, where a 1280px shell used half the screen and read as a
        narrow column floating in the middle of the page.

        The floor is what makes 90vw safe: below a ~1422px viewport the 1280px term
        wins, exceeds the viewport, and the container falls back to full width minus
        its own 40px padding -- exactly the previous behaviour. Without it, 90vw
        would stack a 5vw gutter on top of that padding and make phones narrower.

        This widens only the outer shell. Per-page inner max-widths (prose columns
        at 760-860px, hero copy at 580px) still govern measure.
        */
        .container, .th-container {
            max-width: max(1280px, 90vw);
            margin: 0 auto;
            padding: 0 40px;
        }
        /*
        Prose shell. The measure goes on the children, not on the container, so the
        column's left edge stays on the container's own gutter -- the same edge the
        page hero sits on.

        Page templates used to carry the measure as an inline `max-width` on the
        `.container` itself, which overrode the shell's width and centred an 800px
        column in the viewport. At a 1280px shell that read as intentional; once the
        shell went to 90vw the body column drifted several hundred pixels away from
        the hero above it.
        */
        .prose-shell > * { max-width: var(--prose-measure, 860px); }
        .th-section { padding: 120px 0; }
        .th-section-dark { background: var(--canvas); }
        .th-section-surface { background: var(--card); }
        .hairline { height: 1px; background: var(--line); width: 100%; }

        /* Eyebrow / section label (used by index pages, content pages) */
        .section-label {
            font-family: var(--font-mono);
            font-size: 11px;
            letter-spacing: 0.22em;
            text-transform: uppercase;
            color: var(--fg-2);
            display: inline-flex;
            align-items: center;
            gap: 12px;
        }
        .section-label::before {
            content: "";
            width: 18px;
            height: 1px;
            background: var(--mag);
        }
        .th-eyebrow {
            display: inline-flex;
            align-items: center;
            gap: 10px;
            padding: 6px 12px;
            border: 1px solid var(--line);
            border-radius: 999px;
            font-family: var(--font-mono);
            font-size: 11px;
            color: var(--fg-2);
            letter-spacing: 0.14em;
            text-transform: uppercase;
            margin-bottom: 24px;
        }
        .th-eyebrow-dot {
            width: 6px;
            height: 6px;
            background: var(--mag);
            border-radius: 50%;
        }

        /* Primary button (shared with home page hero, final CTA, inline CTAs) */
        .btn-primary {
            display: inline-flex;
            align-items: center;
            gap: 12px;
            background: var(--mag);
            color: #fff;
            font-weight: 600;
            font-size: 14px;
            letter-spacing: 0.02em;
            padding: 16px 22px;
            border-radius: var(--r);
            transition: all 0.2s ease;
        }
        .btn-primary:hover {
            background: var(--mag-press);
            transform: translateY(-1px);
            box-shadow: 0 8px 30px -10px color-mix(in srgb, var(--mag) 60%, transparent);
        }
        .btn-primary .arr {
            width: 16px;
            height: 1px;
            background: currentColor;
            position: relative;
        }
        .btn-primary .arr::after {
            content: "";
            position: absolute;
            right: 0;
            top: -4px;
            width: 9px;
            height: 9px;
            border-top: 1.5px solid currentColor;
            border-right: 1.5px solid currentColor;
            transform: rotate(45deg);
        }
        .btn-ghost {
            display: inline-flex;
            align-items: center;
            gap: 10px;
            font-size: 14px;
            color: var(--fg-2);
            font-weight: 500;
            border-bottom: 1px solid var(--line);
            padding-bottom: 4px;
            transition: all 0.2s ease;
        }
        .btn-ghost:hover { color: var(--fg); border-color: var(--fg-2); }

        /* ===== NAV ===== */
        /*
        --nav-rule is a token, not a magic number, because two rules depend on
        the same value: the bar's own bottom border, and the mega panel's top
        offset. An absolutely-positioned `top: 100%` resolves against the
        containing block's PADDING box, so the panel would otherwise open 2px
        high and cover the rule it is supposed to hang from.
        */
        .nav {
            --nav-rule: 2px;
            position: fixed;
            top: 0; left: 0; right: 0;
            z-index: var(--z-nav);
            background: color-mix(in srgb, var(--canvas) 72%, transparent);
            backdrop-filter: blur(14px);
            -webkit-backdrop-filter: blur(14px);
            border-bottom: var(--nav-rule) solid var(--mag);
        }
        /*
        Flush variant for pages that own a full-bleed hero: the bar tints down so
        the artwork still reads through it, but it keeps the blur.

        The blur used to be dropped here on the grounds that a filter creates a
        containing block. That hazard is real but it only reaches position:FIXED
        descendants -- which is why the mobile panel lives outside <nav> (see the
        comment above it). The mega panel is position:absolute and resolves to
        .nav either way, since .nav is itself positioned. So neither panel is
        trapped by restoring the filter, and the bar stays legible over a
        full-bleed hero at the top of the page instead of only after scrolling.

        The 2px magenta base rule is inherited from .nav and deliberately not
        overridden: it is the brand's edge on the bar and it reads on every
        route, flush or not.
        */
        .nav--flush {
            background: color-mix(in srgb, var(--canvas) 45%, transparent);
        }
        .nav-inner {
            display: flex;
            align-items: center;
            justify-content: space-between;
            height: var(--nav-h);
        }
        /*
        The mega panel is edge-to-edge, so its containing block must be .nav
        (already position:fixed) and NOT .nav-inner, which .container constrains
        to the text column. Every nav item therefore stays static so the panel
        resolves up to the bar, and the bar must not clip it.
        */
        .nav { overflow: visible; }
        /*
        Nav and footer align to the same centred column as page content. Not by
        editing .container -- that is shared with the cart, account and product
        templates, and its max(1280px, 90vw) rule is a decision with a written
        rationale. Overriding it only inside the 1b chrome keeps both true.
        */
        .nav .nav-inner,
        footer > .container {
            max-width: none;
            padding-inline: var(--pad-x);
        }
        .nav-links { height: 100%; }
        .nav-links > li { position: static; }
        /*
        The mega-menu items must fill the full bar height, or the menu becomes
        unusable: the panel opens at the BOTTOM of the bar, while a flex-centred
        <li> is only as tall as its own text. That left a dead band between the
        link and the panel -- crossing it dropped :hover and the panel closed
        before the pointer arrived, so nothing inside it could be clicked.

        Making the trigger span the bar means the item box and the panel share an
        edge, so the pointer never leaves the hovered subtree on the way down.
        */
        .nav-links > li.th-has-mega { display: flex; align-items: center; height: 100%; }
        .nav-links > li.th-has-mega > a { display: flex; align-items: center; height: 100%; }
        .brand {
            display: flex;
            align-items: center;
            gap: 10px;
            font-weight: 700;
            letter-spacing: 0.14em;
            font-size: 14px;
        }
        .brand .dot {
            width: 8px;
            height: 8px;
            background: var(--mag);
            border-radius: 1px;
            box-shadow: 0 0 10px color-mix(in srgb, var(--mag) 70%, transparent);
        }
        /*
        Sized by height with width:auto so the client's own aspect ratio governs --
        a second client's wordmark will not be squashed to Thusa's proportions.
        */
        .brand img { height: 22px; width: auto; display: block; }
        .foot-brand .brand img { height: 40px; }
        .brand small {
            font-family: var(--font-mono);
            color: var(--fg-2);
            font-weight: 400;
            letter-spacing: 0.1em;
            font-size: 11px;
            margin-left: 8px;
            padding-left: 10px;
            border-left: 1px solid var(--line);
        }
        .nav-links {
            display: flex;
            align-items: center;
            gap: 36px;
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .nav-links a {
            font-size: 13px;
            color: var(--fg-2);
            font-weight: 500;
            letter-spacing: 0.02em;
            transition: color 0.18s ease;
        }
        .nav-links a:hover { color: var(--fg); }
        .nav-cta {
            display: inline-flex;
            align-items: center;
            gap: 10px;
            font-size: 13px;
            font-weight: 600;
            padding: 9px 16px;
            border: 1px solid var(--line);
            border-radius: var(--r);
            transition: all 0.2s ease;
            color: var(--fg);
        }
        .nav-cta:hover { border-color: var(--mag); color: var(--fg); }
        .nav-cta .arr {
            width: 14px;
            height: 1px;
            background: currentColor;
            position: relative;
            transition: width 0.2s ease;
        }
        .nav-cta .arr::after {
            content: "";
            position: absolute;
            right: 0;
            top: -3px;
            width: 7px;
            height: 7px;
            border-top: 1px solid currentColor;
            border-right: 1px solid currentColor;
            transform: rotate(45deg);
        }
        .nav-cta:hover .arr { width: 20px; }

        /* ===== MOBILE NAV (hamburger) ===== */
        .nav-toggle {
            display: none;
            width: 36px;
            height: 36px;
            border: 1px solid var(--line);
            border-radius: var(--r);
            background: transparent;
            cursor: pointer;
            padding: 0;
            align-items: center;
            justify-content: center;
            color: var(--fg);
            transition: border-color 0.2s ease;
        }
        .nav-toggle:hover { border-color: var(--mag); }
        .nav-toggle span,
        .nav-toggle span::before,
        .nav-toggle span::after {
            display: block;
            position: relative;
            width: 16px;
            height: 1.5px;
            background: currentColor;
            transition: transform 0.25s ease, opacity 0.18s ease, top 0.25s ease;
        }
        .nav-toggle span::before,
        .nav-toggle span::after {
            content: "";
            position: absolute;
            left: 0;
        }
        .nav-toggle span::before { top: -5px; }
        .nav-toggle span::after  { top: 5px; }
        .nav-toggle[aria-expanded="true"] span { background: transparent; }
        .nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
        .nav-toggle[aria-expanded="true"] span::after  { top: 0; transform: rotate(-45deg); }

        .nav-mobile {
            position: fixed;
            inset: var(--nav-h) 0 0 0;
            z-index: calc(var(--z-nav) - 1);
            background: var(--canvas);
            padding: 24px;
            border-top: 1px solid var(--line-soft);
            /* The panel now carries disclosure groups and can exceed the
               viewport, so it has to scroll itself rather than the page behind. */
            overflow-y: auto;
            overscroll-behavior: contain;
            display: none;
            flex-direction: column;
            gap: 0;
            overflow-y: auto;
        }
        .nav-mobile[data-open="true"] { display: flex; }

        .site-main { padding-top: var(--nav-h); }
        /*
        Article pages used to narrow the WHOLE column to 900px, which put every
        article template -- offering, outcome, blog, content, case study, team,
        support, client -- on a visibly different column from the home page.
        At a 2560px viewport home ran ~2300px and an outcome page ran 900px,
        which is what "the content is shrunk into the centre of the page" on
        Pulse 8d8207e7 is describing. It is one clamp shared by eight
        templates, not a per-page problem.

        So the column is no longer narrowed: article pages inherit the same
        --content-max and --pad-x as home and land on its edges exactly.

        The measure moves to the running text instead, which is how the home
        page already works -- its sections and grids run the full shell while
        its own hero copy sits on a ~580px measure. Headings, tables, images,
        FAQ blocks and card grids therefore span the full column, and only
        paragraphs and list items keep a line length you can actually read.
        Without this, a paragraph at 2560px runs about 250 characters.
        */
        /*
        Nothing inside an article is measure-capped. The scope brief carried a
        readability cap on running text as an open assumption, on the reasoning
        that home caps its own hero copy; it was vetoed. "The same visual
        distance the home page content spans" means the text too, not just the
        containers around it, so the cap is gone rather than narrowed.

        --prose-measure is left in place and still honoured by .prose-shell on
        non-article pages. It is the knob to reach for if this is ever revisited.
        */
        .site-main--article .prose-shell > * { max-width: none; }
        .site-main--flush { padding-top: 0; }
        .nav-mobile a {
            font-size: 18px;
            font-weight: 600;
            color: var(--fg);
            padding: 18px 4px;
            border-bottom: 1px solid var(--line-soft);
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        .nav-mobile a::after {
            content: "→";
            color: var(--fg-3);
            font-size: 16px;
            transition: color 0.18s ease, transform 0.18s ease;
        }
        .nav-mobile a:hover::after,
        .nav-mobile a:focus::after { color: var(--mag); transform: translateX(2px); }
        .nav-mobile .nav-cta {
            margin-top: 24px;
            justify-content: center;
            padding: 14px 22px;
            font-size: 14px;
            border-color: var(--mag);
            background: var(--mag);
            color: #fff;
        }
        .nav-mobile .nav-cta:hover { background: var(--mag-press); }
        .nav-mobile .nav-cta::after { content: none; }
        body.nav-locked { overflow: hidden; }

        /* ===== FOOTER ===== */
        footer {
            padding: 72px 0 36px;
            background: var(--canvas);
            border-top: 1px solid var(--line-soft);
            margin-top: 80px;
        }
        .foot-grid {
            display: grid;
            grid-template-columns: 1.4fr 1fr 1fr 1fr;
            gap: 48px;
            margin-bottom: 56px;
        }
        .foot-brand p {
            font-size: 13px;
            color: var(--fg-2);
            line-height: 1.6;
            max-width: 320px;
            margin: 18px 0 16px;
        }
        .foot-nap {
            font-style: normal;
            font-size: 12px;
            color: var(--fg-2);
            line-height: 1.7;
            margin: 0 0 16px;
            font-family: var(--font-mono);
            letter-spacing: 0.02em;
        }
        .foot-nap div { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 6px; }
        .foot-nap .ico {
            width: 14px;
            height: 14px;
            color: var(--mag);
            margin-top: 2px;
            flex-shrink: 0;
        }
        .foot-nap a { color: inherit; transition: color 0.18s ease; }
        .foot-nap a:hover { color: var(--fg); }
        .foot-reach {
            display: flex;
            align-items: flex-start;
            gap: 8px;
            font-size: 11px;
            color: var(--fg-3);
            line-height: 1.55;
            font-family: var(--font-mono);
            letter-spacing: 0.02em;
            margin-top: 12px;
        }
        .foot-col h5 {
            font-family: var(--font-mono);
            font-size: 11px;
            letter-spacing: 0.18em;
            text-transform: uppercase;
            color: var(--fg-3);
            margin: 0 0 18px;
            font-weight: 500;
        }
        .foot-col a {
            display: block;
            font-size: 13.5px;
            color: var(--fg-2);
            margin-bottom: 10px;
            transition: color 0.18s ease;
        }
        .foot-col a:hover { color: var(--mag); }
        .foot-bottom {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding-top: 28px;
            border-top: 1px solid var(--line);
            font-family: var(--font-mono);
            font-size: 11px;
            color: var(--fg-3);
            letter-spacing: 0.1em;
            flex-wrap: wrap;
            gap: 12px;
        }
        .foot-bottom .right { display: flex; gap: 24px; }

        /*
        CARDS (docx-derived offering/outcome content blocks) -- Pulse f50120c0.

        These are the cards the bug is actually about. They are authored into
        StreamField body HTML by ingest_content, not written in any template, so
        grepping templates finds nothing and they look dead. They are not: the
        class appears in the body of 11 offering pages and 3 outcome pages, which
        is every Zone 1 page the reporter could have been looking at.

        They now match the home page's tile surface -- var(--canvas) ground, a
        1px var(--line) edge and SQUARE corners. Previously they sat on
        var(--card) with a 6px var(--r) radius, so a card in body copy read as a
        different component from the tile grid directly above it on the same
        page. Home is the design system of record for this pass, so home wins.

        Type sizes move onto the --fs-* scale for the same reason: 17px/14px/13px
        literals here predate the scale and drift from every other heading.
        */
        .th-card {
            background: var(--canvas);
            border: 1px solid var(--line);
            border-radius: var(--r-0);
            padding: var(--sp-9);
            margin: var(--sp-6) 0;
            transition: border-color var(--dur-base) var(--ease);
        }
        .th-card:hover { border-color: var(--mag); }
        .th-card h4 {
            font-family: var(--font-heading);
            font-size: var(--fs-5);
            font-weight: 600;
            color: var(--fg);
            margin: 0 0 12px;
            line-height: 1.3;
        }
        .th-card p { margin: 0 0 12px; color: var(--fg-2); }
        .th-card p:last-child { margin-bottom: 0; }
        .th-card-list {
            list-style: none;
            padding: 0;
            margin: 12px 0;
        }
        .th-card-list li {
            position: relative;
            padding-left: 22px;
            margin-bottom: 8px;
            font-size: var(--fs-3);
            line-height: var(--lh-body);
            color: var(--fg-2);
        }
        .th-card-list li::before {
            content: "";
            position: absolute;
            left: 0;
            top: 9px;
            width: 6px;
            height: 6px;
            border-radius: 1px;
            background: var(--mag);
        }
        /*
        Keeps its magenta wash and left bar -- that is the callout's job and
        home has no equivalent to defer to. Only the radius is squared off, so
        it sits inside a .th-card without a rounded box inside a square one.
        */
        .th-card-outcome {
            margin-top: 14px;
            padding: 12px 14px;
            background: color-mix(in srgb, var(--mag) 8%, transparent);
            border-left: 3px solid var(--mag);
            border-radius: var(--r-0);
            font-size: var(--fs-3);
        }
        .th-card-outcome strong { color: var(--mag); }
        .th-card-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 16px;
            margin: 16px 0;
        }
        .th-card-grid .th-card { margin: 0; }
        .th-card-band h4 {
            color: var(--mag);
            font-family: var(--font-mono);
            font-size: var(--fs-2);
            letter-spacing: 0.18em;
            text-transform: uppercase;
        }

        /* ===== SECTION + PAGE HEADER UTILITIES (used by every inner template) ===== */
        .sec-header {
            display: flex;
            justify-content: space-between;
            align-items: end;
            margin-bottom: 56px;
            gap: 48px;
        }
        .sec-title .mag { color: var(--mag); }
        .sec-desc {
            font-size: 15px;
            color: var(--fg-2);
            max-width: 420px;
            text-wrap: pretty;
        }

        /* Page hero -- smaller than the homepage hero; used on offering/outcome/content pages */
        .page-h1 .mag { color: var(--mag); }

        /* Page body wrapper -- inner content (offering / outcome / content bodies) */
        /*
        Any link inside page content must read as a link. Tailwind's preflight
        sets a { color: inherit }, so a link dropped into a muted container
        (.page-body is --fg-2) inherits that grey and renders as dead text -- it
        looks like prose, not an affordance. (This reset used to live above, in
        this file, unlayered; it was removed because an unlayered colour reset
        beats every text-* utility. Preflight does the same job inside
        @layer base, where a utility can still win.) Scoped by ancestor
        rather than direct child so signposts, internal-link rows, address blocks
        and rich-text links all get the same treatment.
        */

        /* CTA block -- used at end of inner pages */

        /* Sibling / related links (pills) */

        @media (max-width: 768px) {
            .sec-header { flex-direction: column; align-items: flex-start; gap: 16px; margin-bottom: 36px; }
            .sec-desc { max-width: 100%; }
        }

        /* ===== ANIMATED ICONS (design system) =====
           Used on homepage service grid AND offerings index/individual pages.
           Restrained idle motion + decisive hover gesture per brand brief.
           Hover gestures fire when a parent .th-card OR .th-mini is hovered.   */
        .ico { color: var(--mag); overflow: visible; }
        .ico * { transform-box: fill-box; }

        /* 01 RACK -- LEDs blink in sequence */
        .ico-rack .led { transform-origin: center; animation: rack-blink 3.2s steps(1, end) infinite; opacity: 0.35; }
        .ico-rack .led.l2 { animation-delay: 0.4s; }
        .ico-rack .led.l3 { animation-delay: 0.8s; }
        @keyframes rack-blink {
            0%, 70%, 100% { opacity: 0.32; }
            8%, 22% { opacity: 1; }
            10%, 20% { opacity: 0.32; }
        }
        .th-card:hover .ico-rack .led, .th-mini:hover .ico-rack .led { animation-duration: 1.4s; }

        /* 02 SHIELD -- shell breathes; checkmark draws on hover */
        .ico-shield .shell { transform-origin: center; animation: breathe 4.2s ease-in-out infinite; }
        .ico-shield .chk { stroke-dasharray: 18; stroke-dashoffset: 18; transition: stroke-dashoffset 0.55s 0.08s cubic-bezier(0.6, 0.2, 0.2, 1); }
        .th-card:hover .ico-shield .chk, .th-mini:hover .ico-shield .chk { stroke-dashoffset: 0; }
        @keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.04); } }

        /* 03 CLOUD -- drift; hover snap */
        .ico-cloud .dl { animation: cloud-drift 3.6s ease-in-out infinite; }
        .th-card:hover .ico-cloud .dl, .th-mini:hover .ico-cloud .dl { animation: cloud-snap 0.55s cubic-bezier(0.55, 0.1, 0.3, 1.3) both; }
        @keyframes cloud-drift { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(0.8px); } }
        @keyframes cloud-snap { 0% { transform: translateY(-1.5px); } 55% { transform: translateY(2.5px); } 100% { transform: translateY(0); } }

        /* 04 NETWORK -- ring rotates; hub pulses */
        .ico-net .ring { transform-origin: center; animation: spin 18s linear infinite; stroke-dasharray: 2 3; }
        .ico-net .hub { transform-origin: center; animation: hub-pulse 2.4s ease-in-out infinite; }
        .th-card:hover .ico-net .ring, .th-mini:hover .ico-net .ring { animation-duration: 6s; }
        .th-card:hover .ico-net .hub, .th-mini:hover .ico-net .hub { animation-duration: 1.2s; }
        @keyframes spin { to { transform: rotate(360deg); } }
        @keyframes hub-pulse { 0%, 100% { transform: scale(0.85); opacity: 0.7; } 50% { transform: scale(1.1); opacity: 1; } }

        /* 05 BACKUP -- progress bar fills on hover */
        .ico-backup .bar { stroke-dasharray: 10; stroke-dashoffset: 10; transition: stroke-dashoffset 0.8s cubic-bezier(0.4, 0.2, 0.2, 1); }
        .ico-backup .led-b { transform-origin: center; animation: rack-blink 2.6s steps(1, end) infinite; opacity: 0.4; }
        .th-card:hover .ico-backup .bar, .th-mini:hover .ico-backup .bar { stroke-dashoffset: 0; }
        .th-card:hover .ico-backup .led-b, .th-mini:hover .ico-backup .led-b { animation-duration: 1s; }

        /* 06 MONITOR -- scanline + cursor */
        .ico-screen .scan { transform-origin: center; animation: scan 3.4s ease-in-out infinite; opacity: 0; }
        .ico-screen .cursor { animation: cursor-blink 1.2s steps(1, end) infinite; }
        .th-card:hover .ico-screen .scan, .th-mini:hover .ico-screen .scan { animation-duration: 1.6s; opacity: 1; }
        @keyframes scan { 0%, 100% { transform: translateY(-4px); opacity: 0; } 50% { transform: translateY(4px); opacity: 0.9; } }
        @keyframes cursor-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

        /* 07 STRATEGY -- signal pulses, sonar wave on hover */
        .ico-strat .signal { transform-origin: center; animation: hub-pulse 2.2s ease-in-out infinite; }
        .ico-strat .wave { transform-origin: center; animation: wave 2.4s ease-out infinite; opacity: 0; }
        .th-card:hover .ico-strat .signal, .th-mini:hover .ico-strat .signal { animation-duration: 1.1s; }
        .th-card:hover .ico-strat .wave, .th-mini:hover .ico-strat .wave { opacity: 1; }
        @keyframes wave { 0% { transform: scale(0.6); opacity: 0.8; } 100% { transform: scale(2.2); opacity: 0; } }

        /* 08 RETICLE -- slow rotation; locks at 45deg on hover */
        .ico-reticle .ret { transform-origin: center; animation: spin 22s linear infinite; }
        .ico-reticle .hit { transform-origin: center; animation: hub-pulse 2.6s ease-in-out infinite; }
        .th-card:hover .ico-reticle .ret, .th-mini:hover .ico-reticle .ret { animation: reticle-lock 0.6s cubic-bezier(0.5, 0.1, 0.2, 1.2) forwards; }
        .th-card:hover .ico-reticle .hit, .th-mini:hover .ico-reticle .hit { animation-duration: 0.9s; }
        @keyframes reticle-lock {
            0% { transform: rotate(0) scale(1); }
            60% { transform: rotate(45deg) scale(0.85); }
            100% { transform: rotate(45deg) scale(1); }
        }

        /* 09 VOIP -- handset rings + sound waves */
        .ico-voip .handset { transform-origin: 50% 60%; animation: ring 3.2s ease-in-out infinite; }
        .ico-voip .wave1 { transform-origin: center; animation: voip-wave 1.6s ease-out infinite; opacity: 0; }
        .ico-voip .wave2 { transform-origin: center; animation: voip-wave 1.6s ease-out 0.35s infinite; opacity: 0; }
        .th-card:hover .ico-voip .handset, .th-mini:hover .ico-voip .handset { animation-duration: 0.9s; }
        .th-card:hover .ico-voip .wave1, .th-card:hover .ico-voip .wave2,
        .th-mini:hover .ico-voip .wave1, .th-mini:hover .ico-voip .wave2 { animation-duration: 1s; }
        @keyframes ring {
            0%, 8%, 16%, 100% { transform: rotate(0); }
            4% { transform: rotate(-9deg); }
            12% { transform: rotate(9deg); }
        }
        @keyframes voip-wave {
            0% { transform: scale(0.7); opacity: 0.9; }
            100% { transform: scale(1.6); opacity: 0; }
        }

        /* 10 PROCUREMENT -- lid tilts + stamp */
        .ico-proc .lid { transform-origin: 50% 100%; animation: proc-tilt 4s ease-in-out infinite; }
        .ico-proc .stamp { transform-origin: center; opacity: 0; animation: proc-stamp 4s ease-in-out infinite; }
        .th-card:hover .ico-proc .lid, .th-mini:hover .ico-proc .lid { animation: proc-lift 1s cubic-bezier(0.4, 0.1, 0.3, 1.2) infinite; }
        .th-card:hover .ico-proc .stamp, .th-mini:hover .ico-proc .stamp { animation: proc-stamp-fast 1s ease-out infinite; }
        @keyframes proc-tilt {
            0%, 80%, 100% { transform: translateY(0) rotate(0); }
            90% { transform: translateY(-1px) rotate(-2deg); }
        }
        @keyframes proc-lift {
            0%, 100% { transform: translateY(0) rotate(0); }
            50% { transform: translateY(-2px) rotate(-4deg); }
        }
        @keyframes proc-stamp {
            0%, 70% { opacity: 0; transform: scale(0.4); }
            85% { opacity: 1; transform: scale(1.1); }
            100% { opacity: 1; transform: scale(1); }
        }
        @keyframes proc-stamp-fast {
            0% { opacity: 0; transform: scale(0.4); }
            50% { opacity: 1; transform: scale(1.15); }
            100% { opacity: 1; transform: scale(1); }
        }

        @media (prefers-reduced-motion: reduce) {
            .ico-rack .led, .ico-shield .shell, .ico-cloud .dl, .ico-net .ring, .ico-net .hub,
            .ico-backup .led-b, .ico-screen .scan, .ico-screen .cursor, .ico-strat .signal,
            .ico-strat .wave, .ico-reticle .ret, .ico-reticle .hit,
            .ico-voip .handset, .ico-voip .wave1, .ico-voip .wave2,
            .ico-proc .lid, .ico-proc .stamp { animation: none !important; }
        }

        /* Touch-device fallback: hover gestures fire as gentle idle loops */
        @media (hover: none) {
            .ico-shield .chk { stroke-dashoffset: 0; animation: chk-touch 5s ease-in-out infinite; }
            @keyframes chk-touch { 0%, 65% { stroke-dashoffset: 0; } 78% { stroke-dashoffset: 18; } 92%, 100% { stroke-dashoffset: 0; } }
            .ico-backup .bar { stroke-dashoffset: 0; animation: bar-touch 6s ease-in-out infinite; }
            @keyframes bar-touch { 0%, 65% { stroke-dashoffset: 0; } 78% { stroke-dashoffset: 10; } 92%, 100% { stroke-dashoffset: 0; } }
            .ico-cloud .dl { animation: cloud-touch 5.5s ease-in-out infinite; }
            @keyframes cloud-touch { 0%, 70% { transform: translateY(0); } 82% { transform: translateY(2.5px); } 100% { transform: translateY(0); } }
            .ico-screen .scan { animation: scan-touch 5s ease-in-out infinite; }
            @keyframes scan-touch { 0%, 70% { transform: translateY(-4px); opacity: 0; } 82% { transform: translateY(4px); opacity: 0.9; } 100% { transform: translateY(-4px); opacity: 0; } }
            .ico-strat .wave { opacity: 1; }
            .ico-reticle .ret { animation: reticle-touch 8s ease-in-out infinite; }
            @keyframes reticle-touch { 0%, 65% { transform: rotate(45deg) scale(1); } 72% { transform: rotate(45deg) scale(0.85); } 85%, 100% { transform: rotate(45deg) scale(1); } }
        }

        /* ===== REVEAL ANIMATION ===== */
        .reveal {
            opacity: 0;
            transform: translateY(20px);
            transition: opacity 0.8s cubic-bezier(.2,.6,.2,1), transform 0.8s cubic-bezier(.2,.6,.2,1);
        }
        .reveal.in {
            opacity: 1;
            transform: none;
        }

        /* ===== COOKIE BANNER ===== */
        #thCookieBanner {
            position: fixed;
            bottom: 24px;
            left: 24px;
            right: 24px;
            max-width: 560px;
            z-index: 2000;
            background: var(--card);
            border: 1px solid var(--line);
            border-radius: var(--r);
            box-shadow: 0 24px 64px rgba(0,0,0,0.55);
            padding: 24px;
            font-size: 14px;
            line-height: 1.6;
            color: var(--fg);
        }
        #thCookieBanner button[data-thcc="essential"] {
            flex: 1;
            min-width: 140px;
            padding: 10px 18px;
            background: transparent;
            border: 1px solid var(--line);
            color: var(--fg);
            border-radius: var(--r);
            font-size: 13px;
            font-weight: 500;
            cursor: pointer;
        }
        #thCookieBanner button[data-thcc="all"] {
            flex: 1;
            min-width: 140px;
            padding: 10px 18px;
            background: var(--mag);
            border: 1px solid var(--mag);
            color: #fff;
            border-radius: var(--r);
            font-size: 13px;
            font-weight: 600;
            cursor: pointer;
        }

        @media (max-width: 1100px) {
            .nav-links { display: none; }
            .nav-toggle { display: inline-flex; }
            .nav .nav-cta { display: none; }
            .foot-grid { grid-template-columns: 1fr 1fr; gap: 32px; }
            .th-section { padding: 80px 0; }
            .container, .th-container { padding: 0 24px; }
            .th-card-grid { grid-template-columns: 1fr; }
        }
        @media (max-width: 640px) {
            .foot-grid { grid-template-columns: 1fr; }
            .container, .th-container { padding: 0 20px; }
            footer { padding: 56px 0 32px; margin-top: 56px; }
            .foot-bottom { font-size: 10px; }
            .brand small { display: none; }
        }
        @media (max-width: 480px) {
            .container, .th-container { padding: 0 16px; }
            #thCookieBanner {
                left: 12px;
                right: 12px;
                bottom: 12px;
                padding: 18px;
            }
        }
