/* Webfort - Main Stylesheet */

/* Self-hosted fonts */
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(../fonts/outfit-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url(../fonts/outfit-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/space-mono-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/space-mono-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/space-mono-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/space-mono-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ─────────────────────────────────────────────
   Design tokens

   Colour roles live in tailwind.input.css @theme. Everything below is the
   scale hand-written CSS must draw from — the Tailwind utilities already sit
   on a clean scale, so the drift has always come from bespoke page CSS
   inventing its own radii, shadows and type sizes.

   Rule: no raw px for radius, shadow or font-size in this file or in a page's
   `pageStyles`. Reach for a token. If none fits, the design is wrong, not the
   scale.
   ───────────────────────────────────────────── */
:root {
    color-scheme: light;

    /* Elevation — three steps, never coloured. On a light ground depth comes
       from layered neutrals and hairlines; coloured glow reads as a smudge. */
    --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.05);
    --shadow-md: 0 1px 2px rgba(16, 24, 40, 0.05), 0 12px 24px -12px rgba(16, 24, 40, 0.10);
    --shadow-lg: 0 2px 4px rgba(16, 24, 40, 0.05), 0 24px 48px -20px rgba(16, 24, 40, 0.16);

    /* Radius — five steps, deliberately matching the Tailwind utilities
       already in the markup (rounded-lg/-xl/-2xl/-3xl/-full) so CSS and
       classes never disagree. */
    --r-sm: 8px;      /* chips, inputs, small badges */
    --r-md: 12px;     /* icon tiles, nested elements */
    --r-lg: 16px;     /* cards — the default */
    --r-xl: 24px;     /* large panels, feature blocks */
    --r-full: 9999px; /* pills, buttons, avatars */

    /* Type — content scale. 12px is the floor for anything a visitor reads. */
    --t-micro: 12px;
    --t-small: 14px;
    --t-body: 16px;
    --t-lead: 18px;

    /* Type — mockup scale. The control-panel, scan-report and server-rack
       set-pieces are miniature UI simulations, so they legitimately run
       tighter than content type. Confined to those components. */
    --t-mock-xs: 10px;
    --t-mock-sm: 11px;
    --t-mock-md: 12px;
    --t-mock-lg: 14px;

    --hairline: #e4e9f2;
    --ink: #0b1220;
    --ink-soft: #475569;
    --ink-muted: #5b6a7d;

    /* Brand blue carries every action: buttons, links, primary emphasis.
       White on it is 5.17:1. */
    --brand: #2563eb;

    /* The accent. A light tint of the brand rather than a separate hue — the
       neon lime it replaces was picked for the midnight theme, where it read
       as a glow against near-black; on white it read as foreign.

       Still area-capped: solid fills only on the headline swipe, status dots,
       uptime bars, and badges under ~40px tall. Never a button or panel.
       For tints and borders reach for brand-500 at low alpha — this value is
       already close to white and disappears below about 40% opacity. */
    --accent: #93c5fd;
    --accent-deep: #1e40af;

    /* Gold — the one warm note, and the only hue on the site that isn't blue.
       Its legibility flips between grounds, hence the pair: on navy the bright
       value is 8.0:1 and reads as text; on white it drops to 3.19:1, which
       clears the 3:1 bar for graphics but not the 4.5:1 for copy. So gold text
       on a light ground must use --gold-deep (5.05:1).

       Area-capped exactly like the accent: ratings, the "most popular" badge,
       the £1 promo emphasis, and the headline swipe on navy. Never a button
       fill on white, never a panel background, never past ~2% of a viewport.
       It only reads as premium while it stays scarce. */
    --gold: #f59e0b;
    --gold-deep: #b45309;

    /* Navy — the dark ground. Blue-leaning so it belongs to the brand family,
       but far enough from --brand that the two never read as the same colour. */
    --navy: #0b1a3a;
    --navy-raised: #12244a;
    --navy-sunken: #081530;

    /* Semantic colour. Anything outside these carries no meaning and should
       not appear on the site. */
    --positive: #009966;
    --negative: #d42f2f;
}

/* ── Dark surface context ──────────────────────────────────────────────
   The whole site sat between #ffffff and #eef2f9 — a luminance spread of
   about 6% across 21 pages, which is why it read as flat no matter how
   consistent it got. This class is the fix.

   Every semantic Tailwind utility compiles to a var() reference
   (.text-ink-muted{color:var(--color-ink-muted)}), so redefining those
   custom properties here re-points an entire subtree without touching a
   single class in the markup. The footer's 57 colour utilities need no
   edits at all.

   Contrast against --navy is noted per line; all clear AA. */
.on-dark {
    --color-surface: var(--navy);
    --color-surface-alt: var(--navy-raised);
    --color-surface-sunken: var(--navy-sunken);

    --color-ink: #ffffff;        /* 17.2:1 */
    --color-ink-soft: #c3d0e8;   /* 11.1:1 */
    --color-ink-muted: #93a4c4;  /*  6.8:1 */
    --color-ink-faint: rgba(255, 255, 255, 0.35);
    --color-hairline: rgba(255, 255, 255, 0.12);

    /* --accent-deep is a dark blue chosen to sit on white; on navy it drops to
       1.97:1. On a dark ground the "deep" and "light" ends of the accent swap
       roles, so it inverts to a pale tint (12.1:1). */
    --color-accent-deep: #bfdbfe;
    --accent-deep: #bfdbfe;

    /* --brand is remapped only for hand-written CSS that uses it as a text
       colour (.eyebrow--brand and friends). --color-brand-600 is deliberately
       NOT remapped: Tailwind uses it for both `text-brand-600` and
       `bg-brand-600`, and the two want opposite things here — link text needs
       to get lighter on navy, a button fill needs to stay the true brand or
       its white label falls to 2.3:1. Handled per-utility below instead. */
    --brand: #7dabf8;

    /* Mirror the plain aliases so hand-written CSS in this file inverts too. */
    --hairline: rgba(255, 255, 255, 0.12);
    --ink: #ffffff;
    --ink-soft: #c3d0e8;
    --ink-muted: #93a4c4;

    background-color: var(--navy);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.045'/%3E%3C/svg%3E");
    color: var(--color-ink-soft);
}

/* Focus rings need to be visible on navy too — the brand-blue ring is only
   3.3:1 there, which is below the 3:1-plus-margin a focus indicator wants. */
.on-dark :focus-visible {
    outline-color: var(--gold);
}

/* The primary CTA is brand-blue on white. On navy that fill is only 3.3:1
   against its own band, so the most important button on the page would read
   as the quietest thing in the section. Inverted to a white fill it becomes
   the brightest element on the site — which is what a final CTA should be.
   Gold is deliberately not used here; it stays scarce. */
.on-dark .cta-buy-btn {
    background: #ffffff;
    color: var(--navy);
}
.on-dark .cta-buy-btn-price {
    color: var(--navy);
    opacity: 0.72;
}
.on-dark .cta-buy-btn::before {
    background: linear-gradient(120deg, transparent 30%, rgba(11, 26, 58, 0.14) 50%, transparent 70%);
}
/* The promo-code chip is brand-900 on a blue tint — built for white, and
   1.66:1 on navy. */
.on-dark .cta-buy-meta strong {
    color: #ffffff;
    background: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 255, 255, 0.45);
}

