/* ═══════════════════════════════════════════════════
           DESIGN TOKENS
           ═══════════════════════════════════════════════════
           Two layers. The first is the system itself. The second
           re-points the names the 602 KB template stylesheet and
           the rest of this file already use (--cyan, --purple,
           --color-primary, --gradient-*), so one edit here
           recolours everything underneath instead of 120 scattered
           declarations.

           Measured against #101113:
             #F1F0EB  16.7:1    #ABAEB3  8.6:1    #C5AD7D  8.7:1
           All three clear AAA for body text, so gold is safe as
           type and not only as decoration — it is used sparingly by
           choice, not by necessity. */
        html { color-scheme: dark; }   /* dark only — no light theme */
        :root {
            /* ── Ground ───────────────────────────────────── */
            --bg:          #101113;   /* deep charcoal — the page */
            --bg-sunk:     #0C0D0F;   /* recessed wells, media mats */
            --surface:     #191B1E;   /* elevated: cards, panels    */
            --surface-2:   #1F2225;   /* raised on top of a surface */

            /* ── Ink ──────────────────────────────────────── */
            --ink:         #F1F0EB;   /* warm platinum */
            --ink-2:       #ABAEB3;
            /* #75787D measured 4.26:1 on --bg, just under the 4.50 WCAG AA
               floor for text below 18.66px — which is every place this
               token is used (stat labels, footer, phone caption, resume
               notes). #7D8086 is 4.77:1 and the same hue. */
            --ink-3:       #7D8086;   /* captions, disabled, meta   */

            /* ── Accent ───────────────────────────────────── */
            --gold:        #C5AD7D;
            --gold-hi:     #DCC79A;   /* hover / lit state          */
            --gold-lo:     #9C875C;
            --gold-wash:   rgba(197,173,125,.10);

            /* ── Lines ────────────────────────────────────── */
            --line:        rgba(241,240,235,.09);
            --line-2:      rgba(241,240,235,.14);
            --line-gold:   rgba(197,173,125,.32);

            /* ── Depth ────────────────────────────────────── */
            --lift-1: 0 2px 8px rgba(0,0,0,.30);
            --lift-2: 0 12px 32px rgba(0,0,0,.36);
            --lift-3: 0 28px 64px rgba(0,0,0,.46);

            /* ── Radius ───────────────────────────────────── */
            --r-xs: 4px;
            --r-sm: 8px;
            --r-md: 12px;
            --r-lg: 16px;
            --r-pill: 999px;

            /* ── Motion ───────────────────────────────────────
               One easing pair for the whole site. --ease-out is an
               expo-style curve for things arriving; --ease is the
               symmetric one for state changes. Durations are the
               four bands the design calls for, so nothing on the
               page invents its own timing. */
            --ease:      cubic-bezier(.4, 0, .2, 1);
            --ease-out:  cubic-bezier(.22, 1, .36, 1);
            --t-tap:     200ms;   /* interaction feedback 160-240 */
            --t-ui:      360ms;   /* component transitions 280-450 */
            --t-enter:   720ms;   /* main entrances       600-850 */
            --stagger:    65ms;   /* between related items 50-80  */

            /* ── Rhythm ───────────────────────────────────── */
            /* The fixed header's height, declared once. Everything that
               needs to clear it — the hero's top padding, anchor scroll
               offsets — reads this instead of hard-coding a number that
               then drifts out of sync with the bar. */
            --header-h:    72px;
            --pad-section: 132px;
            --container:   1240px;
            --gutter:      32px;

            /* ═══ Compatibility layer ═══════════════════════
               Old names, re-pointed. --cyan and --purple survive
               because ~120 declarations still reference them; both
               now resolve into the champagne/neutral system so no
               rule can reintroduce the old neon. */
            --dark-bg:     var(--bg);
            --dark-card:   var(--surface);
            --cyan:        #C5AD7D;
            --purple:      #ABAEB3;
            --text:        var(--ink);
            --muted:       var(--ink-2);
            --border:      var(--line);
            --surface-old: var(--surface);
            --header-bg:   rgba(16,17,19,.72);
            --on-accent:   #101113;
            --glow-soft:   rgba(197,173,125,.10);

            --color-primary:     #C5AD7D;
            --color-primary-alt: rgba(197,173,125,.85);
            --color-primary-2nd: #ABAEB3;
            --color-subtitle:    #C5AD7D;
            /* deliberately neutral: these drive the template's big
               fills and headings, so anything this redesign has not
               reached by hand lands as platinum, never as gold */
            --gradient-box:      linear-gradient(to right, #ABAEB3, #F1F0EB);
            --gradient-one:      linear-gradient(to right bottom, #F1F0EB, #ABAEB3);
            --gradient-two:      linear-gradient(to right, #F1F0EB, #ABAEB3);
            --text-gradient-one: linear-gradient(to right, #F1F0EB, #ABAEB3);
        }


        /* ═══════════════════════════════════════════════════
           BRAND INTRO
           ═══════════════════════════════════════════════════
           Visible only while <html> carries .is-loading, which the head
           script adds — and only on a first visit in this tab, with no
           hash in the URL. With JS disabled the class is never added, so
           the overlay never appears and the page is simply readable,
           rather than stuck behind a curtain with no script to lift it.

           The sequence is CSS. Nothing here waits on the network: the
           script holds a clock and the animations run against it.
              80ms  logo fades up and settles from .94
             560ms  one reflection sweeps the mark
             660ms  "Agan Aliu"
             900ms  "Full-Stack Developer"
            1280ms  composition complete, holds
            1760ms  overlay begins its 380ms fade  */
        .boot {
            position: fixed; inset: 0; z-index: 100000;
            display: none;
            align-items: center; justify-content: center;
            background: var(--bg);
            opacity: 1;
            transition: opacity 380ms var(--ease);
            will-change: opacity;
            overflow: hidden;
            padding: max(20px, env(safe-area-inset-top, 0px))
                     max(20px, env(safe-area-inset-right, 0px))
                     max(20px, env(safe-area-inset-bottom, 0px))
                     max(20px, env(safe-area-inset-left, 0px));
        }
        html.is-loading .boot { display: flex; }
        /* .is-revealed unlocks the page while the overlay is still
           fading. It cannot be "remove .is-loading" — that also flips the
           overlay back to display:none and snaps it away mid-fade. */
        html.is-loading:not(.is-revealed),
        html.is-loading:not(.is-revealed) body { overflow: hidden !important; }
        /* the width the hidden scrollbar was occupying, so releasing the
           lock does not shift the page sideways */
        html.is-loading:not(.is-revealed) body { padding-right: var(--sbw, 0px); }
        .boot.is-gone { opacity: 0; pointer-events: none; }

        .boot-inner {
            position: relative;
            display: flex; flex-direction: column; align-items: center;
            gap: 0;
        }

        .boot-logo {
            position: relative; display: block;
            width: clamp(60px, 15vmin, 84px);
            height: clamp(60px, 15vmin, 84px);
            opacity: 0;
        }
        .boot.is-playing .boot-logo {
            animation: bootRise 520ms var(--ease-out, cubic-bezier(.2,.7,.3,1)) 80ms both;
        }
        .boot-mark {
            display: block; width: 100%; height: 100%; object-fit: contain;
            /* the mark ships as a mid-blue icon; this chain discards the
               source colour outright and lands it on champagne — the same
               chain the header uses, so the logo never shifts colour
               between the intro and the page it hands over to */
            filter: brightness(0) saturate(100%) invert(74%) sepia(21%)
                    saturate(548%) hue-rotate(5deg) brightness(93%);
        }
        /* One reflection, masked BY the logo so it is confined to the
           mark's own shape — the logo itself is not redrawn or recoloured. */
        .boot-shine {
            position: absolute; inset: 0;
            -webkit-mask: url(/assets/images/brand/logo-mark.webp) center / contain no-repeat;
                    mask: url(/assets/images/brand/logo-mark.webp) center / contain no-repeat;
            background-image: linear-gradient(104deg,
                transparent 42%, rgba(255,255,255,.70) 50%, transparent 58%);
            background-repeat: no-repeat;
            background-size: 240% 100%;
            background-position: -70% 0;
            opacity: 0;
        }
        .boot.is-playing .boot-shine { animation: bootShine 720ms var(--ease) 560ms both; }

        .boot-name {
            margin-top: 20px;
            font-family: 'Space Grotesk', sans-serif;
            font-size: clamp(19px, 5.2vmin, 24px);
            font-weight: 600; letter-spacing: -.015em; line-height: 1.1;
            color: var(--ink);
            opacity: 0;
        }
        .boot.is-playing .boot-name {
            animation: bootRise 420ms var(--ease-out, cubic-bezier(.2,.7,.3,1)) 660ms both;
        }
        .boot-role {
            margin-top: 9px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: clamp(9px, 2.6vmin, 10.5px);
            letter-spacing: .18em; text-transform: uppercase; line-height: 1.2;
            color: var(--ink-3);
            opacity: 0;
        }
        .boot.is-playing .boot-role {
            animation: bootRise 380ms var(--ease-out, cubic-bezier(.2,.7,.3,1)) 900ms both;
        }

        @keyframes bootRise {
            from { opacity: 0; transform: translateY(8px) scale(.965); }
            to   { opacity: 1; transform: none; }
        }
        @keyframes bootShine {
            0%   { opacity: 0;  background-position: -70% 0; }
            18%  { opacity: 1; }
            82%  { opacity: 1; }
            100% { opacity: 0;  background-position: 170% 0; }
        }

        /* Reduced motion: the same composition, held still. Nothing
           moves, nothing sweeps, and the script shortens the hold. */
        @media (prefers-reduced-motion: reduce) {
            .boot { transition: none; }
            .boot-logo, .boot-name, .boot-role { animation: none; opacity: 1; }
            .boot-shine { display: none; }
        }
        .boot.is-still .boot-logo,
        .boot.is-still .boot-name,
        .boot.is-still .boot-role { animation: none; opacity: 1; }
        .boot.is-still .boot-shine { display: none; }

        html, body { transition: background-color .35s ease, color .35s ease; }

        /* style.css lays a hard scrim over the hero for legibility over a
           background image this page does not use. It would also mask the
           particle layer in that one section, so the effect appeared to stop
           at the fold. */
        .tmp-banner-one-area::before { display: none !important; }

        /* ─── AOS safety: never let data-aos hide content forever ── */
        body:not(.aos-ready) [data-aos] { opacity: 1; transform: none; }

        /* ═══════════════════════════════════════════════════
           MOTION — the entrance system
           ═══════════════════════════════════════════════════
           One mechanism for the whole site. An element marked
           [data-rise="n"] starts displaced and lands when its
           container gets .is-live; n is its place in the stagger,
           not a hand-typed delay, so re-ordering the markup
           re-orders the choreography without touching CSS.

           Two flavours share it:
             · a plain block fades and rises,
             · a masked line (.rl) slides its inner span out from
               behind a clipping window, so the text arrives from
               under the line above instead of appearing in place.

           Both animate only transform and opacity. */
        html.js [data-rise] {
            opacity: 0;
            transform: translateY(18px);
            transition: opacity var(--t-enter) var(--ease-out),
                        transform var(--t-enter) var(--ease-out);
            transition-delay: calc(var(--rise-i, 0) * var(--stagger));
        }
        html.js .hero-title .rl > span {
            transform: translateY(105%);
            transition: transform var(--t-enter) var(--ease-out);
            transition-delay: calc(var(--rise-i, 0) * var(--stagger));
        }
        /* the mask itself must not also fade, or the reveal reads as a
           cross-dissolve rather than as movement */
        html.js .hero-title .rl[data-rise] { opacity: 1; transform: none; }

        html.js .is-live [data-rise],
        html.js [data-rise].is-live             { opacity: 1; transform: none; }
        html.js .is-live .hero-title .rl > span { transform: none; }

        @media (prefers-reduced-motion: reduce) {
            [data-rise], .hero-title .rl > span {
                opacity: 1 !important; transform: none !important; transition: none !important;
            }
            .hero-dot { animation: none !important; }
        }

        /* ─── Reduced-motion guard ──────────────────────── */
        @media (prefers-reduced-motion: reduce) {
            *, *::before, *::after {
                animation-duration: 0.01ms !important;
                animation-iteration-count: 1 !important;
                transition-duration: 0.01ms !important;
            }
        }

        /* ─── Global reset to dark theme ───────────────── */
        html, body {
            background-color: var(--dark-bg) !important;
            color: var(--text) !important;
            font-family: 'Space Grotesk', sans-serif !important;
            overflow-x: hidden;
        }
        /* One ground for the whole document. Sections stay transparent
           over html/body's colour rather than each painting their own,
           which is what guarantees there is no seam where one section
           ends and the next begins — including under the hero. */
        section { background-color: transparent !important; }
        header, main, footer { position: relative; z-index: 1; }
        /* .tmp-popup-mobile-menu is a fixed full-screen overlay at z-index 9999
           in style.css. It must not be re-positioned or re-stacked here — it
           already sits above the canvas. */
        /* .scrollToTop is position:fixed in style.css — only lift it, never
           re-position it, or it falls into the document flow */
        .scrollToTop { z-index: 20; }
        h1,h2,h3,h4,h5,h6 { font-family: 'Space Grotesk', sans-serif !important; color: var(--text) !important; }
        p, .description, .disc { color: var(--muted) !important; font-family: 'Space Grotesk', sans-serif !important; }
        a { transition: color .3s ease, box-shadow .3s ease !important; }

        /* ─── Skip link + visually-hidden labels ────────── */
        .skip-link {
            position: absolute; left: -9999px; top: 0;
            z-index: 10000;
            background: var(--cyan); color: var(--on-accent) !important;
            padding: 12px 20px; border-radius: 0 0 8px 0;
            font-weight: 700; text-decoration: none;
        }
        .skip-link:focus { left: 0; }
        /* main needs tabindex="-1" to accept focus from the skip link; the
           visible result is the jump itself, so suppress the ring on it */
        main:focus { outline: none !important; }

        .visually-hidden-label {
            position: absolute !important;
            width: 1px; height: 1px;
            margin: -1px; padding: 0; border: 0;
            clip: rect(0 0 0 0); clip-path: inset(50%);
            overflow: hidden; white-space: nowrap;
        }

        /* Visible keyboard focus everywhere (the template had none) */
        a:focus-visible, button:focus-visible,
        input:focus-visible, textarea:focus-visible,
        [tabindex]:focus-visible {
            outline: 2px solid var(--cyan) !important;
            outline-offset: 3px !important;
            border-radius: 4px;
        }

        /* ─── Footer ────────────────────────────────────── */
        .site-footer {
            background: var(--dark-bg);
            border-top: 1px solid var(--border);
            padding: 34px 0;
            margin-top: 60px;
        }
        .site-footer .footer-inner {
            display: flex; flex-wrap: wrap;
            align-items: center; justify-content: space-between;
            gap: 18px;
        }
        .site-footer .footer-copy {
            margin: 0;
            color: var(--muted) !important;
            font-size: 15px !important;
        }
        .site-footer .footer-social { display: flex; gap: 20px; }
        .site-footer .footer-social a { color: var(--muted) !important; font-size: 18px; }
        .site-footer .footer-social a:hover { color: var(--cyan) !important; text-shadow: 0 0 10px var(--cyan); }
        @media (max-width: 575px) {
            .site-footer .footer-inner { flex-direction: column; text-align: center; }
        }

        /* ─── Scroll progress bar ───────────────────────── */
        #scroll-progress {
            position: fixed; top: 0; left: 0; height: 3px; width: 0%;
            background: linear-gradient(90deg, var(--cyan), var(--purple));
            box-shadow: 0 0 10px var(--cyan);
            z-index: 9999;
            transition: width .1s linear;
        }

        /* The replacement cursor that lived here is gone. It hid the
           real pointer's shape — which is what tells you whether a
           thing is clickable — and lagged behind it by a frame. */

        /* ─── Header ────────────────────────────────────── */
        /* The template left the header `position:absolute`, so it scrolled away
           with the page, and its JS snapped it to `fixed` at 150px — the header
           vanished and then jumped back with no transition. Pin it from the
           start instead and let it condense smoothly as you scroll. */
        .tmp-header-area-start,
        .header-one.header--transparent,
        .header--sticky.sticky {
            position: fixed !important;
            top: 0 !important;
            left: 0 !important;
            right: 0 !important;
            width: 100% !important;
            transform: none !important;      /* template used left:50% + translateX */
            margin: 0 !important;
            padding: 0 !important;
            z-index: 1000 !important;
            /* Fully transparent at every scroll position — no panel, no rule,
               no shadow. style.css gives .header--sticky.sticky a background,
               a shadow and a 9px backdrop blur once the template's own sticky
               class lands, so each of those is overridden here rather than
               only the background. */
            background: transparent !important;
            box-shadow: none !important;
            border: 0 !important;
            -webkit-backdrop-filter: none !important;
            backdrop-filter: none !important;
        }

        /* Auto-hide: slides away on the way down, returns on the smallest
           move up. The base rule above pins `transform: none !important`, so
           this carries a third class to outrank it rather than relying on
           source order. */
        .tmp-header-area-start {
            transition: transform .38s cubic-bezier(.4, 0, .2, 1) !important;
        }
        .tmp-header-area-start.header--sticky.nav-hidden {
            transform: translateY(-100%) !important;
        }

        /* Fixed height: the header never resizes, so nothing reflows as you
           scroll — only the backdrop fades in. Must stay under 80px because
           onePageNav hardcodes `offset().top - 80`. */
        .tmp-header-area-start .row { --bs-gutter-y: 0 !important; margin-top: 0 !important; }
        .tmp-header-area-start .row > * { margin-top: 0 !important; padding-top: 0 !important; }

        .tmp-header-area-start .header-content {
            height: var(--header-h);
            padding: 0 !important;
            gap: 20px;
            flex-wrap: nowrap;
        }
        /* The bar is one row at every width. The menu and the social icons are
           both wrapping flex containers by default, and together they wanted
           ~1280px inside a 1260px container — so each spilled a line the 72px
           bar has no room for. nowrap keeps the row intact; the tightened
           spacing below is what actually buys back the width. */
        .tmp-header-area-start .brand,
        .tmp-header-area-start .tmp-header-right { flex: 0 0 auto; }
        .tmp-header-area-start .tmp-mainmenu-nav { flex: 0 1 auto; min-width: 0; }
        .tmp-header-area-start ul.tmp-mainmenu { align-items: center; margin: 0; flex-wrap: nowrap; }
        .tmp-header-area-start .tmp-mainmenu > li { margin: 0 2px; white-space: nowrap; }
        .tmp-header-area-start .tmp-mainmenu li a { padding: 4px 10px !important; }
        .tmp-header-area-start .tmp-mainmenu.nav-pills { --bs-nav-link-padding-y: 0; }
        .tmp-header-area-start .tmp-header-right { gap: 18px; flex-wrap: nowrap; }
        .tmp-header-area-start .tmp-header-right .social-link { flex-wrap: nowrap; gap: 6px; }

        /* Brand */
        .brand {
            display: inline-flex; align-items: center; gap: 12px;
            text-decoration: none; flex-shrink: 0;
        }
        .brand-mark {
            width: 38px; height: 38px; flex: 0 0 38px;
            object-fit: contain;
            /* The mark ships as a mid-blue icon. This chain discards
               the source colour outright (brightness(0) flattens it to
               black) and rebuilds it as champagne, so it matches
               whatever the file happens to contain. Same chain as the
               boot veil, so the logo does not change colour between
               the loading screen and the page it hands over to. */
            filter: brightness(0) saturate(100%) invert(74%) sepia(21%)
                    saturate(548%) hue-rotate(5deg) brightness(93%);
            transition: filter var(--t-tap) var(--ease);
        }
        .brand:hover .brand-mark {
            filter: brightness(0) saturate(100%) invert(82%) sepia(18%)
                    saturate(520%) hue-rotate(5deg) brightness(100%);
        }
        .brand-text { display: flex; flex-direction: column; justify-content: center; }
        /* The container was 1275px wide — odd, so its auto margins were x.5
           and all text inside rendered on half pixels. An even width snaps
           the whole page's type back onto the pixel grid. */
        .container { max-width: 1276px; padding-left: 8px; padding-right: 8px; }

        /* integer font sizes: 11.5px/2.2px were landing between pixels */
        .brand-name {
            color: var(--text); font-weight: 700; font-size: 17px;
            line-height: 20px; letter-spacing: normal;
            transition: color .3s ease;
        }
        /* weight 400 at 11px leaves strokes under a pixel wide, which reads as
           fuzzy however sharp the rasterisation is — 600 gives it real edges */
        .brand-role {
            color: var(--muted); font-size: 11px; line-height: 14px; font-weight: 600;
            letter-spacing: 2px; text-transform: uppercase;
        }
        .brand:hover .brand-name { color: var(--cyan); }

        /* Theme toggle */

        /* Nav CTA */
        .nav-cta {
            align-items: center; gap: 9px;
            padding: 10px 20px; border-radius: 999px;
            font-weight: 600; font-size: 15px;
            color: var(--cyan) !important;
            border: 1px solid rgba(197,173,125,.45);
            background: rgba(197,173,125,.07);
            text-decoration: none; white-space: nowrap;
            transition: background .3s ease, color .3s ease, box-shadow .3s ease, transform .3s ease;
        }
        .nav-cta i { font-size: 12px; transition: transform .3s ease; }
        .nav-cta:hover {
            background: var(--cyan); color: var(--on-accent) !important;
            box-shadow: 0 0 18px rgba(197,173,125,.45);
            transform: translateY(-1px);
        }
        .nav-cta:hover i { transform: translateX(3px); }

        /* The header's breakpoints live once, with the rest of the
           responsive pass at the foot of this stylesheet. They used to
           be declared here as well, at a different height (64px vs
           66px) — so the offset the hero had to clear depended on
           which block won. */

        .tmp-mainmenu li a, .tmp-mainmenu .nav-item a {
            color: var(--muted) !important;
            font-family: 'Space Grotesk', sans-serif !important;
            font-weight: 500 !important;
            position: relative;
            padding-bottom: 4px;
            transition: color .3s ease !important;
        }
        .tmp-mainmenu li a::after, .tmp-mainmenu .nav-item a::after {
            content: '';
            position: absolute; bottom: 0; left: 0;
            width: 0; height: 2px;
            background: linear-gradient(90deg, var(--cyan), var(--purple));
            box-shadow: 0 0 8px var(--cyan);
            transition: width .3s ease;
        }
        .tmp-mainmenu li a:hover, .tmp-mainmenu .nav-item a:hover,
        .tmp-mainmenu li.current a {
            color: var(--cyan) !important;
        }
        .tmp-mainmenu li a:hover::after, .tmp-mainmenu .nav-item a:hover::after,
        .tmp-mainmenu li.current a::after { width: 100%; }

        /* ── Active nav indicator ───────────────────────────
           style.css gives `.tmp-mainmenu-nav .tmp-mainmenu > li > a::after`
           a full-size rounded panel at 10% of the brand colour, scaled
           up on hover. That selector outranks any `.tmp-mainmenu li a`
           rule here, so the panel is what actually rendered. Restated
           at matching specificity as a hairline — every property the
           template set has to be undone explicitly or it persists. */
        .tmp-mainmenu-nav .tmp-mainmenu > li > a::after {
            top: auto; bottom: 0; left: 50%;
            width: 0; height: 1px;
            border-radius: 0;
            opacity: 1; visibility: visible;
            transform: translateX(-50%);
            background: var(--gold);
            transition: width var(--t-tap) var(--ease);
            z-index: 0;
        }
        .tmp-mainmenu-nav .tmp-mainmenu > li:hover > a::after,
        .tmp-mainmenu-nav .tmp-mainmenu > li.current > a::after,
        .tmp-mainmenu-nav .tmp-mainmenu > li > a.active::after {
            width: 100%; opacity: 1; visibility: visible; transform: translateX(-50%);
        }
        .tmp-mainmenu-nav .tmp-mainmenu > li > a { color: var(--ink-2) !important; }
        .tmp-mainmenu-nav .tmp-mainmenu > li:hover > a,
        .tmp-mainmenu-nav .tmp-mainmenu > li.current > a { color: var(--ink) !important; }
        /* Bootstrap's .nav-pills also paints the active link */
        .tmp-mainmenu.nav-pills .nav-link,
        .tmp-mainmenu.nav-pills li a,
        .tmp-mainmenu.nav-pills li.current a {
            background: transparent !important; background-color: transparent !important;
            border-radius: 0 !important;
        }

        /* Header social: the template gives these filled grey discs,
           the heaviest objects in a bar that is otherwise open type. */
        .tmp-header-right .social-link a {
            background: transparent !important; background-color: transparent !important;
            border: 1px solid var(--line) !important;
            color: var(--ink-3) !important;
        }
        .tmp-header-right .social-link a:hover {
            color: var(--gold) !important; border-color: var(--line-gold) !important;
        }
        .social-link a { color: var(--muted) !important; transition: color var(--t-tap) var(--ease), border-color var(--t-tap) var(--ease) !important; }
        .social-link a:hover { color: var(--cyan) !important; text-shadow: 0 0 10px var(--cyan); }
        .hamberger-menu, #menuBtn { color: var(--muted) !important; }

        /* ─── Mobile menu ───────────────────────────────── */
        .tmp-popup-mobile-menu {
            background: rgba(10,10,15,.98) !important;
            /* No backdrop blur. This scrim is 98% opaque, so blurring the page
               behind it is invisible — it was re-blurring the whole viewport on
               every frame of the fade for no visible result, which is what made
               the drawer stutter or appear to skip its animation on a phone. */
            -webkit-backdrop-filter: none !important;
            backdrop-filter: none !important;
            /* the border was on the full-screen scrim, drawing a line down the
               right edge of the display; it belongs on the drawer itself */
            border: 0 !important;
            /* visibility has to outlast the close. Flipped with the class it
               takes effect on the first frame, and the whole exit animation
               then plays while the element is already switched off — the menu
               just vanished instead of sliding away. */
            transition: opacity .24s ease, visibility 0s linear .3s !important;
        }
        .tmp-popup-mobile-menu.active {
            transition: opacity .24s ease, visibility 0s linear 0s !important;
        }

        /* The template slid the drawer by animating `left`, which lays out a
           full-height panel on every frame. Same movement, kept on the
           compositor, and at a length that reads as deliberate rather than slow. */
        .tmp-popup-mobile-menu .inner {
            left: 0 !important;
            transform: translateX(-100%);
            border-right: 1px solid var(--border);
            transition: transform .28s cubic-bezier(.4, 0, .2, 1),
                        opacity .22s ease !important;
        }
        .tmp-popup-mobile-menu.active .inner { transform: none; }
        .tmp-popup-mobile-menu .tmp-mainmenu li a { color: var(--muted) !important; }
        .tmp-popup-mobile-menu .tmp-mainmenu li a:hover { color: var(--cyan) !important; }

        /* ═══════════════════════════════════════════════════
           HERO — TYPE
           ═══════════════════════════════════════════════════ */
        /* `div.` is deliberate. style.css targets this section as
           `div.tmp-banner-one-area` (specificity 0,1,1) and a bare
           `.tmp-banner-one-area` (0,1,0) loses to it even with
           !important — which is how a background image got in here in
           the first place. Matching its specificity is what makes the
           solid colour stick.

           Stated as shorthand and longhand so nothing can slip an
           image back in, and with no transition on the property: a
           background that fades in is the flash this removes. */

        div.tmp-banner-one-area {
            position: relative;
            overflow: hidden;
            background: var(--bg) !important;
            background-color: var(--bg) !important;
            background-image: none !important;
            transition: none !important;

            /* Mobile first, and the header is counted exactly ONCE.
               This used to be a flat 150px — a desktop number applied
               at every width, which on a phone with a 60px bar left
               ~90px of dead space under the navbar before the first
               word. It is now the bar's real height plus the gap I
               actually want beneath it.

               No min-height and no vertical centring here either: on a
               phone the hero's height should follow its content, not
               stretch to the viewport and float the text in the middle
               of it. env() adds the notch inset on top, resolving to
               0 everywhere it does not apply. */
            display: block;
            min-height: 0;
            padding-top: calc(var(--header-h) + 28px + env(safe-area-inset-top, 0px));
            padding-bottom: 56px;
        }

        /* ── First screen ───────────────────────────────────
           The header is position:fixed, so it is lifted out of the
           flow and the hero already starts at y=0 underneath it. That
           means the header is accounted for exactly ONCE — as this
           block's own padding-top — and the hero box itself is a whole
           viewport tall. Subtracting --header-h from the min-height as
           well would count it twice and leave the fold short.

           min-height, never height: a hero taller than the screen
           (every phone, and any short desktop window) simply grows and
           scrolls. Nothing is clipped, nothing is scaled down, and
           there is no spacer element doing the work. */
        /* Desktop only. On a phone the hero is one compact stack that
           takes the height it needs — forcing a viewport onto it is
           exactly what opened the dead space this replaced. */
        @media (min-width: 992px) {
            div.tmp-banner-one-area {
                min-height: 100vh;    /* fallback for browsers without svh */
                min-height: 100svh;   /* the visible viewport, URL bar included */
            }
        }
        /* Centre it only where the hero is genuinely shorter than the
           screen; on a short window it stays a block so tall content
           cannot overflow past the top of a centred flex box. */
        @media (min-width: 992px) and (min-height: 640px) {
            div.tmp-banner-one-area {
                display: flex;
                align-items: center;
            }
            div.tmp-banner-one-area > .container { width: 100%; }
        }

        /* ── Anchor offsets ─────────────────────────────────
           Jumping to #about must not park the heading under the fixed
           bar. scroll-margin-top does this at the destination, which
           also covers keyboard focus and a direct load of /#about —
           things a scroll handler's offset would miss. */
        #home, #about, #service, #portfolio, #skills, #resume, #contacts {
            scroll-margin-top: calc(var(--header-h) + 16px);
        }
        /* Smooth only when the visitor has not asked for less motion.
           !important because the template pins `scroll-behavior: auto
           !important` on html in style.css — without matching it, this
           rule never applied and every anchor jump was a hard cut.
           Under `reduce` this block does not match at all, so the
           template's auto stands and the jump is instant. */
        @media (prefers-reduced-motion: no-preference) {
            html { scroll-behavior: smooth !important; }
        }
        @media (min-width: 992px) {
            /* the full-height stage is a desktop composition */
            .tmp-banner-one-area {
                min-height: 100svh;
                display: flex; align-items: center;
                padding-top: calc(var(--header-h) + 48px);
                padding-bottom: 90px;
            }
            .tmp-banner-one-area > .container { width: 100%; }
        }

        .hero-eyebrow {
            /* flex, not inline-flex: as an inline box it sat on the
               parent's 28px line strut and was pushed 8px down from the
               content edge, which quietly widened the gap under the
               navbar. Block-level flex has no strut. flex-wrap lets the
               label break onto a second line on a narrow phone instead
               of being squeezed. */
            display: flex; flex-wrap: wrap; align-items: center; gap: 9px;
            width: fit-content; max-width: 100%;
            margin: 0 0 26px !important;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 11.5px !important;
            letter-spacing: .04em;
            line-height: 1.4 !important;
            color: var(--ink-2) !important;
        }
        .hero-dot {
            width: 6px; height: 6px; border-radius: 50%; flex: 0 0 6px;
            background: var(--gold);
            box-shadow: 0 0 0 0 rgba(197,173,125,.55);
            animation: heroPing 2.6s var(--ease) infinite;
        }
        @keyframes heroPing {
            0%   { box-shadow: 0 0 0 0 rgba(197,173,125,.5); }
            70%  { box-shadow: 0 0 0 7px rgba(197,173,125,0); }
            100% { box-shadow: 0 0 0 0 rgba(197,173,125,0); }
        }

        /* Three masked lines. Each .rl is a clipping window and the
           <span> inside it is what travels — so the text rises out of
           the line above rather than fading in place, and no
           individual letters are animated. */
        .hero-title {
            margin: 0 0 26px !important;
            /* capped at 60px: past that, "and software that" no longer
               holds one line inside a half-width column, and a masked
               line that wraps loses the reveal it exists for */
            font-size: clamp(36px, 4.2vw, 60px) !important;
            font-weight: 600 !important;
            line-height: 1.06 !important;
            letter-spacing: -.035em !important;
            color: var(--ink) !important;
            -webkit-text-fill-color: var(--ink) !important;
            background: none !important;
        }
        .hero-title .rl { display: block; overflow: hidden; padding-bottom: .04em; }
        /* the phone headline exists only at the mobile breakpoint */
        .hero-title .rl.tl-narrow { display: none; }
        .hero-title .rl > span { display: block; }

        .hero-lede--narrow { display: none; }
        .hero-lede {
            margin: 0 0 34px !important;
            max-width: 50ch;
            font-size: 17px !important;
            line-height: 1.75 !important;
            color: var(--ink-2) !important;
        }

        .hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 44px; }

        /* ── Facts ──────────────────────────────────────────
           A <dl>, because these are term/definition pairs and a
           screen reader should read them as such. */
        /* Three equal columns spanning the container, each one centred
           on its own axis. Equal tracks mean equal outer spacing, and
           because every number is a single line the labels start on a
           matching row across all three. */
        .hero-facts {
            display: grid;
            grid-template-columns: repeat(3, minmax(0, 1fr));
            gap: 14px 12px;
            margin: 0; padding-top: 26px;
            border-top: 1px solid var(--line);
            text-align: center;
        }
        .hero-facts > div {
            display: flex; flex-direction: column; align-items: center;
            gap: 6px;                /* one number-to-label step everywhere */
            min-width: 0;
        }
        .hero-facts dt {
            font-size: 22px; font-weight: 600; line-height: 1;
            letter-spacing: -.02em; color: var(--ink);
        }
        .hero-facts dd {
            margin: 0;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
            color: var(--ink-3);
        }

        /* ═══════════════════════════════════════════════════
           BUTTONS
           ═══════════════════════════════════════════════════
           Two, same geometry, different material. Neither glows:
           the arrow travels and the surface shifts, which is what
           answers a pointer without shouting. */
        .btn {
            display: inline-flex; align-items: center; justify-content: center; gap: 9px;
            min-height: 48px;
            padding: 13px 24px;
            border-radius: var(--r-pill);
            font-family: 'Space Grotesk', sans-serif;
            font-size: 15px; font-weight: 600; letter-spacing: -.01em;
            text-decoration: none !important;
            border: 1px solid transparent;
            cursor: pointer;
            transition: background var(--t-tap) var(--ease),
                        border-color var(--t-tap) var(--ease),
                        color var(--t-tap) var(--ease),
                        transform var(--t-tap) var(--ease);
        }
        .btn-arrow { width: 15px; height: 15px; flex: 0 0 15px; transition: transform var(--t-tap) var(--ease); }
        .btn:hover .btn-arrow { transform: translateX(3px); }
        .btn:active { transform: translateY(1px); }

        .btn-primary {
            background: var(--gold);
            color: var(--on-accent) !important;
            border-color: var(--gold);
        }
        .btn-primary:hover { background: var(--gold-hi); border-color: var(--gold-hi); color: var(--on-accent) !important; }

        .btn-ghost {
            background: transparent;
            color: var(--ink) !important;
            border-color: var(--line-2);
        }
        .btn-ghost:hover { background: var(--surface); border-color: var(--ink-3); color: var(--ink) !important; }

        /* The template's own button class still exists on the contact
           submit; keep it in the same family rather than leaving one
           button on the page styled from 2019. */
        .tmp-btn {
            background: var(--gold) !important;
            color: var(--on-accent) !important;
            border: 1px solid var(--gold) !important;
            font-family: 'Space Grotesk', sans-serif !important;
            font-weight: 600 !important;
            box-shadow: none !important;
            transition: background var(--t-tap) var(--ease), transform var(--t-tap) var(--ease) !important;
        }
        .tmp-btn:hover { background: var(--gold-hi) !important; box-shadow: none !important; }

        /* ─── Gradient section titles ───────────────────── */
        .section-head h2.title,
        .custom-title {
            background: linear-gradient(135deg, var(--cyan), var(--purple)) !important;
            -webkit-background-clip: text !important;
            -webkit-text-fill-color: transparent !important;
            background-clip: text !important;
        }
        .section-sub-title .subtitle {
            color: var(--cyan) !important;
            letter-spacing: 3px !important;
            font-size: 16px !important;
            font-weight: 600 !important;
        }

        /* ─── Kill the template's leftover brand pink ───── */
        /* style.css paints these #FF014F from rules more specific than the
           ones above, so the hero name and the active nav link were rendering
           hot pink inside an otherwise cyan/purple theme. */
        .banner-one-main-wrapper .inner .title span.glitch {
            background: linear-gradient(135deg, var(--cyan), var(--purple)) !important;
            -webkit-background-clip: text !important;
            background-clip: text !important;
            -webkit-text-fill-color: transparent !important;
            color: transparent !important;
        }
        /* the glitch layers must opt back out of the parent's transparent fill */
        .glitch::before {
            background: none !important;
            color: var(--cyan) !important;
            -webkit-text-fill-color: var(--cyan) !important;
        }
        .glitch::after {
            background: none !important;
            color: var(--purple) !important;
            -webkit-text-fill-color: var(--purple) !important;
        }
        /* style.css sets these to --color-heading with !important at a higher
           specificity than .tmp-mainmenu li a, so match it and use themed ink */
        .tmp-mainmenu-nav .tmp-mainmenu > li > a { color: var(--text) !important; }
        .tmp-mainmenu-nav .tmp-mainmenu > li:hover > a,
        .tmp-mainmenu-nav .tmp-mainmenu > li.current > a,
        .tmp-popup-mobile-menu .tmp-mainmenu li.current a {
            color: var(--cyan) !important;
        }
        /* the "</>" badge in the About card */
        .design-card .design-card-img .icon,
        .design-card .design-card-img .icon i {
            color: var(--cyan) !important;
        }
        /* testimonial carousel dots */
        .swiper-pagination-bullet {
            background: var(--muted) !important;
            box-shadow: none !important;
            opacity: .45 !important;
        }
        .swiper-pagination-bullet-active {
            background: var(--cyan) !important;
            box-shadow: 0 0 0 1px var(--cyan) inset, 0 0 10px rgba(197,173,125,.6) !important;
            opacity: 1 !important;
        }
        /* section label wrappers (children already cyan; keeps inherit clean) */
        .section-sub-title { color: var(--cyan) !important; }
        /* star ratings inherit from <li>, which style.css paints pink */
        .tmp-star ul li, .tmp-star ul li i { color: var(--cyan) !important; }
        /* mobile menu close button — its hover fill was still pink */
        .tmp-round-action-btn::after { background: var(--cyan) !important; }
        .tmp-round-action-btn:hover { color: var(--on-accent) !important; }
        .hamberger-menu { border-color: var(--border) !important; }
        /* back-to-top: the rising "water" fill and its two wave layers */

        /* ─── Cards — glassmorphism base ────────────────── */
        .glass {
            background: var(--surface) !important;
            backdrop-filter: blur(10px) !important;
            border: 1px solid var(--border) !important;
            border-radius: 14px !important;
            transition: all .3s ease !important;
        }

        /* ─── About ─────────────────────────────────────── */
        /* No panel here — the template's card-inside-a-card read as two empty
           boxes. This is set as type on the page instead: an oversized numeral
           against a soft glow, a hairline rule, then the stack line. */
        .about-us-left-content-wrap {
            position: relative;
            background: none !important;
            border: 0 !important;
            box-shadow: none !important;
            border-radius: 0 !important;
            padding: 8px 0 8px 26px !important;
            text-align: left;
        }
        /* the only "container" is a gradient rule down the left edge */
        .about-us-left-content-wrap::before {
            content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
            width: 3px; border-radius: 3px;
            background: linear-gradient(to bottom, var(--cyan), var(--purple));
        }
        /* soft light behind the numeral so the column doesn't read as empty */
        .about-us-left-content-wrap::after {
            content: ""; position: absolute; z-index: -1;
            left: -90px; top: -110px;
            width: 460px; height: 460px; border-radius: 50%;
            background: radial-gradient(circle, var(--glow-soft), transparent 60%);
            opacity: .7;
            pointer-events: none;
        }

        .years-of-experience-card {
            background: none !important;
            border: 0 !important;
            box-shadow: none !important;
            -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
            border-radius: 0 !important;
            padding: 0 !important;
            margin: 0 !important;
            display: block !important;
        }
        .years-of-experience-card h2, .counter-val {
            background: linear-gradient(135deg, var(--cyan), var(--purple)) !important;
            -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important;
            background-clip: text !important;
            font-size: clamp(4.5rem, 8vw, 6.5rem) !important;
            font-weight: 700 !important;
            line-height: .9 !important;
            letter-spacing: -3px;
            margin: 0 !important;
        }
        /* the template sets this label at 48px capitalised — same specificity
           so it reads as a small tracked caption under the numeral */
        .about-us-left-content-wrap .years-of-experience-card .card-para {
            color: var(--muted) !important;
            margin: 14px 0 0 !important;
            line-height: 1.5; text-align: left;
            font-weight: 600; letter-spacing: 1.6px; text-transform: uppercase;
        }

        /* hairline rule, not a card */
        .design-card {
            background: none !important;
            border: 0 !important;
            border-top: 1px solid var(--border) !important;
            box-shadow: none !important;
            -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
            border-radius: 0 !important;
            padding: 24px 0 0 !important;
            margin: 28px 0 0 !important;
            display: block;
            text-align: left;
        }
        .design-card .card-title { color: var(--text) !important; font-size: 16px; font-weight: 600; margin: 0 0 4px; }
        .design-card .card-para  { color: var(--muted) !important; margin: 0; font-size: 16px; }

        @media (max-width: 991px) {
            .about-us-left-content-wrap { margin-bottom: 44px; }
        }
        @media (max-width: 575px) {
            .years-of-experience-card h2, .counter-val { letter-spacing: -2px; }
        }
        /* ─── About: eyebrow, two-tone heading, signature ─ */
        .about-us-right-content-wrap .section-sub-title {
            display: flex; align-items: center; gap: 16px;
        }
        .about-us-right-content-wrap .eyebrow-rule {
            height: 1px; flex: 0 1 70px;
            background: linear-gradient(to right, var(--cyan), transparent);
        }

        /* The section-wide rule paints every h2.title as one gradient. This
           heading is two-tone, so the fill is handed back to the spans and
           each one colours itself. */
        .section-head h2.about-title {
            background: none !important;
            -webkit-text-fill-color: currentColor !important;
            margin: 16px 0 22px;
            line-height: 1.25;
        }
        .about-title .t-plain { color: var(--text); }
        .about-title .t-grad {
            background: linear-gradient(120deg, var(--cyan), var(--purple));
            -webkit-background-clip: text; background-clip: text;
            -webkit-text-fill-color: transparent; color: transparent;
        }
        /* its own line without a <br>: the template hides <br> inside
           .section-head .title below 767px, which would run the two lines
           together on a phone */
        .about-title .t-sub {
            display: block; color: var(--muted);
            font-weight: 500;
        }
        .me-em { color: var(--text) !important; -webkit-text-fill-color: var(--text); font-weight: 700; }

        .about-sign {
            display: flex; align-items: center; gap: 18px;
            margin-top: 34px;
        }
        .about-sign .sign-name {
            font-family: 'Dancing Script', 'Snell Roundhand', cursive;
            font-size: clamp(34px, 7vw, 44px); font-weight: 600;
            line-height: 1; color: var(--text); opacity: .9;
            /* the descenders sit low; nudge it back onto the optical centre */
            transform: translateY(-2px);
        }
        .about-sign .sign-rule {
            height: 1px; flex: 0 0 46px; margin-left: auto;
            background: linear-gradient(to right, var(--cyan), var(--purple));
        }
        .about-sign .sign-tag {
            font-size: 10.5px; font-weight: 600; letter-spacing: .18em;
            text-transform: uppercase; color: var(--muted);
            line-height: 1.6; text-align: right; flex: 0 0 auto;
        }

        /* ─── About cards: icon + arrow ──────────────────── */
        /* icon, title and arrow share the top row; the description wraps
           onto its own line beneath and gets the card's full width. Kept
           inside the flex row it was squeezed to ~180px by the two-column
           grid on desktop and broke across five lines. */
        .about-us-card {
            display: flex; flex-wrap: wrap; align-items: center;
            column-gap: 14px; row-gap: 10px;
            text-decoration: none !important; color: inherit !important;
        }
        /* flex-basis 0, not auto: a wrapping flex container breaks lines
           before it shrinks anything, so a title asking for its full content
           width pushes the arrow onto a row of its own. Starting from zero it
           takes only the space left over and wraps its own text instead. */
        .about-us-card .card-title { flex: 1 1 0; min-width: 0; margin: 0 !important; }
        .about-us-card .card-para  { flex: 1 0 100%; }
        .about-us-card .card-ico {
            flex: 0 0 44px; width: 44px; height: 44px;
            display: grid; place-items: center;
            border-radius: 13px; font-size: 17px;
            color: var(--cyan);
            background: linear-gradient(135deg, rgba(197,173,125,.16), rgba(171,174,179,.18));
            border: 1px solid var(--border);
            transition: transform .3s ease, box-shadow .3s ease;
        }
        .about-us-card .card-go {
            flex: 0 0 30px; width: 30px; height: 30px;
            display: grid; place-items: center;
            border-radius: 50%; font-size: 11px;
            color: var(--muted); border: 1px solid var(--border);
            transition: color .3s ease, border-color .3s ease, transform .3s ease;
        }
        .about-us-card:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

        @media (max-width: 420px) {
            .about-us-card { gap: 12px; }
            .about-us-card .card-ico { flex-basis: 38px; width: 38px; height: 38px; font-size: 15px; }
        }

        .about-us-card { padding: 22px !important; }
        .about-us-card .card-title { color: var(--text) !important; font-size: 16px; font-weight: 600; margin: 0 0 8px; }
        .about-us-card .card-para { color: var(--muted) !important; margin: 0; font-size: 16px; }
        /* Gap between the two about columns. Only meaningful while they sit
           side by side — once they stack (<992px) it just pushes the whole
           block off-centre, so it is scoped to lg and up. */
        @media (min-width: 992px) {
            .about-us-right-content-wrap { padding-left: 30px; }
        }

        /* Profile float */
        /* No perpetual float. translateY() animating forever kept these
           images on a composited layer at sub-pixel offsets every frame, so
           they never landed on the pixel grid and always looked soft. A
           transform on hover is transient, so it costs nothing at rest. */
        .float-img {
            border-radius: 16px !important;
            box-shadow: 0 0 32px rgba(197,173,125,.2) !important;
            transition: transform .4s ease, box-shadow .4s ease;
        }

        /* ─── Services ──────────────────────────────────── */
        .service-card-v2 {
            padding: 26px 28px !important; margin-bottom: 20px !important;
            transition: all .3s ease !important;
        }
        .service-card-v2 .service-card-num { color: var(--text) !important; font-size: 1.15rem !important; font-weight: 600 !important; margin: 0 0 8px; }
        .service-card-v2 .service-card-num span { color: var(--cyan) !important; }
        .service-card-v2 .service-para { color: var(--muted) !important; margin: 0; font-size: 16px; }

        /* ═══════════════════════════════════════════════════
           SECTION HEADS
           ═══════════════════════════════════════════════════
           One pattern for every section: a mono kicker, a heading in
           solid ink, a lede. Headings are NOT gradients — a page
           where every heading is a gradient emphasises none of them. */
        .sec-head { max-width: 680px; margin-bottom: 64px; }
        .sec-kicker {
            margin: 0 0 18px !important;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 11.5px !important;
            letter-spacing: .12em; text-transform: uppercase;
            color: var(--gold) !important;
        }
        .sec-title {
            margin: 0 0 18px !important;
            font-size: clamp(28px, 3.3vw, 44px) !important;
            font-weight: 600 !important;
            line-height: 1.14 !important;
            letter-spacing: -.03em !important;
            color: var(--ink) !important;
            -webkit-text-fill-color: var(--ink) !important;
            background: none !important;
        }
        /* Controlled line breaks that survive being turned off. A <br>
           hidden with display:none takes its whitespace with it and
           welds the two halves into one word; a span with a real space
           beside it simply goes inline and wraps where it should. */
        .sec-title .ln { display: block; }

        .sec-lede {
            margin: 0 !important;
            max-width: 56ch;
            font-size: 16.5px !important;
            line-height: 1.7 !important;
            color: var(--ink-2) !important;
        }

        /* ═══════════════════════════════════════════════════
           SELECTED WORK
           ═══════════════════════════════════════════════════
           Replaces a Swiper coverflow that showed one screenshot at a
           time with its neighbours tucked behind it.

           The governing constraint is resolution: the screenshots are
           900px wide, so no frame is allowed to exceed that. The
           feature layout puts the screen in a ~58% column (≈660px at
           the widest) rather than bleeding it full-width, and the
           two-up grid lands each card around 570px. Both sit inside
           the source, so nothing is upscaled. */
        /* ── Project cards ──────────────────────────────────
           Two columns, not three: at this container width three cards
           would leave each laptop too small to be worth showing. */
        .pw-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 26px; }
        .pw-card {
            background: var(--surface);
            border: 1px solid var(--line);
            border-radius: var(--r-lg);
            overflow: hidden;
            transition: transform var(--t-ui) var(--ease),
                        border-color var(--t-ui) var(--ease),
                        box-shadow var(--t-ui) var(--ease);
        }
        /* flex column + margin-top:auto on the footer aligns the actions
           across a row however long the descriptions run */
        .pw-link { display: flex; flex-direction: column; height: 100%; text-decoration: none; }

        /* the stage: one tone off the card body, so the device reads as
           sitting on a surface rather than floating on the card */
        .pw-media {
            background: #131417;
            border-bottom: 1px solid var(--line);
            padding: 34px 34px 30px;
            display: flex; align-items: center; justify-content: center;
        }

        /* ── Laptop ─────────────────────────────────────────
           Built in CSS rather than composited from a rendered image:
           the display is a real element, so the screenshot sits in it
           exactly, stays perfectly rectangular (no perspective
           resampling) and is therefore as sharp as the source allows at
           any pixel density. Every card shares this one geometry and
           one lighting direction; the websites supply the colour. */
        .mb { position: relative; display: block; width: 100%;
              transition: transform var(--t-ui) var(--ease); }
        .mb-lid {
            position: relative; display: block;
            aspect-ratio: 1000 / 675;
            box-sizing: border-box;
            /* percentage padding resolves against the WIDTH on all four
               sides, so the bezel stays proportional as the card flexes */
            padding: 2.4% 2.4% 5.6%;
            border-radius: 11px 11px 5px 5px;
            background: linear-gradient(158deg,
                #3d4046 0%, #24272c 13%, #1b1e22 50%, #24272c 86%, #383b41 100%);
            box-shadow: inset 0 0 0 1px rgba(255,255,255,.07),
                        inset 0 1px 0 rgba(255,255,255,.13);
        }
        .mb-cam {
            position: absolute; top: 1.05%; left: 50%; transform: translateX(-50%);
            width: 1.05%; aspect-ratio: 1; border-radius: 50%;
            background: #0b0d10; box-shadow: 0 0 0 1px rgba(255,255,255,.07);
        }
        .mb-screen {
            position: relative; display: block; width: 100%; height: 100%;
            border-radius: 3px; overflow: hidden;   /* clips the shot, never the bezel */
            background: #0b0d10;
            box-shadow: inset 0 0 0 1px rgba(0,0,0,.55);
        }
        .mb-screen img {
            display: block; width: 100%; height: 100%;
            /* cover, not fill: the site keeps its own proportions and is
               cropped from the bottom rather than stretched */
            object-fit: cover; object-position: top center;
        }
        /* a single restrained highlight, kept to the top-right corner so
           it never sits over a site's logo or opening headline */
        .mb-glare {
            position: absolute; inset: 0; pointer-events: none;
            background: linear-gradient(205deg,
                rgba(255,255,255,.085) 0%, rgba(255,255,255,.022) 18%, rgba(255,255,255,0) 34%);
        }
        .mb-base {
            position: relative; display: block;
            width: 107%; margin-left: -3.5%;
            height: 0; padding-bottom: 2.5%;
            background: linear-gradient(180deg, #4b4f55 0%, #34383d 16%, #1f2227 68%, #15171a 100%);
            clip-path: polygon(1.5% 0, 98.5% 0, 100% 100%, 0 100%);
        }
        .mb-notch {
            position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
            width: 12%; height: 46%;
            background: #101215; border-radius: 0 0 46% 46%;
        }
        .mb-shadow {
            position: absolute; left: 7%; right: 7%; bottom: -4%; height: 6%;
            background: radial-gradient(50% 50% at 50% 50%,
                rgba(0,0,0,.6) 0%, rgba(0,0,0,0) 72%);
            filter: blur(7px); z-index: -1;
        }

        /* ── Card text ──────────────────────────────────────── */
        .pw-body { display: flex; flex-direction: column; flex: 1 1 auto; padding: 26px 28px 28px; }
        .pw-meta {
            display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
        }
        .pw-num { color: var(--gold); }
        .pw-cat { color: var(--ink-2); }
        .pw-cat::before { content: '/ '; color: var(--ink-3); }
        .pw-loc { color: var(--ink-3); }
        .pw-loc::before { content: '/ '; }
        .pw-name {
            font-size: clamp(21px, 1.55vw, 25px); font-weight: 600;
            line-height: 1.2; letter-spacing: -.02em; color: var(--ink);
            transition: color var(--t-ui) var(--ease);
        }
        .pw-domain {
            margin-top: 5px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 11.5px; letter-spacing: .01em; color: var(--ink-3);
        }
        .pw-desc {
            margin-top: 12px; margin-bottom: 22px;
            font-size: 15px; line-height: 1.65; color: var(--ink-2);
        }
        .pw-foot {
            margin-top: auto; padding-top: 16px;
            border-top: 1px solid var(--line);
            display: flex; align-items: center; justify-content: space-between; gap: 14px;
        }
        .pw-role {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
            color: var(--ink-3);
        }
        .pw-go {
            display: inline-flex; align-items: center; gap: 7px;
            font-size: 14px; font-weight: 500; color: var(--ink);
            transition: color var(--t-ui) var(--ease);
        }
        .pw-go svg {
            width: 14px; height: 14px; flex: 0 0 auto;
            transition: transform var(--t-ui) var(--ease);
        }
        .pw-link:focus-visible {
            outline: 2px solid var(--gold); outline-offset: 3px;
            border-radius: var(--r-lg);
        }
        .pw-link:focus-visible .pw-go { color: var(--gold); }

        @media (hover: hover) {
            .pw-card:hover {
                transform: translateY(-4px);
                border-color: var(--line-2);
                box-shadow: 0 18px 46px rgba(0,0,0,.46);
            }
            /* the whole assembly rises — screen, bezel, base and shadow
               together, so the screenshot never slides inside the frame */
            .pw-card:hover .mb { transform: translateY(-6px); }
            .pw-card:hover .pw-name { color: #FFFFFF; }
            .pw-card:hover .pw-go { color: var(--gold); }
            .pw-card:hover .pw-go svg { transform: translate(2px, -2px); }
        }

        @media (max-width: 991px) {
            .pw-grid { grid-template-columns: minmax(0,1fr); gap: 18px; }
            /* the laptop takes nearly the full card width */
            .pw-media { padding: 16px 16px 15px; }
            .pw-body  { padding: 20px 18px 22px; }
            .pw-name  { font-size: 21px; }
            .pw-desc  { font-size: 14.5px; line-height: 1.6; margin-bottom: 18px; }
            .pw-go    { font-size: 15px; padding: 6px 0; }   /* comfortable tap target */
        }
        @media (prefers-reduced-motion: reduce) {
            .pw-card, .mb, .pw-go svg { transition: none !important; }
            .pw-card:hover, .pw-card:hover .mb { transform: none !important; }
        }

        /* ═══════════════════════════════════════════════════
           ABOUT
           ═══════════════════════════════════════════════════ */
        .ab-grid { display: grid; grid-template-columns: minmax(0,1fr); gap: 44px; align-items: start; }
        @media (min-width: 900px) {
            /* The portrait is 1085x1450 — displayed at ~420px it is
               well inside its source even on a 2x screen. */
            .ab-grid { grid-template-columns: minmax(0, 420px) minmax(0,1fr); gap: 72px; }
        }
        .ab-portrait {
            position: relative; margin: 0;
            border-radius: var(--r-lg);
            overflow: hidden;
            border: 1px solid var(--line);
            background: var(--surface);
        }
        .ab-portrait img { display: block; width: 100%; height: auto; }
        /* the one handwritten thing on the site, sitting on the frame
           rather than floating beside it */
        .ab-sign {
            position: absolute; left: 20px; bottom: 14px;
            font-family: 'Dancing Script', cursive;
            font-size: 30px; line-height: 1;
            color: var(--ink);
            text-shadow: 0 1px 12px rgba(0,0,0,.6);
        }
        .ab-para {
            margin: 0 0 18px !important;
            font-size: 16.5px !important; line-height: 1.8 !important;
            color: var(--ink-2) !important;
            max-width: 58ch;
        }
        .ab-para strong { color: var(--ink); font-weight: 600; }
        .ab-facts {
            display: grid; grid-template-columns: repeat(2, minmax(0,1fr));
            gap: 18px 28px; margin: 34px 0 0;
            padding-top: 26px; border-top: 1px solid var(--line);
        }
        .ab-facts dt {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
            color: var(--ink-3); margin-bottom: 4px;
        }
        .ab-facts dd { margin: 0; font-size: 15px; color: var(--ink); }
        @media (max-width: 479px) { .ab-facts { grid-template-columns: minmax(0,1fr); } }


        /* ═══════════════════════════════════════════════════
           CAPABILITIES
           ═══════════════════════════════════════════════════
           A numbered list, not four cards. Each row is a rule, an
           index, a statement and the technologies that back it — so
           the claim and its evidence sit on the same line. */
        .cap-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
        .cap {
            display: grid;
            grid-template-columns: minmax(0,1fr);
            gap: 14px;
            padding: 30px 0;
            border-bottom: 1px solid var(--line);
            transition: background var(--t-ui) var(--ease);
        }
        @media (min-width: 860px) {
            .cap {
                grid-template-columns: 52px minmax(0,1fr) minmax(0, 300px);
                gap: 28px; align-items: start;
                padding: 34px 0;
            }
        }
        .cap-n {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 12px; letter-spacing: .08em;
            color: var(--gold);
            padding-top: 4px;
        }
        .cap-title {
            margin: 0 0 8px !important;
            font-size: 20px !important; font-weight: 600 !important;
            letter-spacing: -.02em !important;
            color: var(--ink) !important;
        }
        .cap-desc {
            margin: 0 !important;
            font-size: 15.5px !important; line-height: 1.7 !important;
            color: var(--ink-2) !important;
            max-width: 56ch;
        }
        .cap-tech { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; }
        .cap-tech li {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .04em;
            padding: 5px 9px;
            border: 1px solid var(--line);
            border-radius: var(--r-xs);
            color: var(--ink-3);
        }
        @media (hover: hover) and (pointer: fine) {
            .cap:hover .cap-n { color: var(--gold-hi); }
        }

        /* ═══════════════════════════════════════════════════
           TOOLKIT
           ═══════════════════════════════════════════════════ */
        /* ── Toolkit ────────────────────────────────────────
           The original desktop treatment: auto-fit category columns,
           a gold rule under each heading, and plain lists. The compact
           chip layout is phone-only and lives in the ≤767px block
           further down. */
        .tk-grid {
            display: grid; gap: 34px 40px;
            grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
        }
        .tk-name {
            margin: 0 0 14px !important;
            padding-bottom: 12px;
            border-bottom: 1px solid var(--line);
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px !important; font-weight: 500 !important;
            letter-spacing: .12em; text-transform: uppercase;
            color: var(--gold) !important;
        }
        .tk-list { list-style: none; margin: 0; padding: 0; }
        .tk-list li {
            font-size: 15px; line-height: 2;
            color: var(--ink-2);
            transition: color var(--t-tap) var(--ease);
        }
        @media (hover: hover) and (pointer: fine) { .tk-list li:hover { color: var(--ink); } }
        /* Icons, counts and the sprite are phone-only furniture. Hidden
           here, the h3 is its text again and each li is its label again —
           the desktop Toolkit is byte-for-byte the design it was. */
        .tk-ic, .tk-ct, .tk-b, .tk-list .tk-i { display: none; }
        .tk-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
        .tk-i {
            fill: none; stroke: currentColor; stroke-width: 1.6;
            stroke-linecap: round; stroke-linejoin: round;
        }

        /* ═══════════════════════════════════════════════════
           BACKGROUND — timeline
           ═══════════════════════════════════════════════════
           Dates in their own column so the sequence can be scanned
           without reading every entry. No cards. */
        .tl { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); }
        .tl-row {
            display: grid; grid-template-columns: minmax(0,1fr);
            gap: 8px; padding: 28px 0;
            border-bottom: 1px solid var(--line);
        }
        @media (min-width: 760px) {
            .tl-row { grid-template-columns: 176px minmax(0,1fr); gap: 32px; padding: 30px 0; }
        }
        .tl-when {
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 11.5px; letter-spacing: .06em;
            color: var(--ink-3); padding-top: 3px;
        }
        .tl-row.is-now .tl-when { color: var(--gold); }
        .tl-kind {
            display: inline-block; margin-bottom: 7px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10px; letter-spacing: .12em; text-transform: uppercase;
            color: var(--ink-3);
        }
        .tl-org {
            margin: 0 0 4px !important;
            font-size: 19px !important; font-weight: 600 !important;
            letter-spacing: -.02em !important; color: var(--ink) !important;
        }
        .tl-role { display: block; font-size: 15px; color: var(--ink-2); margin-bottom: 7px; }
        .tl-note { display: block; font-size: 14.5px; line-height: 1.65; color: var(--ink-3); max-width: 56ch; }
        .tl-place {
            display: block; margin-top: 9px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .06em; color: var(--ink-3);
        }

        /* ═══════════════════════════════════════════════════
           TESTIMONIALS
           ═══════════════════════════════════════════════════
           Three quotes as type on the page. The old build ran these
           through a Swiper carousel; three items that fit side by
           side never needed one. */
        .tq-grid { display: grid; gap: 28px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
        .tq {
            margin: 0; padding: 30px 28px;
            border: 1px solid var(--line);
            border-radius: var(--r-lg);
            background: var(--surface);
            display: flex; flex-direction: column;
        }
        .tq-text {
            margin: 0 0 22px; padding: 0; border: 0;
            /* style.css italicises blockquote; a whole testimonial set
               in italic is harder to read and reads as decoration */
            font-style: normal;
            font-size: 16px; line-height: 1.75; color: var(--ink-2);
        }
        /* the quote mark is drawn, not typed, so it never lands in
           the accessibility tree or a copied selection */
        .tq-text::before {
            content: ''; display: block;
            width: 22px; height: 2px; margin-bottom: 18px;
            background: var(--gold);
        }
        .tq-by { margin-top: auto; padding-top: 18px; border-top: 1px solid var(--line); }

        /* ── Testimonial carousel (phone only) ──────────────
           The stacked grid above is untouched: these rules only apply
           once `.is-carousel` is on the track, and the script only adds
           it below the mobile breakpoint. Everything here is removed
           again on the way back to tablet/desktop. */
        .tq-grid.is-carousel {
            position: relative;
            display: block;
            /* the gutter between cards lives outside the track, so the
               clip happens in the page margin rather than flush against
               the neighbouring card's border */
            overflow: hidden;
            margin-inline: -8px;
            padding-inline: 8px;
            /* horizontal gestures are ours, vertical scrolling stays
               entirely native */
            touch-action: pan-y;
        }
        /* Position is the only thing that moves. Opacity used to fade
           too, which meant a dragged card dimmed under the finger and
           the neighbour could not be dragged into view at all — the
           track is overflow:hidden, so an offscreen slide is already
           invisible without it. */
        .tq-grid.is-carousel .tq {
            position: absolute; top: 0; bottom: 0; left: 8px; right: 8px;
            /* a drag must not paint a text selection across the quote */
            -webkit-user-select: none; user-select: none;
            -webkit-touch-callout: none;
            transform: translateX(100%);
            transition: transform var(--tq-dur, 900ms) var(--ease);
            will-change: transform;
        }
        .tq-grid.is-carousel .tq[aria-hidden="true"] { pointer-events: none; }
        .tq-grid.is-carousel .tq.is-on { transform: translateX(0); }
        /* while a finger is down the card tracks it 1:1, so no
           transition may interpolate behind the drag */
        .tq-grid.is-dragging .tq { transition: none !important; }
        /* height is measured from the longest quote and set inline, so
           the card never truncates and the page never jumps mid-slide */
        .tq-grid.is-measuring .tq {
            position: relative; inset: auto;
            opacity: 1; transform: none; transition: none;
        }

        .tq-nav {
            display: flex; align-items: center; justify-content: center; gap: 4px;
            margin-top: 14px;
        }
        .tq-dot {
            appearance: none; background: none; border: 0;
            width: 30px; height: 30px;          /* 30px each, in a 44px-tall row */
            padding: 0; cursor: pointer;
            display: inline-flex; align-items: center; justify-content: center;
        }
        .tq-dot::before {
            content: ''; display: block;
            width: 7px; height: 7px; border-radius: 50%;
            background: var(--ink-3);
            transition: background var(--t-tap) var(--ease), transform var(--t-tap) var(--ease);
        }
        .tq-dot[aria-current="true"]::before { background: var(--gold); transform: scale(1.25); }
        .tq-dot:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: 50%; }
        @media (prefers-reduced-motion: reduce) {
            .tq-grid.is-carousel .tq { transition: none !important; }
        }
        .tq-name { display: block; font-size: 15px; font-weight: 600; color: var(--ink); }
        .tq-kind {
            display: block; margin-top: 3px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
            color: var(--ink-3);
        }


        /* ═══════════════════════════════════════════════════
           CONTACT
           ═══════════════════════════════════════════════════ */
        #contacts.get-in-touch-area {
            /* the old build forced this to 100vh and then clawed
               pixels back with a max-height query; it is a normal
               section now, and its height is whatever the content
               needs — the tail under the form was a hard 96px. */
            min-height: 0 !important;
            display: block !important;
            padding-top: var(--pad-section) !important;
            padding-bottom: var(--pad-section) !important;
        }
        /* ── Contact ────────────────────────────────────────
           Two columns on desktop: the lead and the quieter details
           stack down the left, the enquiry panel holds the right.
           Grid AREAS rather than source order, because the phone needs
           lead → form → details while the desktop wants the details
           tucked under the lead. */
        .ct-grid {
            display: flex; flex-direction: column;
            gap: 24px;
        }
        /* Phone: the wrapper vanishes, so `order` can slot the form
           between the lead and the details even though the markup keeps
           those two adjacent for the desktop column. */
        .ct-side  { display: contents; }
        .ct-lead  { order: 1; }
        .ct-panel { order: 2; }
        .ct-more  { order: 3; }
        @media (min-width: 992px) {
            .ct-grid {
                display: grid;
                grid-template-columns: minmax(0, 1fr) minmax(0, 560px);
                column-gap: 48px;
                align-items: stretch;
            }
            /* The left column holds ~444px of content against a ~684px
               form. Anchoring the details to the bottom just moved that
               240px into the middle; centring the whole column splits it
               evenly above and below instead, so neither end reads as
               content that ran out. */
            .ct-side {
                display: flex; flex-direction: column; justify-content: center;
                gap: 30px;
            }
        }

        .ct-title {
            margin: 10px 0 14px !important;
            font-size: clamp(30px, 3.6vw, 50px) !important;
            font-weight: 600 !important;
            line-height: 1.08 !important;
            letter-spacing: -.03em !important;
        }
        .ct-title .ct-t1, .ct-title .ct-t2 { display: block; }
        .ct-title .ct-t1 { color: var(--ink) !important; }
        .ct-title .ct-t2 { color: var(--gold) !important; }
        .ct-lede {
            margin: 0 0 22px !important;
            font-size: 16px !important; line-height: 1.65 !important;
            color: var(--ink-2) !important; max-width: 46ch;
        }

        /* ── Direct contact ─────────────────────────────── */
        .ct-direct { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
        .ct-mail {
            display: inline-flex; align-items: center; gap: 8px;
            padding: 0 16px; min-height: 50px;
            border: 1px solid var(--line-gold); border-radius: var(--r-sm);
            background: var(--gold-wash);
            font-size: 15px; font-weight: 500;
            color: var(--ink) !important; text-decoration: none;
            transition: border-color var(--t-tap) var(--ease), background var(--t-tap) var(--ease);
        }
        .ct-mail svg { width: 14px; height: 14px; flex: 0 0 auto; color: var(--gold);
                       transition: transform var(--t-tap) var(--ease); }
        .ct-mail:hover, .ct-mail:focus-visible { border-color: var(--gold); background: rgba(197,173,125,.16); }
        .ct-mail:hover svg, .ct-mail:focus-visible svg { transform: translate(2px, -2px); }
        .ct-copy, .ct-wa {
            display: inline-flex; align-items: center; gap: 8px;
            /* the template resets `input, button, select, textarea` to
               width:100%, which stretched this button across the column
               and pushed every action onto its own row */
            width: auto !important; flex: 0 0 auto;
            padding: 0 14px; min-height: 50px;
            border: 1px solid var(--line); border-radius: var(--r-sm);
            background: transparent; cursor: pointer;
            font-family: inherit; font-size: 14px;
            color: var(--ink-2) !important; text-decoration: none;
            transition: color var(--t-tap) var(--ease), border-color var(--t-tap) var(--ease);
        }
        .ct-copy svg { width: 15px; height: 15px; }
        .ct-wa i { font-size: 15px; color: var(--gold); }
        .ct-copy:hover, .ct-wa:hover,
        .ct-copy:focus-visible, .ct-wa:focus-visible { color: var(--ink) !important; border-color: var(--line-gold); }
        .ct-copy.is-done { color: var(--gold) !important; border-color: var(--line-gold); }

        /* ── Quieter details ────────────────────────────── */
        .ct-facts { margin: 0; display: grid; gap: 12px; }
        .ct-facts > div { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; }
        .ct-facts dt {
            flex: 0 0 82px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
            color: var(--ink-3);
        }
        .ct-facts dd { margin: 0; font-size: 14.5px; color: var(--ink-2); }
        .ct-facts dd a { color: var(--ink-2) !important; text-decoration: none; }
        .ct-facts dd a:hover { color: var(--gold) !important; }
        .ct-social { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
        .ct-social a {
            display: inline-flex; align-items: center; gap: 7px;
            padding: 9px 13px; min-height: 40px;
            border: 1px solid var(--line); border-radius: 999px;
            font-size: 13.5px; color: var(--ink-2) !important; text-decoration: none;
            transition: color var(--t-tap) var(--ease), border-color var(--t-tap) var(--ease);
        }
        .ct-social a:hover, .ct-social a:focus-visible { color: var(--ink) !important; border-color: var(--line-gold); }
        .ct-social i { font-size: 14px; color: var(--gold); }

        /* ── Enquiry panel ──────────────────────────────── */
        .ct-panel {
            background: var(--surface);
            border: 1px solid var(--line);
            border-radius: var(--r-lg);
            padding: 30px;
        }
        .ct-panel-title {
            margin: 0 0 17px !important;
            font-size: 18px !important; font-weight: 600 !important;
            letter-spacing: -.01em; color: var(--ink) !important;
        }
        .ct-form { display: grid; gap: 15px; }
        .ct-pair { display: grid; gap: 16px; grid-template-columns: repeat(2, minmax(0,1fr)); }
        .ct-field { margin: 0; display: grid; gap: 7px; }
        .ct-field > label {
            font-size: 12.5px; font-weight: 500; letter-spacing: .01em;
            color: var(--ink-2);
        }
        .ct-opt {
            margin-left: 5px;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
            color: var(--ink-3);
        }
        .input-field {
            background: var(--bg) !important;
            border: 1px solid var(--line) !important;
            color: var(--ink) !important;
            border-radius: var(--r-sm) !important;
            font-family: 'Space Grotesk', sans-serif !important;
            font-size: 16px !important;   /* 16px min, or iOS zooms on focus */
            padding: 13px 15px !important;
            min-height: 50px !important;
            width: 100% !important;
            transition: border-color var(--t-tap) var(--ease), box-shadow var(--t-tap) var(--ease) !important;
        }
        .input-field::placeholder { color: var(--ink-3) !important; opacity: 1; }
        .input-field:hover { border-color: var(--line-2) !important; }
        .input-field:focus {
            outline: none !important;
            border-color: var(--gold) !important;
            box-shadow: 0 0 0 3px var(--gold-wash) !important;
        }
        textarea.input-field { min-height: 134px !important; resize: vertical; line-height: 1.6 !important; }
        .ct-field.is-bad .input-field { border-color: #E4756B !important; }
        .ct-err { display: none; font-size: 12.5px; color: #E4756B; }
        .ct-field.is-bad .ct-err, .ct-choice.is-bad .ct-err { display: block; }

        /* ── Service chips (radios) ─────────────────────── */
        .ct-choice { margin: 0; padding: 0; border: 0; display: grid; gap: 9px; }
        .ct-choice legend {
            padding: 0; float: left; width: 100%;
            font-size: 12.5px; font-weight: 500; color: var(--ink-2);
        }
        .ct-chips { display: flex; flex-wrap: wrap; gap: 8px; clear: both; }
        .ct-chip { margin: 0; cursor: pointer; }
        .ct-chip input {
            position: absolute; opacity: 0; width: 1px; height: 1px;
            margin: 0; pointer-events: none;
        }
        .ct-chip span {
            display: inline-flex; align-items: center;
            padding: 9px 13px; min-height: 40px;
            border: 1px solid var(--line); border-radius: 8px;
            background: var(--bg);
            font-size: 13.5px; color: var(--ink-2);
            transition: color var(--t-tap) var(--ease), border-color var(--t-tap) var(--ease),
                        background var(--t-tap) var(--ease);
        }
        .ct-chip:hover span { border-color: var(--line-2); color: var(--ink); }
        .ct-chip input:checked + span {
            border-color: var(--line-gold); background: var(--gold-wash);
            color: var(--ink); font-weight: 500;
        }
        /* keyboard users get the same ring the inputs use */
        .ct-chip input:focus-visible + span {
            border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-wash);
        }

        /* the honeypot is never shown and never announced */
        .ct-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

        .ct-submit {
            justify-self: start; width: auto !important; min-width: 0 !important;
            min-height: 50px;
        }
        .ct-submit[disabled] { opacity: .65; cursor: progress; }
        #form-status { margin: 2px 0 0; min-height: 1.4em; font-size: 14px; color: var(--ink-2) !important; }
        #form-status.is-bad { color: #E4756B !important; }
        #form-status.is-good { color: var(--gold) !important; }

        /* ═══════════════════════════════════════════════════
           FOOTER
           ═══════════════════════════════════════════════════ */
        .site-footer {
            background: transparent;
            border-top: 1px solid var(--line);
            padding: 34px 0;
            margin-top: 0;
        }
        .site-footer .footer-inner {
            display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 18px;
        }
        .site-footer .footer-copy {
            margin: 0;
            font-family: 'JetBrains Mono', ui-monospace, monospace;
            font-size: 11px !important; letter-spacing: .04em;
            color: var(--ink-3) !important;
        }
        .site-footer .footer-social { display: flex; gap: 6px; }
        /* 40px hit areas rather than bare glyphs — these are the
           smallest targets on the page and sit at the very bottom,
           where a thumb is least accurate */
        .site-footer .footer-social a {
            display: grid; place-items: center;
            width: 40px; height: 40px; border-radius: 50%;
            color: var(--ink-3) !important; font-size: 15px;
            /* the template fills these with a grey disc */
            background: transparent !important; background-color: transparent !important;
            border: 1px solid transparent;
            transition: color var(--t-tap) var(--ease), border-color var(--t-tap) var(--ease);
        }
        .site-footer .footer-social a:hover { color: var(--gold) !important; border-color: var(--line); }
        @media (max-width: 575px) { .site-footer .footer-inner { flex-direction: column; text-align: center; } }

        /* ═══════════════════════════════════════════════════
           SCROLL-TO-TOP
           ═══════════════════════════════════════════════════ */
        .scrollToTop {
            background: var(--surface) !important;
            border: 1px solid var(--line) !important;
            z-index: 20;
        }
        .scrollToTop .arrowUp i { color: var(--ink) !important; filter: none !important; }
        /* the template's rising "water" fill */
        .scrollToTop .water { background-color: var(--gold-lo) !important; }
        .scrollToTop .water svg use { fill: var(--gold-lo) !important; }

        /* ── Template leftovers ─────────────────────────────
           Wrappers style.css paints with its own backgrounds and a
           decorative ::before pointing at an image this template
           never shipped (a 404 on every load). */
        .client-testimonial-swiper::before { background-image: none !important; }
        .bg-blur-style-three, .bg-vactor-one,
        .latest-portfolio-tabs-area, .tab-content { background: transparent !important; }

        /* ═══════════════════════════════════════════════════
           GLOBAL TYPE SCALE
           ═══════════════════════════════════════════════════ */
        p, .description, .disc {
            font-size: 16.5px !important;
            line-height: 1.75 !important;
            color: var(--ink-2) !important;
        }
        .tmp-mainmenu li a, .tmp-mainmenu .nav-item a { font-size: 15px !important; }


        /* ═══════════════════════════════════════════════════
           HERO MEDIA — device + live screen
           ═══════════════════════════════════════════════════
           A photorealistic still of one phone, with the Instruktori
           AI interface built as real HTML and mapped into its
           display.

           This replaced a generated rotation film for two reasons a
           video could not fix: turning the device produced a screen
           on BOTH faces, and no generated video holds legible
           interface text. A still cannot flip. HTML text is sharp at
           any size, and because the screen is a child of the element
           that rocks, it cannot slide or drift away from the glass —
           the alignment is structural, not tracked.

           Interface colours are taken from the live site:
           ground #070B14, surface #0E1524, ink #E9EDF5,
           muted #93A1BA, amber #F5B400, Inter. */
        /* ── Instruktori AI phone ───────────────────────────
           RESTORED from the pre-rewrite version (the state captured in
           index.BEFORE-SPLIT.html, before the mobile-specific chat
           layout and the JS timeline). One component, one interface,
           one animation sequence, shared by desktop and mobile.
           Everything below this banner is that version verbatim. */
        /* align-items:flex-start so the figure keeps its own 607px
           height instead of being stretched to the stage's reserved
           (already scaled) height. */
        .hero-stage { display: flex; justify-content: center; align-items: flex-start;
                      width: 100%; min-width: 0; }
        .hero-device {
            position: relative;
            margin: 0 auto;
            width: 100%;
            /* Capped so the device column stays close to the height of
               the text column beside it. Taller than this and the row's
               vertical centring pushes the headline down the page, and
               the hero stops fitting inside one screen. */
            max-width: 392px;
        }
        /* ── Caption under the device ───────────────────────
           One small uppercase line. It sits in the
           figure but outside .dev-rock, so the rock's rotation and the
           screen's matrix3d never touch it — it stays level and sharp.

           The gap constant is measured, not read off the file: the
           render fades into the page background rather than being
           transparent, so its alpha bbox reports no padding at all and
           a luminance threshold gives anything from 51px to 68px. It
           was solved on the rendered page instead — 31.7px of empty
           frame at the authored 392px width, scaling with the device.
           Subtracting it means the gap below the GLASS is the number
           written here, not the number the layout box would give. */
        .dev-cap {
            --dev-dead-bottom: calc(31.7px * var(--dev-scale, 1));
            display: flex;
            justify-content: center;
            margin-top: calc(16px - var(--dev-dead-bottom));
            text-align: center;
        }
        .dev-cap-label {
            font-family: 'Space Grotesk', sans-serif;
            font-size: 10.5px; font-weight: 600;
            letter-spacing: .11em; text-transform: uppercase;
            color: var(--ink-3);
            line-height: 1.2;
        }

        /* The whole assembly — body and screen together — rocks as
           one object. ±3deg, 9s, and it never turns far enough to
           show an edge the photograph does not contain. */
        .dev-rock {
            position: relative;
            /* reserved before the image decodes: 780x1207 */
            aspect-ratio: 780 / 1207;
            transform-origin: 50% 60%;
            animation: devRock 9s var(--ease) infinite;
            will-change: transform;
        }
        @keyframes devRock {
            0%,100% { transform: rotate(-0.9deg) translateY(0); }
            50%     { transform: rotate(0.9deg)  translateY(-4px); }
        }
        .dev-body {
            display: block; width: 100%; height: auto;
            /* The render's own backdrop is flattened onto #101113 in the
               asset itself, so there is no rectangle to hide. This only
               feathers the last few percent of each edge, which takes
               care of the residual unit or two of difference and of any
               colour management the browser applies. It is generous
               enough that it never touches the device. */
            -webkit-mask-image: linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
                                linear-gradient(to bottom, transparent 0, #000 5%, #000 95%, transparent 100%);
            -webkit-mask-composite: source-in;
            mask-image: linear-gradient(to right,  transparent 0, #000 7%, #000 93%, transparent 100%),
                        linear-gradient(to bottom, transparent 0, #000 5%, #000 95%, transparent 100%);
            mask-composite: intersect;
        }

        /* ── The display ────────────────────────────────────
           Positioned and sized from the screen quad measured in the
           render itself, then tapered by a homography so it sits on
           the glass rather than merely near it. The homography is
           written by script once and on resize; these percentages
           are the fallback, and are already within a few pixels. */
        .dev-screen {
            position: absolute;
            left: 24.788%; top: 8.662%;
            width: 47.20%; height: 82.57%;
            overflow: hidden;                    /* clipped to the glass */
            border-radius: 6% / 2.4%;            /* follows the corner radius */
            transform-origin: 0 0;
            /* slight shear: the top-right corner sits higher than the
               top-left in the photograph */
            transform: skewY(-2.26deg);
            background: #070B14;
        }
        .dev-ui {
            position: absolute; inset: 0;
            /* Sized by script to exactly 2x the display quad, so every
               length here is worth half a CSS pixel on screen. Read the
               apparent size of anything below by halving it: the chat
               bubbles are 30px here, which is 15px on the glass. */
            width: 360px; height: 780px;
            transform-origin: 0 0;
            font-family: 'Inter', system-ui, sans-serif;
            color: #E9EDF5;
            display: flex; flex-direction: column;
            background: #070B14;
            letter-spacing: -.005em;
            /* nothing dims, blurs or hazes the interface: no overlay,
               no filter, no reduced opacity on the content itself */
            opacity: 1; filter: none;
            /* NOT `antialiased`. That switch drops subpixel rendering and
               thins every stroke, and this interface is light type on a
               near-black panel at 12-15px apparent — exactly the case
               where thinning reads as blur. Measured on the answer bubble
               at both DPR 2 and DPR 3: +17.6% contrast, identical edge
               slope, so the glyphs get fuller without getting softer. */
            -webkit-font-smoothing: auto;
            /* The phone's display is the real viewport for this
               interface, so it adapts to its own width rather than the
               browser's — the same layout has to work in a 370px
               authored screen on a desktop and a 272px one at 320. */
            container-type: inline-size;
            container-name: scr;
        }
        /* secondary line goes first, then the wordmark — the product
           name and the language switch are what must survive */

        /* ── Header ─────────────────────────────────────────── */
        .ui-top {
            display: flex; align-items: center; gap: 8px;
            padding: 13px 14px;
            border-bottom: 1px solid rgba(233,237,245,.10);
            flex: 0 0 auto;
            background: #070B14;
        }
        .ui-mark {
            font-size: 18px; font-weight: 800; letter-spacing: .01em;
            color: #FFFFFF; font-style: italic;
            padding-right: 8px; border-right: 1px solid rgba(233,237,245,.18);
            flex: 0 0 auto;
        }
        .ui-titles { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
        /* nowrap + ellipsis: the lockup has to hold one line at a
           172px screen, and a wrapped product name reads as broken */
        .ui-titles b {
            font-size: 29px; font-weight: 700; line-height: 1.2; color: #FFFFFF;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        }
        .ui-titles i {
            font-size: 21px; font-style: normal; line-height: 1.3;
            color: #A9B6CC;                      /* lifted for contrast */
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        }
        .ui-lang { display: flex; border-radius: 8px; overflow: hidden; flex: 0 0 auto; }
        .ui-lang u, .ui-lang s {
            font-size: 20px; font-weight: 700; text-decoration: none;
            padding: 5px 8px; line-height: 1;
        }
        .ui-lang u { background: #F5B400; color: #0A0A0A; }
        .ui-lang s { color: #A9B6CC; background: #141C2E; }

        .ui-thread { position: relative; flex: 1 1 auto; overflow: hidden; }
        /* Messages stack from the BOTTOM, against the input bar, the
           way every chat client works — which is also what removes the
           dead area that used to sit under the exchange. */
        .ui-scroll {
            position: absolute; inset: 0;
            padding: 18px;
            display: flex; flex-direction: column; justify-content: flex-end; gap: 16px;
            animation: uiScroll var(--ui-cycle, 16s) var(--ease) infinite;
        }

        /* ── Welcome ────────────────────────────────────────── */
        /* Taken out of the flow: while it is fading out it must not
           keep holding a block of empty space above the conversation. */
        .ui-welcome {
            position: absolute; left: 18px; right: 18px; top: 0; bottom: 0;
            display: flex; flex-direction: column; justify-content: center;
            animation: uiWelcome var(--ui-cycle, 16s) var(--ease) infinite;
        }
        .ui-h {
            font-size: 35px !important; font-weight: 700; text-align: center;
            margin: 16px 0 10px !important; color: #FFFFFF !important; line-height: 1.2 !important;
        }
        .ui-sub {
            font-size: 25px !important; color: #A9B6CC !important; text-align: center;
            margin: 0 0 18px !important; line-height: 1.4 !important;
        }
        /* One column, not two. At this screen width a two-up grid
           gave each chip ~8 characters, which forced the label to
           either shrink or wrap mid-phrase. Full-width chips keep the
           real labels intact and readable. */
        .ui-chips { display: flex; flex-direction: column; gap: 9px; }
        .ui-chips span {
            font-size: 28px; color: #DCE4F2;
            background: #101A2C; border: 1px solid rgba(233,237,245,.10);
            border-radius: 12px; padding: 14px 15px; line-height: 1.25;
        }
        /* the last two are dropped on the smallest screens rather than
           squeezed — the welcome is on screen for three seconds */
        .ui-chips span:nth-child(n+4) { display: none; }

        /* ── The exchange ───────────────────────────────────── */
        .ui-q, .ui-a {
            max-width: 90%; border-radius: 18px; padding: 16px 18px; opacity: 0;
            font-size: 30px; line-height: 1.38;      /* the largest that keeps the
                                                       question on two lines */
        }
        .ui-q {
            align-self: flex-end;
            background: #F5B400; color: #12100A;     /* dark ink on yellow */
            font-weight: 500;
            border-bottom-right-radius: 7px;
            animation: uiPop var(--ui-cycle, 16s) var(--ease) infinite;
        }
        .ui-a {
            align-self: flex-start;
            font-weight: 450;     /* holds its colour once minified */
            background: #16203A; border: 1px solid rgba(233,237,245,.12);
            color: #FFFFFF;                          /* bright on the dark bubble */
            border-bottom-left-radius: 7px;
            display: flex; flex-direction: column;
            /* Its own keyframes, NOT uiPop + animation-delay: a delay
               shifts the fade-OUT by the same amount, so the bubble
               outlived its own text and was still on screen after the
               welcome had faded back in — an empty panel over the
               welcome. Entrance is late here; the exit is shared. */
            animation: uiPopA var(--ui-cycle, 16s) var(--ease) infinite;
        }
        /* Inline, not blocks, and no nowrap: the answer is one
           paragraph that wraps to whatever width the screen actually
           is. The three spans still fade in sequence, so it still
           reads as being written rather than pasted — but the line
           breaks are the browser's, not mine, and they cannot
           overflow the bubble at a larger type size. */
        .ui-a { display: block; }
        .ui-a span {
            display: inline; white-space: normal;
            opacity: 0;
        }
        .ui-a span + span::before { content: ' '; }
        /* One keyframe set per line rather than a shared animation plus
           animation-delay. The delays never applied anyway — `.ui-a span`
           (0,1,1) outranked `.ui-a1` (0,1,0), so the shorthand reset them
           to 0 and all three lines faded in together. Baking the offset
           into the keyframes restores the stagger AND keeps every line
           leaving on the same frame as the bubble. */
        .ui-a1 { animation: uiLine1 var(--ui-cycle, 16s) var(--ease) infinite; }
        .ui-a2 { animation: uiLine2 var(--ui-cycle, 16s) var(--ease) infinite; }
        .ui-a3 { animation: uiLine3 var(--ui-cycle, 16s) var(--ease) infinite; }

        .ui-dots {
            align-self: flex-start; display: flex; gap: 7px;
            background: #16203A; border: 1px solid rgba(233,237,245,.12);
            border-radius: 18px; padding: 16px 18px; opacity: 0;
            animation: uiDots var(--ui-cycle, 16s) var(--ease) infinite;
        }
        .ui-dots i {
            width: 7px; height: 7px; border-radius: 50%; background: #A9B6CC;
            animation: uiBlink .9s ease-in-out infinite;
        }
        .ui-dots i:nth-child(2) { animation-delay: .15s; }
        .ui-dots i:nth-child(3) { animation-delay: .3s; }
        @keyframes uiBlink { 0%,100%{opacity:.35} 50%{opacity:1} }

        /* ── Input ──────────────────────────────────────────── */
        /* Fixed height, and the field is taken out of the flow inside
           it. The composer therefore grows UPWARD over the conversation
           as the question is typed — what a real chat input does — and
           the thread and welcome behind it never get squeezed. */
        .ui-bar {
            flex: 0 0 auto; position: relative; height: 83px;
            display: flex; align-items: flex-end; justify-content: flex-end;
            padding: 14px 18px 16px;
            border-top: 1px solid rgba(233,237,245,.10);
            background: #070B14;
        }
        .ui-input {
            position: absolute; left: 18px; bottom: 16px; right: 80px;
            box-sizing: border-box;      /* these spans are content-box by default */
            background: #101A2C; border: 1px solid rgba(233,237,245,.12);
            border-radius: 12px; padding: 7px 14px; min-height: 52px;
            display: flex; align-items: center;
        }
        .ui-ph {
            position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
            font-size: 30px; line-height: 1.25; color: #93A0B6;
            white-space: nowrap;
            animation: uiPh var(--ui-cycle,16s) var(--ease) infinite;
        }
        /* The question wraps instead of scrolling sideways. Each word
           is an inline-block wiped open from zero width in turn, so the
           line grows left-to-right and breaks naturally — the field's
           own height follows, with no measuring and nothing to scroll.
           The leading space lives INSIDE each word (white-space: pre)
           so a word that is still closed contributes no gap. */
        .ui-type {
            font-size: 30px; line-height: 1.25; color: #FFFFFF;
            white-space: normal;
        }
        .ui-type i {
            display: inline-block; vertical-align: top;
            white-space: pre; font-style: normal;
            max-width: 0; overflow: hidden;
        }
        .ui-w1 { animation: uiW1 var(--ui-cycle,16s) linear infinite; }
        .ui-w2 { animation: uiW2 var(--ui-cycle,16s) linear infinite; }
        .ui-w3 { animation: uiW3 var(--ui-cycle,16s) linear infinite; }
        .ui-w4 { animation: uiW4 var(--ui-cycle,16s) linear infinite; }
        .ui-w5 { animation: uiW5 var(--ui-cycle,16s) linear infinite; }
        .ui-w6 { animation: uiW6 var(--ui-cycle,16s) linear infinite; }
        .ui-w7 { animation: uiW7 var(--ui-cycle,16s) linear infinite; }
        /* zero-width, so it always sits exactly at the writing edge */
        .ui-caret {
            display: inline-block; vertical-align: top;
            width: 0; height: 1.15em; max-width: none; overflow: visible;
            border-left: 2px solid #F5B400; opacity: 0;
            animation: uiCaretShow var(--ui-cycle,16s) step-end infinite,
                       uiCaretBlink .7s step-end infinite;
        }
        @keyframes uiCaretShow { 0%,2.5%{opacity:0} 3%,21%{opacity:1} 22%,100%{opacity:0} }
        @keyframes uiCaretBlink { 0%,100%{border-color:#F5B400} 50%{border-color:transparent} }
        .ui-send {
            flex: 0 0 auto; width: 52px; height: 52px; border-radius: 12px;
            background: #101A2C; border: 1px solid rgba(233,237,245,.12);
            position: relative;
            animation: uiSend var(--ui-cycle,16s) var(--ease) infinite;
        }
        .ui-send::after {
            content: ''; position: absolute; left: 50%; top: 50%;
            width: 11px; height: 11px; margin: -4px 0 0 -6px;
            border-left: 2px solid #C7D2E4; border-top: 2px solid #C7D2E4;
            transform: rotate(45deg);
        }

        /* ── The 16s cycle ──────────────────────────────────── */
        /* Each word is wiped open across its own slice of the
           3%%→20%% typing window, sized in ch so the wipe runs at
           roughly one character at a time. Every word closes at
           22%%, when the question is sent. */
        @keyframes uiW1 {   /* 'Çfarë' */
            0%,3.00%   { max-width: 0; }
            5.43%,21%  { max-width: 7ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiW2 {   /* ' mund' */
            0%,5.43%   { max-width: 0; }
            7.86%,21%  { max-width: 7ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiW3 {   /* ' të' */
            0%,7.86%   { max-width: 0; }
            9.31%,21%  { max-width: 5ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiW4 {   /* ' më' */
            0%,9.31%   { max-width: 0; }
            10.77%,21%  { max-width: 5ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiW5 {   /* ' ndihmosh' */
            0%,10.77%   { max-width: 0; }
            15.14%,21%  { max-width: 11ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiW6 {   /* ' të' */
            0%,15.14%   { max-width: 0; }
            16.60%,21%  { max-width: 5ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiW7 {   /* ' mësoj?' */
            0%,16.60%   { max-width: 0; }
            20.00%,21%  { max-width: 9ch; }
            22%,100%   { max-width: 0; }
        }
        @keyframes uiPh {
            0%,2%   { opacity: 1; }
            3%,22%  { opacity: 0; }
            23%,100%{ opacity: 1; }
        }
        @keyframes uiSend {
            0%,19%  { background: #0E1524; }
            20%,22% { background: #F5B400; }
            23%,100%{ background: #0E1524; }
        }
        @keyframes uiWelcome {
            0%,20%  { opacity: 1; transform: none; }
            24%     { opacity: 0; transform: translateY(-6px); }
            92%     { opacity: 0; transform: translateY(-6px); }
            97%,100%{ opacity: 1; transform: none; }
        }
        @keyframes uiPop {
            0%,22%  { opacity: 0; transform: translateY(6px) scale(.98); }
            25%,90% { opacity: 1; transform: none; }
            95%,100%{ opacity: 0; transform: translateY(-4px); }
        }
        @keyframes uiPopA {
            0%,29.5% { opacity: 0; transform: translateY(6px) scale(.98); }
            32.5%,90%{ opacity: 1; transform: none; }
            95%,100% { opacity: 0; transform: translateY(-4px); }
        }
        /* The first line rises WITH the bubble, not after it: an 80ms
           lead was enough to show a briefly empty panel. Lines two and
           three still trail, so the answer reads as being written.
           All three leave at 90% with the bubble. */
        @keyframes uiLine1 {
            0%,29.5% { opacity: 0; transform: translateY(3px); }
            32.5%,90%{ opacity: 1; transform: none; }
            95%,100% { opacity: 0; }
        }
        @keyframes uiLine2 {
            0%,32%  { opacity: 0; transform: translateY(3px); }
            35%,90% { opacity: 1; transform: none; }
            95%,100%{ opacity: 0; }
        }
        @keyframes uiLine3 {
            0%,34%  { opacity: 0; transform: translateY(3px); }
            37%,90% { opacity: 1; transform: none; }
            95%,100%{ opacity: 0; }
        }
        @keyframes uiDots {
            0%,25%  { opacity: 0; }
            26%,30% { opacity: 1; }
            31%,100%{ opacity: 0; }
        }
        /* The thread eases up as the answer lands. Travel is a share
           of the authored height rather than a fixed pixel count, so
           it stays correct now that the authored box tracks the quad. */
        @keyframes uiScroll {
            0%,30%  { transform: translateY(0); }
            42%,90% { transform: translateY(var(--scroll-travel, -4.5%)); }
            96%,100%{ transform: translateY(0); }
        }

        /* ── Narrow-display adaptations ─────────────────────
           Container queries carry no specificity of their own, so this
           layer has to sit after every rule it overrides. */
        /* Order of surrender as the display narrows: the START mark
           goes first (the product name beside it already carries the
           brand), then the subtitle. "Instruktori AI" and the language
           switch never clip — a clipped product name reads as broken. */
        @container scr (max-width: 400px) {
            .ui-mark { display: none; }
        }
        /* The placeholder shortens rather than being cut mid-letter:
           the full string needs 280px and the field only ever offers
           144-244px except on the widest layout. */
        @container scr (max-width: 480px) {
            .ui-ph { font-size: 0; }
            .ui-ph::before { content: 'Shkruaj pyetjen'; font-size: 30px; }
        }
        @container scr (max-width: 310px) {
            .ui-ph::before { content: 'Pyet k\00EB tu'; }
        }
        @container scr (max-width: 320px) {
            .ui-titles i { display: none; }
        }
        @container scr (max-width: 300px) {
            .ui-chips span:nth-child(n+3) { display: none; }
            /* last 16px come out of the language switch, not the name */
            .ui-lang u, .ui-lang s { font-size: 16px; padding: 5px 6px; }
            .ui-top { padding-left: 11px; padding-right: 11px; gap: 6px; }
            /* At this size the exchange is taller than the glass, so
               the padding gives way rather than the type. Narrower
               gutters also widen the text column, which costs the
               answer a line or two of wrapping. */
            .ui-scroll { padding: 10px; gap: 10px; --scroll-travel: 0%; }
            .ui-q, .ui-a { max-width: 98%; padding: 12px 13px; line-height: 1.34; }
            .ui-welcome { left: 12px; right: 12px; }
        }

        /* ── Contact, phone ─────────────────────────────────
           The form comes third, right after the lead and the two
           direct actions, so it is reachable without scrolling past a
           column of contact rows. */
        @media (max-width: 767px) {
            .ct-grid { gap: 22px; }
            .ct-title { font-size: clamp(30px, 8.4vw, 34px) !important; line-height: 1.12 !important;
                        margin: 8px 0 12px !important; }
            .ct-lede  { font-size: 15px !important; margin-bottom: 18px !important; }
            .ct-panel { padding: 19px; }
            .ct-panel-title { font-size: 16.5px !important; margin-bottom: 16px !important; }
            .ct-pair  { grid-template-columns: minmax(0,1fr); }   /* stacked */
            .ct-direct { gap: 8px; }
            .ct-mail { flex: 1 1 100%; justify-content: center; }
            .ct-copy, .ct-wa { flex: 1 1 calc(50% - 4px) !important; justify-content: center; }
            .ct-submit { width: 100% !important; justify-self: stretch; }
            textarea.input-field { min-height: 132px !important; }

            /* ── Secondary details, phone ───────────────────
               The label/value columns cost 74px to a label and left
               the location fighting for the rest — two lines at 320px.
               Stacked instead: the label sits above its value and the
               value gets the full width.

               The two social links then split the row the way Copy
               email and WhatsApp do above them, so the block ends on
               the same rhythm instead of two pills stranded against
               150px of empty space. */
            .ct-more {
                padding-top: 20px;
                border-top: 1px solid var(--line);
            }
            .ct-facts { gap: 14px; }
            .ct-facts > div { display: block; }
            .ct-facts dt { margin-bottom: 3px; }
            .ct-facts dd { font-size: 15px; line-height: 1.5; }
            .ct-social { gap: 8px; margin-top: 18px; }
            .ct-social a {
                flex: 1 1 calc(50% - 4px);
                justify-content: center;
                min-height: 46px;
            }
        }
        /* The back-to-top button is fixed bottom-right and would sit over
           the submit button. While the panel is on screen it steps aside. */
        .scrollToTop.is-hidden {
            opacity: 0 !important; pointer-events: none !important;
            transition: opacity .25s var(--ease);
        }

        /* ═══════════════════════════════════════════════════
           DESKTOP NAV CAPSULE
           The links sit inside one rounded container instead of
           floating loose in the bar, and the active section reads as
           a filled pill rather than a hairline underline. The fill is
           off-white, not gold: gold stays reserved for "Let's Talk",
           so the two don't compete for the same glance.

           Specificity, not order, is what makes these hold. They have
           to outrank style.css's `.tmp-mainmenu-nav .tmp-mainmenu > li
           > a` panel, Bootstrap's .nav-pills backgrounds, and the
           `@media (pointer: coarse)` padding further down the file —
           hence the three-class prefix on every rule.
           ═══════════════════════════════════════════════════ */
        /* ── Three-column bar ───────────────────────────────
           The capsule is centred on the bar itself, not merely spaced
           away from its neighbours: 1fr | auto | 1fr gives the brand
           and the right-hand group equal columns, so the capsule's
           centre is the bar's centre at every width.

           This only fits because the four social icons leave the
           desktop header — brand 215 + capsule 595 + CTA 129 + socials
           196 filled all 1176px of the bar, which is why the gaps were
           stuck at 20px. The same four links are in the footer. */
        @media (min-width: 1200px) {
            .tmp-header-area-start .header-content {
                display: grid;
                grid-template-columns: 1fr auto 1fr;
                align-items: center;
            }
            .tmp-header-area-start .header-content { position: relative; }
            .tmp-header-area-start .header-content > .brand { grid-column: 1; justify-self: start; }
            .tmp-header-area-start .header-content > .tmp-header-right { grid-column: 3; justify-self: end; }
            /* Absolute, not a grid cell. In flow its 595px min-content set a
               floor on how narrow the bar could be, so collapsing it meant
               animating width from auto to 0 — which does not interpolate and
               snapped on the first frame. Out of flow it is centred on the bar
               by geometry and animates on opacity and transform only. */
            .tmp-header-area-start .header-content > .tmp-mainmenu-nav {
                position: absolute;
                left: 50%; top: 50%;
                transform: translate(-50%, -50%);
            }
            .tmp-header-area-start .social-share-wrapper { display: none !important; }
        }

        @media (min-width: 1200px) {
            .tmp-header-area-start .tmp-mainmenu-nav {
                padding: 5px;
                border-radius: 999px;
                border: 1px solid rgba(233,237,245,.09);
                background: rgba(255,255,255,.035);
            }
            .tmp-header-area-start .tmp-mainmenu-nav ul.tmp-mainmenu { gap: 2px; }
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li { margin: 0; }

            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li > a {
                display: block;
                padding: 8px 15px !important;
                border-radius: 999px !important;
                line-height: 1.25 !important;
                color: var(--ink-2) !important;
                background: transparent !important;
                transition: color 200ms var(--ease), background-color 200ms var(--ease) !important;
            }
            /* the underline both the template and the old design drew */
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li > a::after,
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li:hover > a::after,
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li.current > a::after {
                display: none !important;
            }
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li > a:hover,
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li:hover > a {
                color: var(--ink) !important;
                background: rgba(255,255,255,.07) !important;
            }
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li.current > a {
                color: #12100A !important;
                background: var(--ink) !important;
                font-weight: 600 !important;
            }
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li > a:focus-visible {
                outline: 2px solid var(--gold);
                outline-offset: 2px;
            }
        }
        @media (prefers-reduced-motion: reduce) {
            .tmp-header-area-start .tmp-mainmenu-nav .tmp-mainmenu > li > a { transition: none !important; }
        }

        /* ═══════════════════════════════════════════════════
           DESKTOP HEADER — expanded ⇄ compact pill
           One element changes shape: .header-content keeps the header's
           72px footprint in both states (56px tall + 16px top margin),
           so the page never shifts and there is never a second header.
           ═══════════════════════════════════════════════════ */
        @media (min-width: 1200px) {
            /* One duration and one curve for the whole morph, declared on the
               header so every part of it inherits the same timing. The curve
               spreads the distance evenly — ~30% travelled at 20% of the way,
               ~90% at 60%. A harder ease-out covered 97% inside the first
               90ms, which reads as a snap with a long tail, not a morph. */
            .tmp-header-area-start {
                --morph-d: 460ms;
                --morph-e: cubic-bezier(.4, 0, .2, 1);
            }
            .tmp-header-area-start .header-content {
                --morph: var(--morph-d) var(--morph-e);
                max-width: 1260px;          /* px at both ends so it interpolates */
                margin: 0 auto;
                border: 1px solid transparent;
                border-radius: 0;
                background: transparent;
                /* expanding: the bar opens first, the links follow (below) */
                transition: max-width var(--morph), height var(--morph),
                            margin-top var(--morph), padding var(--morph),
                            gap var(--morph), border-radius var(--morph),
                            border-color var(--morph), background-color var(--morph),
                            box-shadow var(--morph), backdrop-filter var(--morph);
            }
            /* The column template stays `1fr auto 1fr` in both states. Swapping
               it for `auto 0 auto` was the single worst part of the old morph:
               grid-template-columns does not interpolate, so the brand and the
               CTA teleported to their end positions on the first frame while
               the bar was still 1176px wide. */
            .tmp-header-area-start.is-compact .header-content {
                transition-delay: 40ms;     /* let the links clear out first */
                max-width: 348px;
                height: 56px;
                margin-top: 16px;           /* 16 + 56 = the same 72px footprint */
                padding: 0 8px 0 14px !important;
                gap: 12px;
                border-radius: 999px;
                border-color: rgba(233,237,245,.10);
                background-color: #15171A;  /* opaque fallback */
                box-shadow: 0 10px 30px rgba(0,0,0,.42);
            }
            @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
                .tmp-header-area-start.is-compact .header-content {
                    background-color: rgba(21,23,26,.78);
                    -webkit-backdrop-filter: blur(14px) saturate(140%);
                    backdrop-filter: blur(14px) saturate(140%);
                }
            }

            /* Links and socials fade out, then leave the flow. visibility
               (not just opacity) is what takes them out of the tab order —
               a hidden control must not stay focusable. */
            /* expanding: the bar opens first; the capsule only fades back in
               once there is width to hold it, so it is never seen overlapping
               the brand or the CTA */
            .tmp-header-area-start .header-content > .tmp-mainmenu-nav {
                transition: opacity 190ms linear 230ms,
                            transform 300ms var(--morph-e) 200ms,
                            visibility 0s linear 0s;
            }
            /* collapsing: the capsule is gone by 130ms, well before the bar
               has given up any real width */
            .tmp-header-area-start.is-compact .header-content > .tmp-mainmenu-nav {
                opacity: 0; visibility: hidden; pointer-events: none;
                transform: translate(-50%, -50%) scale(.96);
                transition: opacity 130ms linear,
                            transform 190ms var(--morph-e),
                            visibility 0s linear 130ms;
            }

            /* The role line used to be display:none, which cannot animate —
               it vanished on frame 1 and the brand jumped up to re-centre.
               Collapsing its height keeps the brand block moving with
               everything else. */
            .tmp-header-area-start .brand-role {
                display: block; height: 14px; overflow: hidden;
                transition: height var(--morph-d) var(--morph-e),
                            opacity 180ms linear 120ms;
            }
            .tmp-header-area-start.is-compact .brand-role {
                height: 0; opacity: 0;
                transition: height var(--morph-d) var(--morph-e),
                            opacity 120ms linear;
            }
            .tmp-header-area-start .brand-mark {
                transition: filter var(--t-tap) var(--ease),
                            width var(--morph-d) var(--morph-e),
                            height var(--morph-d) var(--morph-e),
                            flex-basis var(--morph-d) var(--morph-e);
            }
            .tmp-header-area-start.is-compact .brand-mark { width: 30px; height: 30px; flex-basis: 30px; }
            /* font-size is deliberately NOT animated on either the name or the
               CTA: interpolating it re-lays-out and re-hints the glyphs every
               frame, which is what made the text look like it was crawling. */
            .tmp-header-area-start.is-compact .tmp-header-right { gap: 0; }
            .tmp-header-area-start .nav-cta {
                transition: background var(--morph-d) var(--morph-e),
                            border-color var(--morph-d) var(--morph-e),
                            color 240ms linear,
                            padding var(--morph-d) var(--morph-e),
                            gap var(--morph-d) var(--morph-e),
                            box-shadow .3s ease, transform .3s ease;
            }
            .tmp-header-area-start.is-compact .nav-cta {
                padding: 9px 16px; gap: 7px;
                background: var(--gold); color: #12100A !important;
                border-color: var(--gold);
            }
            .tmp-header-area-start.is-compact .nav-cta:hover {
                background: var(--gold-hi); border-color: var(--gold-hi);
                box-shadow: none; transform: none;
            }
        }
        @media (prefers-reduced-motion: reduce) {
            .tmp-header-area-start .header-content,
            .tmp-header-area-start .header-content > .tmp-mainmenu-nav,
            .tmp-header-area-start .tmp-mainmenu-nav,
            .tmp-header-area-start .brand-mark,
            .tmp-header-area-start .nav-cta,
            .tmp-header-area-start .brand-role { transition: none !important; }
        }

        /* ═══════════════════════════════════════════════════
           MOBILE NAVBAR — floating pill
           Below the desktop breakpoint the header renders as a pill
           that floats clear of the page. The desktop header markup is
           untouched; it is simply hidden here, and .mnav is hidden
           above the breakpoint.
           ═══════════════════════════════════════════════════ */
        .mnav, .mnav-panel { display: none; }

        @media (max-width: 1199px) {
            /* the pill replaces the bar, so the bar's chrome goes */
            .tmp-header-area-start.header--sticky {
                background: transparent !important;
                border: 0 !important;
                box-shadow: none !important;
                backdrop-filter: none !important;
                -webkit-backdrop-filter: none !important;
            }
            .tmp-header-area-start > .container { display: none !important; }

            .mnav {
                display: grid;
                /* equal 1fr sides: the name centres on the pill itself,
                   whatever the logo and button happen to measure */
                grid-template-columns: 1fr auto 1fr;
                align-items: center;
                gap: 10px;
                position: absolute;
                left: max(14px, env(safe-area-inset-left, 0px));
                right: max(14px, env(safe-area-inset-right, 0px));
                top: calc(11px + env(safe-area-inset-top, 0px));
                height: 58px;
                /* symmetric: with uneven padding the content box sits
                   off-centre and the name lands 1px out */
                padding: 0 11px;
                border-radius: 999px;
                border: 1px solid rgba(233,237,245,.10);
                /* opaque first: browsers without backdrop-filter keep a
                   solid charcoal pill rather than a transparent one */
                background: #15171A;
                box-shadow: 0 10px 30px rgba(0,0,0,.42);
            }
            @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
                .mnav { background: rgba(21,23,26,.78);
                        -webkit-backdrop-filter: blur(14px) saturate(140%);
                        backdrop-filter: blur(14px) saturate(140%); }
            }

            .mnav-brand { display: inline-flex; align-items: center; justify-self: start; }
            .mnav-brand img {
                width: 28px; height: 28px; object-fit: contain; display: block;
                /* same champagne chain the desktop brand uses */
                filter: brightness(0) saturate(100%) invert(74%) sepia(21%)
                        saturate(548%) hue-rotate(5deg) brightness(93%);
            }
            .mnav-name {
                justify-self: center;
                font-size: 15.5px; font-weight: 600; letter-spacing: -.01em;
                color: var(--ink); white-space: nowrap;
            }
            .mnav-btn {
                justify-self: end;
                width: 40px; height: 40px; padding: 0;
                display: inline-flex; align-items: center; justify-content: center;
                border-radius: 12px;
                border: 1px solid rgba(233,237,245,.12);
                background: rgba(233,237,245,.04);
                cursor: pointer;
                transition: border-color var(--t-tap) var(--ease), background var(--t-tap) var(--ease);
            }
            .mnav-btn:hover, .mnav-btn:focus-visible { border-color: var(--line-gold); }
            .mnav-btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
            .mnav-bars { display: block; width: 16px; height: 10px; position: relative; }
            .mnav-bars i {
                position: absolute; left: 0; width: 100%; height: 1.6px;
                border-radius: 2px; background: var(--ink);
                transition: transform var(--t-ui) var(--ease), opacity var(--t-tap) var(--ease);
            }
            .mnav-bars i:first-child { top: 1px; }
            .mnav-bars i:last-child  { bottom: 1px; }
            /* the two bars become a cross while the panel is open */
            .mnav-btn[aria-expanded="true"] .mnav-bars i:first-child { transform: translateY(3.2px) rotate(45deg); }
            .mnav-btn[aria-expanded="true"] .mnav-bars i:last-child  { transform: translateY(-3.2px) rotate(-45deg); }

            /* ── Panel ───────────────────────────────────── */
            .mnav-panel {
                display: block;
                position: absolute;
                left: max(14px, env(safe-area-inset-left, 0px));
                right: max(14px, env(safe-area-inset-right, 0px));
                top: calc(11px + env(safe-area-inset-top, 0px) + 58px + 8px);
                max-height: calc(100svh - (11px + env(safe-area-inset-top, 0px) + 58px + 8px) - 16px);
                overflow-y: auto;            /* every link stays reachable on a short screen */
                -webkit-overflow-scrolling: touch;
                padding: 8px;
                border-radius: 18px;
                border: 1px solid rgba(233,237,245,.10);
                background: #15171A;
                box-shadow: 0 18px 44px rgba(0,0,0,.5);
                opacity: 0; transform: translateY(-8px);
                transition: opacity 200ms var(--ease), transform 200ms var(--ease);
            }
            @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
                .mnav-panel { background: rgba(21,23,26,.92);
                              -webkit-backdrop-filter: blur(14px) saturate(140%);
                              backdrop-filter: blur(14px) saturate(140%); }
            }
            .mnav-panel[hidden] { display: none; }
            .mnav-panel.is-open { opacity: 1; transform: translateY(0); }

            .mnav-panel ul { list-style: none; margin: 0; padding: 0; }
            .mnav-panel li { margin: 0; }
            .mnav-panel li a {
                display: flex; align-items: center;
                min-height: 48px; padding: 0 12px;
                border-radius: 12px;
                font-size: 16px; color: var(--ink-2) !important; text-decoration: none;
                transition: color var(--t-tap) var(--ease), background var(--t-tap) var(--ease);
            }
            .mnav-panel li a:hover { color: var(--ink) !important; background: rgba(233,237,245,.04); }
            .mnav-panel li a:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
            /* the scrollspy marks the <li>, same as the desktop bar */
            .mnav-panel li.current a { color: var(--gold) !important; background: var(--gold-wash); }
            .mnav-social {
                display: flex; justify-content: center; gap: 6px;
                margin-top: 6px; padding-top: 8px;
                border-top: 1px solid rgba(233,237,245,.08);
            }
            .mnav-social a {
                display: grid; place-items: center;
                width: 44px; height: 44px; border-radius: 12px;
                color: var(--ink-3) !important; font-size: 15px;
                background: transparent !important;
                transition: color var(--t-tap) var(--ease);
            }
            .mnav-social a:hover, .mnav-social a:focus-visible { color: var(--gold) !important; }
            .mnav-social a:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
        }
        @media (prefers-reduced-motion: reduce) {
            .mnav-panel, .mnav-bars i { transition: none !important; }
        }

        /* ── Reduced motion ─────────────────────────────────
           Everything holds on the completed exchange: the phone is
           still, the conversation is fully written, nothing moves. */
        @media (prefers-reduced-motion: reduce) {
            .dev-rock, .ui-scroll, .ui-welcome, .ui-q, .ui-a, .ui-a span,
            .ui-dots, .ui-dots i, .ui-ph, .ui-type i, .ui-caret, .ui-send {
                animation: none !important;
            }
            .dev-rock { transform: none !important; }
            .ui-welcome, .ui-dots { display: none !important; }
            .ui-q, .ui-a { opacity: 1 !important; transform: none !important; }
            .ui-a span   { opacity: 1 !important; transform: none !important; }
            .ui-type i   { max-width: 0 !important; }
            .ui-caret    { display: none !important; }
            .ui-ph       { opacity: 1 !important; }
        }

        /* ── Mobile hero: ONE composition ───────────────────
           Replaces the two-panel attempt (a 100svh introduction panel
           and a separate phone showcase below it). That version put a
           screen's worth of empty space between the statistics and the
           phone and read as two unrelated screens.

           This is a single column in normal flow: label, headline,
           lede, the whole device, the actions, then the statistics. No
           min-height, no auto margins, no space-between, no spacers —
           every gap below is an explicit number.

           The two Bootstrap columns become `display: contents` so their
           children join one flex column and can be ordered; the phone
           therefore sits between the lede and the actions without being
           moved in the markup, which keeps the desktop grid intact. */
        @media (max-width: 991px) {
            .tmp-banner-one-area {
                padding-top: calc(var(--header-h) + 18px + env(safe-area-inset-top, 0px)) !important;
                padding-bottom: 0 !important;
            }
            .tmp-banner-one-area .hero-row {
                display: flex;
                flex-direction: column;
                /* The hero owns the first screen so About waits for a
                   scroll. The header is fixed, so the hero starts at
                   y=0 and clears the bar with its own padding-top —
                   that is the ONE place the header is counted, and the
                   same amount comes back off here so the row's bottom
                   edge lands on the fold rather than past it.

                   min-height, so a taller stack (short screen, enlarged
                   text) simply grows and scrolls. Nothing is clipped
                   and nothing is scaled down. */
                min-height: calc(100vh  - var(--header-h) - 18px);
                min-height: calc(100svh - var(--header-h) - 18px);
                /* Leftover height is split evenly across every step
                   instead of collecting as one hole at the bottom. The
                   zero-height tail gives the run after the statistics
                   an edge to space against, so they are not pinned to
                   the fold. */
                justify-content: space-between;
                /* The row carries Bootstrap's .align-items-center for the
                   desktop two-column layout. In a column flex that centres
                   on the HORIZONTAL axis, which shrink-wrapped and centred
                   the availability label. !important because that utility
                   class ships with one. */
                align-items: stretch !important;
                margin: 0;
                --bs-gutter-x: 0; --bs-gutter-y: 0; row-gap: 0;
            }
            .hero-col-text, .hero-content, .hero-col-media { display: contents; }
            .hero-intro { display: block; }

            /* One item, so space-between cannot open the label,
               headline and description apart from each other. */
            .hero-intro   { order: 1; }
            .hero-stage   { order: 2; }
            .hero-actions { order: 3; margin: 18px 0 0 !important; }
            .hero-facts   { order: 4; margin: 0 !important; }

            /* Fixed internal rhythm of the introduction. */
            .hero-eyebrow { margin: 0 0 18px !important; }
            .hero-title   { margin: 0 0 14px !important; }
            .hero-lede    { margin: 0 !important; }
            .tmp-banner-one-area .hero-row::after {
                content: ''; display: block; height: 0; order: 5;
            }

            /* ONE phone, scaled as one object.
               The device always lays out at its authored 392px, so the
               screen's internal coordinate system — header, bubbles,
               composer — is identical to desktop and never re-flows.
               The whole assembly is then scaled by a single transform,
               and the stage reserves the scaled box so the page below
               it sits correctly (a transform alone changes nothing in
               layout). --dev-scale is set in JS from the room the
               device actually has — width AND the height left on the
               first screen, between the two bounds below; changing it
               cannot restart or duplicate the animation, which lives on
               a descendant. */
            .hero-stage {
                /* width:100% so the stage measures the room available,
                   not its own 392px child — otherwise it sizes to the
                   device, reports no shortfall, and the phone silently
                   overflows behind the page's overflow-x guard. */
                width: 100%; min-width: 0;
                /* The two ends of the uniform scale. Between them the
                   phone is sized by the room actually LEFT on the first
                   screen once the headline, the buttons and the
                   statistics have taken theirs — measured in JS, not
                   guessed here, because how much the text costs depends
                   on how many lines the headline wraps to.

                   Width alone was the old rule, and on a real phone it
                   always hit the .80 ceiling: a 485px device in a fold
                   of about 660, which pushed the buttons past the
                   bottom edge. The ceiling now only applies where the
                   screen is tall enough to afford it.

                   The floor is the point below which the device stops
                   reading as the hero's subject. Under it the stack is
                   allowed to overflow and scroll instead — the same
                   choice the row's min-height already makes.

                   Its value is set from the real thing rather than from
                   the fold arithmetic, which cannot see Safari's
                   floating toolbar or the notch inset the hero pads for:
                   on an iPhone 16 it puts the rule above the statistics
                   a few px clear of the toolbar, so the line reads as
                   the edge of the first screen and the numbers are the
                   first thing a scroll reveals. */
                --dev-max-scale: .80;
                --dev-min-scale: .556;
            }
            .hero-device {
                /* Real layout width instead of a transform: the device
                   occupies the space it actually draws in, so the stage
                   needs no reserved height and — the point of the
                   change — the screen is minified ONCE, by its own
                   matrix3d, instead of being rasterised and then scaled
                   again by an ancestor. */
                width: calc(392px * var(--dev-scale, 1));
                max-width: none;
                margin: 0;
                flex: 0 0 auto;
                transform: none;
            }
            /* 11px clear of the glass; the 18px already sitting between
               the phone and the buttons becomes the gap below the line */
            .dev-cap { margin-top: calc(11px - var(--dev-dead-bottom)); }
            .dev-cap-label { font-size: 10px; letter-spacing: .1em; }
        }
        .tmp-banner-one-area .container { position: relative; z-index: 1; }

        /* ═══════════════════════════════════════════════════
           RESPONSIVE — mobile is the primary case
           ═══════════════════════════════════════════════════
           Most visitors arrive on a phone, so the phone layout is
           the one the base rules describe and the desktop
           composition is the enhancement layered on top.

           The header's height is a token (--header-h), read once by
           anything that has to clear it. Section rhythm is a token
           too, so the whole page tightens with one value. */

        /* below the desktop breakpoint --header-h is the floating pill's
   footprint (11px offset + 58px tall), counted once here so the
   hero padding and every scroll-margin-top clear it. */
        @media (max-width: 1199px) { :root { --header-h: 70px; --pad-section: 96px; --gutter: 26px; } }
        @media (max-width: 991px)  { :root { --header-h: 70px; --pad-section: 64px; --gutter: 22px; } }
        @media (max-width: 767px)  { :root { --header-h: 70px; --pad-section: 52px; --gutter: 20px; } }
        @media (max-width: 359px)  { :root { --pad-section: 44px; --gutter: 16px; } }

        .container {
            max-width: var(--container);
            /* max() so a notch in landscape widens the gutter but can
               never narrow it below the designed value */
            padding-left:  max(var(--gutter), env(safe-area-inset-left, 0px));
            padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
        }
        .tmp-section-gapTop    { padding-top: var(--pad-section) !important; }
        .tmp-section-gapBottom { padding-bottom: var(--pad-section) !important; }

        /* ── Hero, ≤991px ───────────────────────────────────
           Vertical rhythm is stated explicitly here rather than
           inherited from the desktop stack, so each step is a
           deliberate number: headline → 18px → lede → 24px →
           actions → 28px → stats → 28px → the project deck. */
        @media (max-width: 991px) {
            /* Bootstrap spaces stacked columns with --bs-gutter-y (3rem
               here), applied as a negative margin on the row and a
               matching positive one on each column — not as row-gap.
               Left alone it added 30px on top of the spacing set below,
               so the deck sat 58px under the statistics instead of 28. */
            .tmp-banner-one-area .hero-row { --bs-gutter-y: 0; row-gap: 0; margin-top: 0; }
            .tmp-banner-one-area .hero-row > [class*="col-"] { margin-top: 0; }
            /* Type only — every vertical gap lives in the layout block
               above, so the two cannot disagree. (They did: this block
               is later in the file, so its margins silently beat the
               layout's and the lede sat 26px from the phone, not 16.) */
            .hero-eyebrow  { font-size: 11.5px !important; }

            /* Two phrases, 32-36px on a typical phone and easing down on
               the narrow ones: 8.9vw is 32px at 360 and 36px at 405. */
            .hero-title    { font-size: clamp(29px, 8.9vw, 36px) !important;
                             font-weight: 600 !important;
                             line-height: 1.12 !important;
                             letter-spacing: -.022em !important; }
            .hero-title .rl.tl-wide   { display: none; }
            /* block, so a phrase too long for the width wraps naturally
               rather than being forced onto one line */
            .hero-title .rl.tl-narrow { display: block; }
            /* Solid colours, no gradient, glow or animated lettering —
               the entrance is a one-time reveal of the whole line. */
            .hero-title .rl.tl-gold > span {
                color: var(--gold);
                -webkit-text-fill-color: var(--gold);
            }

            .hero-lede--wide   { display: none; }
            .hero-lede--narrow { display: block; }
            .hero-lede     { font-size: 15px !important; line-height: 1.55 !important;
                             color: var(--ink-2) !important; max-width: none; }

            /* One dominant action and one quiet one. Two equally heavy
               pills made the stack bottom-heavy and neither read as the
               main thing to do. */
            .hero-actions { display: flex; flex-direction: column; align-items: stretch; gap: 4px; }
            .hero-actions .btn-primary {
                width: 100%; min-height: 52px; justify-content: center; font-size: 15.5px;
            }
            .hero-actions .btn-ghost {
                width: auto; align-self: center;
                min-height: 44px;            /* full touch target, no visible bulk */
                padding: 0 14px;
                background: transparent !important;
                border-color: transparent !important;
                color: var(--ink-2) !important;
                font-size: 15px;
                justify-content: center;
            }
            .hero-actions .btn-ghost .btn-arrow { opacity: .8; }

            /* Grid, centring and gaps are the base rule now; the phone
               only changes the sizes. Labels wrap to a second line
               rather than shrink or overflow. */
            .hero-facts dt { font-size: 21px; }
            .hero-facts dd { font-size: 9.5px; letter-spacing: .06em; line-height: 1.35; white-space: normal; }

            /* Headings drop their desktop line breaks — at this width a
               hard break lands in the wrong place — and wrap naturally
               instead, with the space between the halves intact. */
            .sec-title .ln { display: inline; }
            .sec-title br, .hero-lede br { display: none; }
            .sec-head { margin-bottom: 36px; }
            .sec-title { font-size: clamp(26px, 7.2vw, 34px) !important; line-height: 1.16 !important; }
            .sec-lede  { font-size: 15.5px !important; }
        }

        /* ── The project deck on mobile ─────────────────────
           Not the desktop fan shrunk down, and not a single frame
           either: one dominant screen with the other two peeking
           above and behind it.

        /* The mobile rules for the fanned project deck are gone with
           the deck itself — the hero media is one device now, and it
           carries its own responsive sizing above. */

        /* ── Sections on mobile ─────────────────────────────── */
        @media (max-width: 767px) {
            .ab-grid   { gap: 32px; }
            .ab-sign   { font-size: 26px; left: 16px; bottom: 11px; }
            .ab-para   { font-size: 15.5px !important; line-height: 1.75 !important; }
            .ab-facts  { gap: 16px 20px; margin-top: 26px; padding-top: 22px; }

            /* Centred on a phone only — the copy is a single column
               under the portrait here, so a centred axis reads as
               composed rather than as a stray indent. The desktop
               layout keeps its left edge, where the text sits beside
               the portrait and has a column to align to. */
            .ab-copy  { text-align: center; }
            /* max-width: 58ch would otherwise hold the block against
               the left edge however the text inside it is aligned */
            .ab-para  { margin-inline: auto !important; }
            .ab-facts { justify-items: center; }

            .cap       { padding: 22px 0; gap: 10px; }
            .cap-n     { padding-top: 0; font-size: 11px; }
            .cap-title { font-size: 18px !important; }
            .cap-desc  { font-size: 15px !important; }

            /* ── Toolkit, phone only ────────────────────────
               One elevated panel instead of five loose chip clouds.
               The categories are separated by a single hairline each —
               no card inside a card — and every technology is a text
               entry on a fixed icon column, so the two columns line up
               whether a label is "CSS" or "AI-assisted dev".
               Desktop keeps the original lists untouched. */
            .tk-grid {
                display: block;
                padding: 16px;
                background: var(--surface);
                border: 1px solid var(--line);
                border-radius: var(--r-lg);
            }
            .tk-group + .tk-group {
                margin-top: 16px;
                padding-top: 16px;
                border-top: 1px solid var(--line);
            }

            /* header: tinted gold square, platinum name, quiet count */
            .tk-name {
                display: grid;
                grid-template-columns: auto minmax(0, 1fr) auto;
                align-items: center;
                gap: 10px;
                margin: 0 0 11px !important;
                padding-bottom: 0;
                border-bottom: 0;
                font-family: 'Space Grotesk', sans-serif !important;
                font-size: 14px !important; font-weight: 600 !important;
                letter-spacing: 0; text-transform: none;
                color: var(--ink) !important;
            }
            .tk-ic {
                display: grid; place-items: center;
                width: 26px; height: 26px;
                border-radius: 7px;
                background: var(--gold-wash);
                color: var(--gold);
            }
            .tk-ic .tk-i { display: block; width: 14px; height: 14px; }
            .tk-ct {
                display: block;                  /* base rule hides it */
                font-family: 'JetBrains Mono', ui-monospace, monospace;
                font-size: 11px; font-weight: 400;
                color: var(--ink-3);
            }

            .tk-list {
                display: grid;
                grid-template-columns: repeat(2, minmax(0, 1fr));
                gap: 9px 12px;
            }
            .tk-list li {
                display: grid;
                grid-template-columns: 16px minmax(0, 1fr);
                align-items: start;
                gap: 8px;
                margin: 0;                       /* template puts 10px 0 on every li */
                padding: 0; border: 0; background: none; border-radius: 0;
                font-size: 13.5px; line-height: 1.35;
                color: var(--ink-2);
                white-space: normal;             /* long names wrap, never truncate */
            }
            /* One 16px column for both kinds of mark, so a brand glyph and
               a line icon start their label at the same x. */
            .tk-list .tk-i, .tk-list .tk-b {
                display: block;
                justify-self: center;
                color: var(--ink-3);
            }
            .tk-list .tk-i { width: 14px; height: 14px; margin-top: 2px; }
            .tk-list .tk-b { font-size: 13px; line-height: 18px; text-align: center; }

            .tl-row    { padding: 22px 0; }
            .tl-org    { font-size: 17.5px !important; }
            .tl-note   { font-size: 14px !important; }

            .tq        { padding: 20px; }
            /* 24px, not 18: on the tallest card the auto margin below has
               no slack to give, so this margin IS the whole gap between
               the quote and the rule. At 18px that card read as cramped
               next to the shorter ones. */
            .tq-text   { font-size: 15px; line-height: 1.7; margin-bottom: 24px; }

            /* style.css:17118 pins `section.clients-testimonial-area` to
               100px of bottom padding — the only section on the page with
               any. Every other one ends at 0 and lets the next section's
               top padding set the rhythm, so this one opened a gap 100px
               wider than the rest of the page. Matched at the same
               specificity so it simply loses. */
            section.clients-testimonial-area { padding-bottom: 0; }

            /* ── Subject chips: 2x2, not 3+1 ────────────────
               Four labels of unequal width in a wrapping flex row put
               three on the first line and left "Other" alone on the
               second between 400px and 479px — which is exactly the
               430px class of phone. A two-column grid is balanced at
               every phone width instead of only at the ones where the
               widths happen to fall right. */
            .ct-chips {
                display: grid;
                grid-template-columns: repeat(2, minmax(0, 1fr));
            }
            /* the label fills its cell, so when one chip wraps to two
               lines its neighbour grows with it instead of sitting short */
            .ct-chip { display: flex; }
            .ct-chip span {
                width: 100%;
                justify-content: center;
                text-align: center;
                /* the grid cell, not the text, now sets the width, so the
                   side padding only has to keep the label off the border */
                padding-inline: 10px;
                line-height: 1.25;
            }

            .pw-grid   { gap: 18px; }
            /* the feature/flip card variants no longer exist; the
               laptop card is one component at every size */
            .pw-media { padding: 16px 16px 15px; }
            .pw-body  { padding: 20px 18px 22px; }
            .pw-name   { font-size: 21px !important; }
            .pw-desc   { font-size: 14.5px; margin-bottom: 18px; }
            .pw-foot   { flex-wrap: wrap; gap: 10px; }
            /* 44px of touch target without 44px of visible bulk */
            .pw-go     { padding: 11px 0; }

            .ct-grid   { gap: 32px; }
            .ct-lines a, .ct-lines .ct-static { padding: 15px 0; }
        }

        @media (max-width: 479px) {
            .hero-facts dd { font-size: 9px; }
            .cap-tech li   { font-size: 10px; padding: 4px 8px; }
            .ct-lines a, .ct-lines .ct-static { flex-direction: column; gap: 4px; }
            .ct-k { flex: 0 0 auto; }
            .ct-row { grid-template-columns: minmax(0,1fr); }
        }

        /* ── Header at each width ───────────────────────────
           The bar's height is the --header-h token above; only its
           contents step down here. */
        @media (min-width: 1200px) and (max-width: 1399px) {
            .tmp-header-area-start .header-content { gap: 16px; }
            .tmp-header-area-start .tmp-mainmenu > li { margin: 0; }
            .tmp-header-area-start .tmp-header-right { gap: 12px; }
            .tmp-header-area-start .tmp-header-right .social-link a { width: 34px; height: 34px; }
        }
        @media (max-width: 575px) {
            .brand-mark { width: 32px; height: 32px; flex-basis: 32px; }
            .brand-name { font-size: 15px; line-height: 18px; }
            .brand-role { display: none; }
        }

        /* ── Touch ──────────────────────────────────────────
           Gated on the input device, not the viewport: a tablet at
           900px needs this and a small laptop window does not. */
        @media (pointer: coarse) {
            .tmp-mainmenu li a { padding: 12px 10px !important; }
            .social-link a, .site-footer .footer-social a { min-width: 44px; min-height: 44px; }
            .brand { min-height: 44px; }
            .hamberger-menu {
                display: grid !important; place-items: center !important;
                width: 44px !important; height: 44px !important;
                padding: 0 !important; background: transparent !important; border: 0 !important;
            }
            .tmp-popup-mobile-menu .close-button { width: 44px !important; height: 44px !important; }
            .ct-lines a { padding: 18px 0; }
            /* 16px minimum, or iOS zooms the page the moment a field
               takes focus and the layout is never the same again */
            .input-field { font-size: 16px !important; }
        }


        /* ═══════════════════════════════════════════════════
           HOVER — pointer devices only
           ═══════════════════════════════════════════════════
           A touch screen keeps :hover on whatever was tapped last, so
           a lift would read as "selected" long after the finger left. */
        @media (hover: hover) and (pointer: fine) {
            .brand:hover .brand-name { color: var(--ink); }
            .nav-cta:hover { background: var(--gold-hi); border-color: var(--gold-hi); color: var(--on-accent) !important; }
        }