/* Brand blue as *text* is 3.3:1 on navy — under AA for the footer's 21
   body-size links. Lifted per-utility rather than via the token, so
   `bg-brand-600` fills are left alone (see the note in .on-dark above). */
.on-dark .text-brand-600,
.on-dark .hover\:text-brand-600:hover,
.on-dark .group:hover .group-hover\:text-brand-600 {
    color: #7dabf8;   /* 7.4:1 */
}

/* Any solid brand-filled button inside a dark band inverts to white, for the
   same reason .cta-buy-btn does: a brand fill on navy is 3.3:1 against its own
   band, so the primary action would read as the quietest thing in the section. */
.on-dark .bg-brand-600 {
    background-color: #ffffff;
    color: var(--navy);
}
.on-dark .bg-brand-600 svg {
    color: var(--navy);
}

/* .rescue-check pills are hardcoded white with var(--ink) text — inside the
   dark band that resolved to white on white. They become raised navy cards. */
.on-dark .rescue-check {
    background: var(--navy-raised);
    border-color: rgba(255, 255, 255, 0.14);
    color: var(--color-ink);
    box-shadow: none;
}
.on-dark .rescue-check-ico {
    background: rgba(52, 211, 153, 0.16);
    color: #6ee7b7;   /* 8.9:1 on navy — the emerald tick needs lifting too */
}

/* The eyebrow's 8%-brand tint is invisible on navy; give it a white tint so
   the pill still reads as a pill. */
.on-dark .eyebrow--brand,
.on-dark .eyebrow--neutral {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.22);
    color: var(--color-ink-soft);
}

/* ── Light island inside a dark band ───────────────────────────────────
   .on-dark cascades to everything beneath it, including surfaces that are
   deliberately light — the scan-report mockup in rescue-cta.njk is a
   hardcoded white "browser window", and it inherited the dark band's pale
   ink, leaving 2.4:1 grey on white.

   A mockup of a light UI has to stay a mockup of a light UI, so this restores
   the root values for that subtree. Anything painting an explicitly light
   surface inside a dark band needs this class. */
.on-light {
    --color-ink: #0b1220;
    --color-ink-soft: #475569;
    --color-ink-muted: #5b6a7d;
    --color-ink-faint: #94a3b8;
    --color-hairline: #e4e9f2;
    --color-brand-600: #2563eb;
    --color-brand-500: #3b82f6;
    --color-accent-deep: #1e40af;

    --hairline: #e4e9f2;
    --ink: #0b1220;
    --ink-soft: #475569;
    --ink-muted: #5b6a7d;
    --brand: #2563eb;
    --accent-deep: #1e40af;
}

/* ── Band seam ─────────────────────────────────────────────────────────
   A hard edge between a white section and the navy band reads as two pages
   stitched together. This fades the preceding surface down into the navy over
   the first 96px so the transition is deliberate. */
.band-seam::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 96px;
    pointer-events: none;
    background: linear-gradient(180deg, rgba(246, 248, 252, 0.10), transparent);
}
/* When a dark band follows another dark band there is no seam to soften —
   drawing one puts a visible ledge in the middle of what should read as a
   single dark surface. The homepage closes with rescue → final CTA → footer,
   and those three want to be one block, not three stacked panels. */
.on-dark + .on-dark::after,
.on-dark + .on-dark > .band-seam::after {
    background: none;
}

/* ── Surface grid ──────────────────────────────────────────────────────
   A 24px dot lattice, masked so it fades out before it reaches an edge.
   Drawn in var(--color-hairline), so inside .on-dark it inverts to white
   dots for free — one class, correct on both grounds.

   This is what replaces the blurred blobs as the page's depth cue: it gives
   a flat fill something to be flat *against*, at a scale you feel rather
   than notice. */
.surface-grid::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: radial-gradient(var(--color-hairline) 1px, transparent 1px);
    background-size: 24px 24px;
    -webkit-mask-image: radial-gradient(ellipse 75% 60% at 50% 0%, #000 25%, transparent 78%);
    mask-image: radial-gradient(ellipse 75% 60% at 50% 0%, #000 25%, transparent 78%);
}
/* Keep content above the lattice. */
.surface-grid > * {
    position: relative;
    z-index: 1;
}
.on-dark.surface-grid::before {
    /* Slightly stronger on navy — white dots at 12% read fainter than dark
       dots at 12% do on white. */
    background-image: radial-gradient(rgba(255, 255, 255, 0.16) 1px, transparent 1px);
}

/* Grain is applied to .on-dark directly rather than as its own class: an
   element only has two pseudo-elements and the seam and the dot grid have
   already claimed both. Painting it as a background layer over the navy
   fill avoids the collision entirely, and means every dark surface gets it
   without having to remember a second class.

   The opacity is baked into the SVG rect, so it composites at the right
   strength without an element-level opacity that would drag the seam down
   with it. Flat navy across a full viewport reads as moulded plastic; a few
   percent of fractal noise is the whole difference between a dark section
   and an expensive one. */

/* ── Headline emphasis on navy ─────────────────────────────────────────
   The highlighter swipe does not survive the move to a dark ground. It works
   on white because dark ink stays legible everywhere and the swipe merely
   tints the lower third. On navy neither option holds: white text over the
   pale-blue swipe is 3.5:1, and dark text would vanish across the 60% of each
   letter the swipe doesn't cover. Filling the whole word instead would fix the
   contrast but hand a display-size phrase a saturated fill — the exact mistake
   the lime accent was retired for.

   So on navy the swipe collapses to a rule underneath. The word keeps white at
   17.2:1, gold reads unmistakably at a fraction of the area, and the gesture
   still marks the phrase. */
.hl-gold,
.on-dark .hl-accent {
    position: relative;
    display: inline-block;
    isolation: isolate;
    color: #ffffff;
    padding: 0 0 0.08em;
}
.hl-gold::before,
.on-dark .hl-accent::before {
    content: '';
    position: absolute;
    z-index: -1;
    left: 0;
    right: 0;
    bottom: 0;
    height: 0.09em;
    min-height: 3px;
    background: var(--gold);
    border-radius: var(--r-full);
    transform: none;
}

/* ── Icon tile ─────────────────────────────────────────────────────────
   Provides only the surface — the size and radius stay as utilities in the
   markup, so this drops in wherever a flat bg-surface-sunken / bg-surface-alt
   tile was without changing the layout.

   The flat neutral fill was the single flattest thing on the page: at 190
   tiles a site-wide, it set the texture of every feature grid. A 160deg
   gradient plus a top inner highlight gives each one a light direction, so
   they read as objects catching light from the same source rather than
   painted rectangles. Built from tokens, so it inverts inside .on-dark. */
.icon-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background:
        linear-gradient(160deg, var(--color-surface) 0%, var(--color-surface-sunken) 100%);
    border: 1px solid var(--hairline);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.85),
        var(--shadow-sm);
    color: var(--brand);
}
.on-dark .icon-tile {
    background: linear-gradient(160deg, rgba(255, 255, 255, 0.09) 0%, rgba(255, 255, 255, 0.02) 100%);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}

/* Mono kicker above an editorial section heading. Deliberately quiet — it is
   a wayfinding mark, not a second heading. */
.section-kicker {
    display: block;
    margin-bottom: 0.75rem;
    font-family: 'Space Mono', ui-monospace, monospace;
    font-size: var(--t-micro);
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    /* Not --ink-faint: that is 2.56:1 on white, which is fine for a rule or a
       divider but this is 12px text a person reads. */
    color: var(--ink-muted);
}
.section-kicker::after {
    content: '';
    display: inline-block;
    width: 2rem;
    height: 1px;
    margin-left: 0.75rem;
    vertical-align: middle;
    background: var(--hairline);
}

/* Keyboard focus — one consistent ring across the site */
:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

/* ── Page ground ───────────────────────────────────────────────────────
   A still, asymmetric wash rather than the three animated blurred blobs this
   used to carry. Drifting background decoration reads as restless; a fixed
   ground lets the type and cards be the only thing moving. Weighted warm at
   the top-left and cool at the bottom-right so the page has a direction. */
.gradient-bg {
    /* The wash lives on the element so the lattice in ::before can be masked
       independently of it. */
    background:
        radial-gradient(ellipse 70% 55% at 12% 8%,  rgba(37, 99, 235, 0.10) 0%, transparent 60%),
        radial-gradient(ellipse 80% 60% at 88% 78%, rgba(37, 99, 235, 0.09) 0%, transparent 62%),
        linear-gradient(180deg, #ffffff 0%, #f4f8ff 100%);
    position: relative;
    overflow: hidden;
}
.gradient-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    /* The dot lattice is what carries the hero's depth now that the blurred
       blobs are gone. A soft blue wash on white has almost no value difference
       to register, so it read as nothing; a structure at a fixed 24px pitch
       reads as a made surface even at 7% alpha. Masked so it never reaches an
       edge and turns into a visible rectangle. */
    background-image: radial-gradient(rgba(11, 18, 32, 0.07) 1px, transparent 1px);
    background-size: 24px 24px;
    -webkit-mask-image: radial-gradient(ellipse 85% 75% at 50% 25%, #000 30%, transparent 82%);
    mask-image: radial-gradient(ellipse 85% 75% at 50% 25%, #000 30%, transparent 82%);
}

/* ── Card ──────────────────────────────────────────────────────────────
   One surface for the whole site. This existed as 71 near-identical classes
   across 14 pages — .spec-card, .step-card, .persona-card, .feature-card,
   .pricing-card-{hosting,reseller,premium,wp} — every one of them painting
   the same white fill, hairline border and lift-on-hover, differing only in
   transition duration and how far they moved.

   The motion is deliberately short and small: 180ms ease-out and 2px. The
   old 400-500ms cubic-bezier at 5-8px reads as bouncy; restraint reads as
   engineered.

   Modifiers:
     .card--static   no hover response, for cards that aren't interactive
     .featured       inverted brand-blue tier (see the inverted block below) */
.card,
.glass-card {
    background: var(--color-surface);
    border: 1px solid var(--hairline);
    box-shadow: var(--shadow-md);
    transition: transform 0.18s ease-out,
                box-shadow 0.18s ease-out,
                border-color 0.18s ease-out;
}
.card:hover,
.glass-card:hover {
    border-color: #c7d7f5;
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}
.card--static:hover {
    transform: none;
    box-shadow: var(--shadow-md);
    border-color: var(--hairline);
}
@media (prefers-reduced-motion: reduce) {
    .card, .glass-card { transition: border-color 0.18s ease-out; }
    .card:hover, .glass-card:hover { transform: none; }
}

/* Marquee */
.marquee-track {
    display: flex;
    animation: marquee 30s linear infinite;
}
@keyframes marquee {
    0% { transform: translateX(0); }
    100% { transform: translateX(-50%); }
}

/* Logo Marquee */
.logo-marquee-track {
    display: flex;
    align-items: center;
    animation: logo-marquee 40s linear infinite;
}
@keyframes logo-marquee {
    0% { transform: translateX(0); }
    100% { transform: translateX(-25%); }
}
.logo-marquee-item {
    opacity: 0.55;
    transition: opacity 0.3s ease;
}
.logo-marquee-item:hover {
    opacity: 1;
}
/* Partner marks ship as single-colour white SVGs in <img> tags, so
   currentColor can't reach them — flatten to ink instead. */
.logo-marquee-item img {
    filter: brightness(0);
}

/* Bento grid */
.bento-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: repeat(3, minmax(180px, auto));
    gap: 20px;
}
.bento-item-1 { grid-column: span 2; grid-row: span 2; }
.bento-item-2 { grid-column: span 2; }
.bento-item-3 { grid-column: span 1; }
.bento-item-4 { grid-column: span 1; }
.bento-item-5 { grid-column: span 2; }
.bento-item-6 { grid-column: span 2; }

@media (max-width: 1024px) {
    .bento-grid {
        grid-template-columns: repeat(2, 1fr);
        grid-template-rows: auto;
    }
    .bento-item-1, .bento-item-2, .bento-item-5, .bento-item-6 { grid-column: span 2; }
    .bento-item-3, .bento-item-4 { grid-column: span 1; }
    .bento-item-1 { grid-row: span 1; }
}
@media (max-width: 640px) {
    .bento-grid { grid-template-columns: 1fr; }
    .bento-item-1, .bento-item-2, .bento-item-3, .bento-item-4, .bento-item-5, .bento-item-6 { grid-column: span 1; }
}

/* 3D tilt effect */
.tilt-card {
    transform-style: preserve-3d;
    transition: transform 0.5s ease;
}
.tilt-card:hover {
    transform: perspective(1000px) rotateX(5deg) rotateY(-5deg);
}

/* Magnetic button */
.magnetic-btn {
    transition: transform 0.3s ease;
    cursor: pointer;
}

/* Animated border */
.animated-border {
    position: relative;
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.2), rgba(37, 99, 235, 0.1));
}
.animated-border::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 2px;
    background: linear-gradient(135deg, #2563eb, var(--accent), #60a5fa, #2563eb);
    background-size: 300% 300%;
    animation: borderRotate 4s linear infinite;
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
}
@keyframes borderRotate {
    0% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

/* ── Plan card ─────────────────────────────────────────────────────────
   The pricing tier. Every product page had its own copy of this — 43 lines
   each in .pricing-card-hosting, -premium, -reseller and -wp, identical apart
   from the class name. One definition; pages use .pricing-card. */
.pricing-card {
    position: relative;
    background: var(--color-surface);
    border: 1px solid var(--hairline);
    transition: transform 0.18s ease-out,
                box-shadow 0.18s ease-out,
                border-color 0.18s ease-out;
}
.pricing-card:hover {
    transform: translateY(-4px);
    border-color: #c7d7f5;
    box-shadow: var(--shadow-lg);
}
/* A hairline accent that traces the border on hover. This is lime doing what
   lime is good at: one pixel wide, so no area, all signal. */
.pricing-card::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(135deg, transparent, rgba(37, 99, 235, 0.30), transparent);
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.18s ease-out;
    pointer-events: none;
}
.pricing-card:hover::before { opacity: 1; }

.pricing-card.featured {
    background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
    /* A lit top-left edge fading to nothing at the bottom-right. Nothing else
       on the page has an edge that changes along its length, so the featured
       plan reads as the more expensive object without needing a second hue or
       a heavier shadow. */
    border-color: transparent;
    /* The blue also stays on background-color. The gradient border needs the
       fill to live in background-image, which leaves background-color
       transparent — and a transparent card with white text on it is invisible
       if the image layer ever fails to paint. */
    background-color: #2563eb;
    background-image:
        linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%),
        linear-gradient(135deg, rgba(191, 219, 254, 0.85) 0%, rgba(191, 219, 254, 0.10) 45%, rgba(30, 64, 175, 0) 75%);
    background-origin: border-box;
    background-clip: padding-box, border-box;
    box-shadow: var(--shadow-lg);
    /* Everything inside sits on blue — inherited text (plan name, the price
       macro's span) must not fall back to the page's ink colour. */
    color: #ffffff;
}
/* No scale below md: the cards are stacked full-width there, so scaling up
   pushes the card past the viewport edge. */
@media (min-width: 768px) {
    .pricing-card.featured { transform: scale(1.05); }
    .pricing-card.featured:hover { transform: scale(1.05) translateY(-4px); }
}
@media (prefers-reduced-motion: reduce) {
    .pricing-card:hover { transform: none; }
    .pricing-card.featured:hover { transform: scale(1.05); }
}

/* Expandable pricing features - smooth grid animation */
.expanded-features-wrapper {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.pricing-cards-expanded .expanded-features-wrapper {
    grid-template-rows: 1fr;
}
.expanded-features {
    overflow: hidden;
    opacity: 0;
    transform: translateY(-10px);
    transition: opacity 0.4s ease 0.1s, transform 0.4s ease 0.1s;
}
.pricing-cards-expanded .expanded-features {
    opacity: 1;
    transform: translateY(0);
}
.expanded-features-inner {
    padding-top: 16px;
    margin-top: 16px;
    border-top: 1px solid var(--hairline);
}
/* ── Inverted surface ──────────────────────────────────────────────────
   The featured tier is the one dark surface on a light page, so every ink,
   border and fill utility inside it has to flip. `.featured` appears only on
   pricing cards, and every page's variant (.pricing-card, -hosting, -reseller,
   -premium, -wp, .plan-card) renders the same solid brand card — so one block
   keyed on `.featured` covers all six. Chained with .featured for the extra
   specificity needed to beat the single-class Tailwind utilities. */
.featured.featured { color: #ffffff; }
.featured.featured .text-ink        { color: #ffffff; }
.featured.featured .text-ink-soft   { color: rgba(255, 255, 255, 0.80); }
.featured.featured .text-ink-muted  { color: rgba(255, 255, 255, 0.70); }
.featured.featured .text-ink-faint  { color: rgba(255, 255, 255, 0.55); }
.featured.featured .border-hairline { border-color: rgba(255, 255, 255, 0.22); }
.featured.featured .bg-surface-alt,
.featured.featured .bg-surface-sunken { background-color: rgba(255, 255, 255, 0.12); }
.featured.featured .expanded-features-inner { border-top-color: rgba(255, 255, 255, 0.25); }

/* Accents that read as emphasis on white are invisible on brand blue. The
   accent is itself a blue now, so it cannot do this job: #93c5fd on the card
   is only 2.9:1. Text goes white (5.2:1); the ticks take a pale blue, which
   clears the 3:1 bar that applies to graphics and keeps them distinct from
   the copy. */
.featured.featured .text-brand-600 { color: #ffffff; }
.featured.featured .text-emerald-600 { color: #bfdbfe; }

/* A blue button vanishes into a blue card. Invert it: white fill, brand text —
   the strongest CTA available on a coloured surface. */
.featured.featured .bg-brand-600 {
    background-color: #ffffff;
    color: var(--brand);
}
.featured.featured .bg-brand-600:hover { background-color: #eef4ff; }

.expand-toggle {
    transition: all 0.18s ease-out;
}
.expand-toggle svg {
    transition: transform 0.3s ease;
}
.pricing-cards-expanded .expand-toggle svg {
    transform: rotate(180deg);
}

/* Live chat bubble */
.chat-bubble {
    animation: chatPulse 2s ease-in-out infinite;
}
@keyframes chatPulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.05); }
}

/* Domain pill animation */
.domain-pill {
    transition: all 0.18s ease-out;
}
.domain-pill:hover {
    transform: scale(1.1) rotate(-2deg);
    box-shadow: var(--shadow-lg);
}

/* Floating animation */
.float {
    animation: float 6s ease-in-out infinite;
}
.float-delay-1 { animation-delay: -2s; }
.float-delay-2 { animation-delay: -4s; }
@keyframes float {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-20px); }
}

/* Pulse ring */
.pulse-ring {
    animation: pulseRing 2s ease-out infinite;
}
@keyframes pulseRing {
    0% { transform: scale(1); opacity: 1; }
    100% { transform: scale(1.5); opacity: 0; }
}

/* Network map (contact page location visual).
   London sits at the hub; traffic runs out along the arcs to each region.
   The flow is a single short dash chased along the full path length, so the
   dasharray and the dashoffset it animates to must stay in step: 6 + 134 = 140
   is one dash per cycle, and -140 walks it exactly one cycle along. */
.netmap-arc {
    fill: none;
    stroke: rgba(37, 99, 235, 0.35);
    stroke-width: 1.5;
}
.netmap-flow {
    fill: none;
    stroke: var(--color-brand-600, #2563eb);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-dasharray: 6 134;
    animation: netmapFlow 3s linear infinite;
}
@keyframes netmapFlow {
    to { stroke-dashoffset: -140; }
}
.netmap-hub-ring {
    fill: none;
    stroke: var(--color-brand-600, #2563eb);
    stroke-width: 1.5;
    animation: netmapHub 3s ease-out infinite;
}
@keyframes netmapHub {
    0%   { r: 10; opacity: 0.55; }
    100% { r: 34; opacity: 0; }
}
.netmap-label {
    font-family: 'Space Mono', ui-monospace, monospace;
    font-size: 9px;
    letter-spacing: 0.12em;
    fill: var(--color-ink-soft, #475569);
}
.netmap-label--hub {
    fill: var(--color-ink, #0b1220);
    font-weight: 700;
}
.netmap-label--muted {
    font-size: 8px;
    fill: var(--color-ink-faint, #94a3b8);
}
/* Full-size label, dimmed — the region that isn't live yet. */
.netmap-label--pending {
    fill: var(--color-ink-faint, #94a3b8);
}
/* The 570-unit viewBox scales to roughly 0.6 in a single-column card, which
   would take these labels down to ~5px. Sizes are in user units, so they scale
   with the drawing — scale them back up to land near 9px again. */
@media (max-width: 639px) {
    .netmap-label { font-size: 15px; }
    .netmap-label--muted { font-size: 13px; }
}
/* Without motion the dash pattern would freeze mid-path and read as a broken
   line, so the flow reverts to a plain solid arc. */
@media (prefers-reduced-motion: reduce) {
    .netmap-flow {
        animation: none;
        stroke-dasharray: none;
        stroke-width: 1.5;
    }
    .netmap-hub-ring { animation: none; opacity: 0.3; r: 22; }
}

/* Promo banner */
.promo-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 45;
    background: linear-gradient(90deg, #e6f0fe 0%, #f5f9ff 50%, #e6f0fe 100%);
    border-bottom: 1px solid #bfdbfe;
    overflow: hidden;
}
.promo-banner ~ nav {
    top: 2.25rem; /* 36px — matches .h-9 banner height */
}
body:has(> .promo-banner) {
    padding-top: 2.25rem; /* push static content down below the fixed banner */
}
.promo-banner::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.85) 50%, transparent 100%);
    transform: translateX(-100%);
    animation: promoShimmer 7s ease-in-out infinite;
    pointer-events: none;
}
@keyframes promoShimmer {
    0%, 15% { transform: translateX(-100%); }
    55%, 100% { transform: translateX(100%); }
}
.promo-banner-inner {
    position: relative;
    z-index: 1;
}
.promo-code {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.18rem 0.55rem;
    background: var(--accent);
    border: 1px solid #60a5fa;
    border-radius: var(--r-sm);
    font-family: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    font-weight: 700;
    color: #1e3a8a;
    cursor: pointer;
    transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease, transform 0.15s ease;
    letter-spacing: 0.06em;
    line-height: 1;
}
.promo-code:hover {
    background: #d6ff3d;
    border-color: #9dcc00;
    transform: translateY(-1px);
}
.promo-code.copied {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--accent);
}
.promo-code-label {
    font-size: var(--t-micro);
}
.promo-code-icon {
    opacity: 0.65;
}
@media (prefers-reduced-motion: reduce) {
    .promo-banner::before { animation: none; }
}

/* Text gradient animation */
/* Headline gradient. Was a four-stop ramp through sky and indigo on a 5s
   infinite loop — off-palette, and a headline that never stops moving is the
   loudest thing on the page. Now a still two-stop fall within the brand
   scale, so it reads as depth rather than as an effect. */
.animated-gradient-text {
    background: linear-gradient(100deg, var(--brand) 0%, #1e40af 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

/* Rotating headline words — JS driven */
.hero-rotating-wrapper {
    display: inline-block;
    position: relative;
    vertical-align: bottom;
    perspective: 600px;
}
/* Ink word over a lime marker swipe — keeps the brand accent at full
   saturation while the headline itself stays fully legible on white.
   .hl-accent is the same treatment for any static headline accent. */
.hero-word,
.hl-accent {
    position: relative;
    display: inline-block;
    /* own stacking context so the swipe sits behind the word, not behind
       the section background */
    isolation: isolate;
    color: var(--ink);
    padding: 0 0.1em 0.1em;
}
.hero-word {
    transition-duration: 0.35s;
    transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.hero-word::before,
.hl-accent::before {
    content: '';
    position: absolute;
    z-index: -1;
    left: 0;
    right: 0;
    bottom: 0.14em;
    height: 0.4em;
    background: var(--accent);
    border-radius: 0.06em;
    transform: skewX(-4deg);
}

/* Clip — enter from bottom wipe, exit top wipe */
.anim-clip .hero-word { transition-property: clip-path; clip-path: inset(0 0 0 0); }
.anim-clip .hero-word.out { clip-path: inset(0 0 100% 0); }
.anim-clip .hero-word.in { clip-path: inset(100% 0 0 0); }

/* Pop — scale bounce in/out */
.anim-pop .hero-word { transition-property: transform, opacity; transform: scale(1); opacity: 1; }
.anim-pop .hero-word.out { transform: scale(0.6); opacity: 0; }
.anim-pop .hero-word.in { transform: scale(1.3); opacity: 0; }

/* Flip — 3D rotation */
.anim-flip .hero-word { transition-property: transform, opacity; transform: rotateX(0deg); opacity: 1; transform-origin: center bottom; }
.anim-flip .hero-word.out { transform: rotateX(-90deg); opacity: 0; }
.anim-flip .hero-word.in { transform: rotateX(90deg); opacity: 0; }

/* Drop — fall from above, exit below */
.anim-drop .hero-word { transition-property: transform, opacity; transform: translateY(0); opacity: 1; }
.anim-drop .hero-word.out { transform: translateY(80%); opacity: 0; }
.anim-drop .hero-word.in { transform: translateY(-80%); opacity: 0; }

/* Social proof avatars */

/* Counter animation */
.counter {
    font-variant-numeric: tabular-nums;
}

/* Scroll indicator */
.scroll-indicator {
    animation: scrollBounce 2s ease-in-out infinite;
}
@keyframes scrollBounce {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(10px); }
}

/* Split text animation */
.split-text span {
    display: inline-block;
    opacity: 0;
    transform: translateY(100%);
    animation: splitReveal 0.8s ease forwards;
}
.split-text.active span {
    opacity: 1;
    transform: translateY(0);
}

/* Nav bar shell — translucent white so content reads under it while scrolling */
nav > div > .glass-card {
    background: rgba(255, 255, 255, 0.82);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: var(--shadow-sm);
}
nav > div > .glass-card:hover {
    transform: none;
    border-color: var(--hairline);
    box-shadow: var(--shadow-sm);
}

/* Navigation links */
.nav-link {
    position: relative;
    padding: 10px 20px;
    font-size: var(--t-small);
    font-weight: 700;
    color: var(--ink);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    transition: all 0.18s ease-out;
    border-radius: var(--r-md);
}
.nav-link::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.08), rgba(37, 99, 235, 0.22));
    border-radius: var(--r-md);
    opacity: 0;
    transform: scale(0.8);
    transition: all 0.18s ease-out;
}
.nav-link:hover {
    color: var(--brand);
    transform: translateY(-2px);
}
.nav-link:hover::before {
    opacity: 1;
    transform: scale(1);
}
/* "Switch to Webfort" — the one nav item that keeps the lime, as a chip */
.nav-link.text-accent {
    color: var(--ink);
    background: var(--accent);
}
.nav-link.text-accent:hover {
    color: var(--ink);
    background: #d6ff3d;
}
.nav-link.text-accent::before {
    display: none;
}

/* Dropdown */
.nav-dropdown {
    position: relative;
}
.nav-dropdown-trigger {
    display: flex;
    align-items: center;
    gap: 8px;
}
.nav-dropdown-trigger svg {
    transition: transform 0.3s ease;
}
.nav-dropdown:hover .nav-dropdown-trigger svg {
    transform: rotate(180deg);
}
.nav-dropdown:hover .nav-link {
    color: var(--brand);
}
.nav-dropdown-menu {
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%) translateY(10px);
    min-width: 240px;
    padding: 12px;
    background: #ffffff;
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    opacity: 0;
    visibility: hidden;
    transition: all 0.18s ease-out;
    box-shadow: var(--shadow-lg);
}
.nav-dropdown:hover .nav-dropdown-menu {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}
.nav-dropdown-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 18px;
    color: var(--ink);
    font-size: var(--t-small);
    font-weight: 600;
    border-radius: var(--r-md);
    transition: all 0.2s ease;
    white-space: nowrap;
}
.nav-dropdown-item:hover {
    background: #f4f7fd;
    color: var(--brand);
    transform: translateX(4px);
}
.nav-dropdown-item svg {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    padding: 8px;
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.10), rgba(37, 99, 235, 0.22));
    border-radius: var(--r-md);
    transition: all 0.2s ease;
}
.nav-dropdown-item:hover svg {
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.18), rgba(37, 99, 235, 0.45));
    transform: scale(1.1);
}

/* Mobile menu */
.mobile-menu {
    transform: translateX(100%);
    transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.mobile-menu.active {
    transform: translateX(0);
}

/* Glow button */
.glow-btn {
    position: relative;
    overflow: hidden;
}
.glow-btn::before {
    content: '';
    position: absolute;
    top: 0;
    left: -100%;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
    transition: left 0.5s;
}
.glow-btn:hover::before {
    left: 100%;
}

/* Scrollbar styling */
html {
    scrollbar-width: thin;
    scrollbar-color: #cbd5e1 #f1f5f9;
}
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: #f1f5f9; }
::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: var(--r-sm); }
::-webkit-scrollbar-thumb:hover { background: #94a3b8; }

/* Currency Switcher */
.currency-switcher {
    display: inline-flex;
    align-items: center;
    background: #f1f5f9;
    border: 1px solid var(--hairline);
    border-radius: var(--r-full);
    padding: 3px;
}
.currency-switcher .cs-btn {
    width: 32px;
    height: 32px;
    border-radius: var(--r-full);
    font-size: var(--t-small);
    font-weight: 700;
    color: var(--ink-muted);
    background: transparent;
    border: none;
    cursor: pointer;
    transition: all 0.2s ease;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.currency-switcher .cs-btn:hover {
    color: var(--ink);
}
html[data-currency="gbp"] .currency-switcher .cs-btn[data-cur="gbp"],
html[data-currency="usd"] .currency-switcher .cs-btn[data-cur="usd"],
html[data-currency="eur"] .currency-switcher .cs-btn[data-cur="eur"] {
    background: var(--ink);
    color: #ffffff;
}

/* ─────────────────────────────────────────────
   £1 Primary CTA — used in hero, final, sticky
   ───────────────────────────────────────────── */
.cta-buy {
    display: inline-flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.625rem;
    width: 100%;
    max-width: 26rem;
}
.cta-buy-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 1.125rem 2.25rem;
    background: var(--brand);
    color: #ffffff;
    border-radius: var(--r-full);
    font-weight: 900;
    font-size: var(--t-lead);
    line-height: 1;
    letter-spacing: -0.01em;
    box-shadow: var(--shadow-sm);
    transition: transform 0.18s ease, box-shadow 0.25s ease;
    overflow: hidden;
    isolation: isolate;
}
.cta-buy-btn::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(120deg, transparent 30%, rgba(255,255,255,0.55) 50%, transparent 70%);
    transform: translateX(-120%);
    transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}
.cta-buy-btn:hover {
    transform: translateY(-2px) scale(1.02);
    box-shadow: var(--shadow-sm);
}
.cta-buy-btn:hover::before {
    transform: translateX(120%);
}
.cta-buy-btn-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.05;
}
.cta-buy-btn-headline {
    font-size: var(--t-lead);
    letter-spacing: 0.005em;
}
.cta-buy-btn-price {
    font-family: 'Space Mono', ui-monospace, monospace;
    font-size: var(--t-micro);
    font-weight: 700;
    /* Dark ink here was correct when the button was lime. On brand blue it
       dropped to 3.65:1 — under AA for 12px text. Full white is 5.17:1; the
       hierarchy against the headline comes from size and the mono face, which
       is the right lever anyway. Dimming this to get separation is what put it
       under the threshold in the first place. */
    color: #ffffff;
    margin-top: 0.2rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.cta-buy-arrow {
    width: 1.25rem;
    height: 1.25rem;
    transition: transform 0.25s ease;
}
.cta-buy-btn:hover .cta-buy-arrow {
    transform: translateX(0.25rem);
}
.cta-buy-meta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-size: var(--t-micro);
    color: var(--ink-muted);
    text-align: center;
    line-height: 1.4;
    flex-wrap: wrap;
}
.cta-buy-meta strong {
    color: #1e3a8a;
    font-weight: 700;
    font-family: 'Space Mono', ui-monospace, monospace;
    letter-spacing: 0.04em;
    font-size: var(--t-micro);
    text-transform: uppercase;
    padding: 0.1rem 0.45rem;
    background: rgba(37, 99, 235, 0.35);
    border: 1px dashed #60a5fa;
    border-radius: var(--r-sm);
}
.cta-buy-meta-sep {
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: #cbd5e1;
}

/* ── Eyebrow ───────────────────────────────────────────────────────────
   The small label above a section heading. This existed as 20+ near-identical
   Tailwind strings across the site — lime, blue, orange and slate variants at
   two paddings, two type sizes and three weights. One treatment, three tones.

   Emitted by the eyebrow() macro in _includes/macros/ui.njk. */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    margin-bottom: 1.5rem;
    border: 1px solid transparent;
    border-radius: var(--r-full);
    font-family: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: var(--t-small);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    line-height: 1;
    white-space: nowrap;
}
/* Default: the section label. Brand blue reads as structure, not decoration. */
.eyebrow--brand {
    background: rgba(37, 99, 235, 0.08);
    border-color: rgba(37, 99, 235, 0.22);
    color: var(--brand);
}
/* Informational pills that sit inline with content (region, status, meta). */
.eyebrow--neutral {
    background: var(--color-surface-alt);
    border-color: var(--hairline);
    color: var(--ink-soft);
}
/* Reserved for the rare label that genuinely needs the accent. Well inside
   lime's area budget at this size, but use it once per page at most. */
.eyebrow--accent {
    background: rgba(37, 99, 235, 0.25);
    border-color: rgba(37, 99, 235, 0.60);
    color: var(--accent-deep);
}
.eyebrow svg {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}

/* ── FAQ accordion ─────────────────────────────────────────────────────
   Defined identically on six pages. The open state was a lime wash across the
   whole panel — well outside the accent's area budget — so it now uses the
   alternating band, with the accent reduced to a left rule that marks which
   item is open. */
.faq-item {
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    overflow: hidden;
    transition: border-color 0.18s ease-out, background-color 0.18s ease-out;
}
.faq-item:hover { border-color: #c7d7f5; }
.faq-item.active {
    border-color: #c7d7f5;
    background-color: var(--color-surface-alt);
    box-shadow: inset 3px 0 0 var(--accent);
}
.faq-answer {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.28s ease-out;
}
.faq-item.active .faq-answer { max-height: 300px; }
.faq-icon { transition: transform 0.18s ease-out; }
.faq-item.active .faq-icon { transform: rotate(45deg); }

/* ── Stagger-in ────────────────────────────────────────────────────────
   Entrance animation, previously copied into seven pages along with its five
   delay steps. One ladder now, so sections on different pages come in at the
   same rhythm. */
.stagger-in {
    opacity: 0;
    transform: translateY(30px);
    animation: staggerIn 0.8s ease forwards;
}
.stagger-in-1 { animation-delay: 0.10s; }
.stagger-in-2 { animation-delay: 0.20s; }
.stagger-in-3 { animation-delay: 0.30s; }
.stagger-in-4 { animation-delay: 0.40s; }
.stagger-in-5 { animation-delay: 0.50s; }
@keyframes staggerIn {
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .stagger-in { opacity: 1; transform: none; animation: none; }
}

/* ── Hero glow ─────────────────────────────────────────────────────────
   A soft pool of brand colour behind a hero. Seven pages each defined their
   own 600px blurred circle on a 10s infinite drift; like the orbs, the motion
   was the problem, not the glow. Static, and softer than any of the copies. */
.hero-glow {
    position: absolute;
    width: 600px;
    height: 600px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(37, 99, 235, 0.22) 0%, transparent 70%);
    filter: blur(80px);
    pointer-events: none;
}

/* ── Comparison table ──────────────────────────────────────────────────
   Defined separately on /switch/, /web-hosting/, /premium-hosting/ and
   /wordpress-hosting/. The row hover was a lime tint; a full table row is far
   outside the accent's area budget, so it uses the alternating band instead. */
.comparison-table {
    border-collapse: separate;
    border-spacing: 0;
}
.comparison-table th,
.comparison-table td {
    border-bottom: 1px solid var(--hairline);
}
.comparison-table tbody tr {
    transition: background-color 0.18s ease-out;
}
.comparison-table tbody tr:hover {
    background-color: var(--color-surface-alt);
}

/* Hero trust strip */
.trust-strip {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    margin-top: 1.5rem;
    color: var(--ink-muted);
    font-size: var(--t-small);
    font-weight: 500;
}
.trust-strip-item {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    white-space: nowrap;
}
.trust-strip-item svg {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    color: #059669;
}
.trust-strip-sep {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: #cbd5e1;
    display: none;
}
@media (min-width: 640px) {
    .trust-strip-sep { display: inline-block; }
}

/* Hero secondary domain link */
.hero-secondary-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 1.25rem;
    color: var(--ink-muted);
    font-size: var(--t-small);
    font-weight: 500;
    transition: color 0.2s ease;
    border-bottom: 1px dashed transparent;
    padding-bottom: 2px;
}
.hero-secondary-link:hover {
    color: var(--brand);
    border-bottom-color: rgba(37, 99, 235, 0.4);
}
.hero-secondary-link svg {
    transition: transform 0.2s ease;
}
.hero-secondary-link:hover svg {
    transform: translateX(3px);
}

/* Pricing tier guarantee pill */
.tier-guarantee {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    margin-top: 0.65rem;
    width: 100%;
    color: #047857;
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: 0.01em;
    line-height: 1.3;
    text-align: center;
}
.tier-guarantee svg {
    width: 0.9rem;
    height: 0.9rem;
    flex-shrink: 0;
    color: #059669;
}
.pricing-card.featured .tier-guarantee {
    color: rgba(110, 231, 183, 1);
}
.pricing-card.featured .tier-guarantee svg {
    color: rgba(110, 231, 183, 1);
}

/* Tier audience hint (subtitle under plan name) */
.tier-audience {
    display: inline-block;
    margin-top: 0.25rem;
    padding: 0.2rem 0.55rem;
    background: #f1f5f9;
    border: 1px solid var(--hairline);
    border-radius: var(--r-sm);
    font-family: 'Space Mono', ui-monospace, monospace;
    font-size: var(--t-mock-sm);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-muted);
}
.pricing-card.featured .tier-audience {
    background: rgba(37, 99, 235, 0.16);
    border-color: rgba(37, 99, 235, 0.45);
    /* bfdbfe was 3.64:1 on the blue card — under AA for 11px. White is 5.17:1;
       the step down from the plan name comes from size and the mono face. */
    color: #ffffff;
}

/* Promo banner dismiss button */
.promo-banner-dismiss {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 1.5rem;
    height: 1.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-sm);
    color: var(--ink-muted);
    background: transparent;
    border: none;
    cursor: pointer;
    transition: background 0.18s ease, color 0.18s ease;
}
.promo-banner-dismiss:hover {
    color: var(--ink);
    background: rgba(11, 18, 32, 0.06);
}
.promo-banner.is-hidden {
    display: none;
}
.promo-banner.is-hidden ~ nav {
    top: 0;
}
body:has(> .promo-banner.is-hidden) {
    padding-top: 0;
}

/* Sticky mobile CTA bar */
.sticky-cta {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0));
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--hairline);
    box-shadow: 0 -8px 24px -12px rgba(16, 24, 40, 0.18);
    transform: translateY(calc(100% + 1rem));
    opacity: 0;
    pointer-events: none;
    transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
}
.sticky-cta.is-visible {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
}
.sticky-cta-meta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    margin-bottom: 0.4rem;
    color: var(--ink-muted);
    font-size: var(--t-mock-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
}
.sticky-cta-meta svg {
    width: 0.85rem;
    height: 0.85rem;
    color: #059669;
}
.sticky-cta-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.85rem 1rem;
    background: var(--brand);
    color: #ffffff;
    font-weight: 800;
    font-size: var(--t-body);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
    line-height: 1;
}
.sticky-cta-btn-price {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.55rem;
    margin-left: 0.25rem;
    background: rgba(10, 16, 36, 0.18);
    border-radius: var(--r-sm);
    font-family: 'Space Mono', ui-monospace, monospace;
    font-size: var(--t-micro);
    letter-spacing: 0.04em;
}
@media (min-width: 768px) {
    .sticky-cta { display: none; }
}


/* Slim featured pricing card refinements */
.pricing-card.featured {
    position: relative;
}
@media (min-width: 768px) {
    .pricing-card.featured {
        transform: scale(1.04);
        z-index: 2;
    }
    .pricing-card.featured:hover {
        transform: scale(1.04) translateY(-4px);
    }
}

