/* ============================================================================
   ISSULOGIX CRM — Business Consultancy — product site (bc.issulogix.com)
   Built to RULES/DESIGN_SYSTEM_RULES.md v2.1 + landing_page_skill_enhanced v2.0
   The ILX Properties stylesheet, repainted in the owner's Business Consultancy
   palette: ink #00050D, midnight #18203C, harbour #133C5A and steel #22587F
   for the dark ground; magenta #9C2968, rose #C46EA1 and plum #5B1343 for
   every highlight. Some comments below still describe the POS green they
   were first written for.
   ========================================================================= */

:root {
    /* ── Brand ─────────────────────────────────────────────────────────────
       VIVID, deliberately.

       #9c2968 stays as `--color-primary` because that is the exact green the
       Suite paints the POS workspace with and the licence panel files POS
       under — the product's identity, and not something a website should
       redefine. But it is a UI green: calm on purpose, and on a marketing
       page a whole screen of it reads flat.

       So the site is built on the LIFTED end of that hue instead. The deep
       green anchors, and everything that catches light — gradients, glows,
       auroras, highlights — runs up through emerald into spring green, with a
       cyan on one side and a warm amber on the other. Same colour family, far
       more energy, and it still matches the app it is selling. */
    --color-primary: #9c2968;
    --color-primary-rgb: 5, 38, 89;

    /* The workhorse: what gradients and glows actually run to. */
    --color-primary-lift: #c46ea1;
    --color-primary-lift-rgb: 84, 131, 179;

    /* Cool side — keeps the long gradients from going muddy in the middle. */
    --color-secondary: #c46ea1;
    --color-secondary-rgb: 125, 160, 202;
    --color-cyan: #f3cfe3;

    /* Warm side — the complement that makes the greens read as greens. */
    --color-accent: #f5b83d;
    --color-accent-rgb: 245, 184, 61;

    --color-mint: #f3cfe3;
    --color-spring: #fbeaf3;

    /* ── Neutrals ──────────────────────────────────────────────────────── */
    --color-bg: #ffffff;
    --color-bg-alt: #f6f4f8;
    --color-bg-deep: #133c5a;
    --color-bg-deeper: #00050d;
    --color-text: #00050d;
    --color-text-rgb: 2, 16, 36;
    --color-text-muted: #4b5068;
    --color-text-inverse: #f8eef4;
    --color-line: rgba(0, 5, 13, 0.10);

    /* ── Glass ─────────────────────────────────────────────────────────── */
    --glass-bg-light: rgba(255, 255, 255, 0.72);
    --glass-bg-dark: rgba(0, 5, 13, 0.68);
    --glass-border-light: rgba(255, 255, 255, 0.30);
    --glass-border-dark: rgba(255, 255, 255, 0.12);

    /* ── Shadows ───────────────────────────────────────────────────────── */
    --shadow-sm: 0 1px 4px rgba(0, 0, 0, 0.06), 0 2px 8px rgba(0, 0, 0, 0.04);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.08), 0 8px 32px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12), 0 24px 64px rgba(0, 0, 0, 0.08);
    --shadow-float: 0 16px 64px rgba(0, 0, 0, 0.18), 0 4px 16px rgba(0, 0, 0, 0.12);
    --shadow-glow: 0 18px 60px rgba(var(--color-primary-lift-rgb), 0.45);

    /* ── Gloss: the "sheen" the whole page is built on ─────────────────── */
    --sheen-soft: linear-gradient(155deg, rgba(255, 255, 255, 0.38) 0%, rgba(255, 255, 255, 0.10) 34%, rgba(255, 255, 255, 0) 35%);
    --sheen-hard: linear-gradient(160deg, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0.14) 30%, rgba(255, 255, 255, 0) 31%);
    /* Three stops and real hue travel: spring → emerald → teal. A two-stop
       green gradient is just a green rectangle with a shadow. */
    --grad-brand: linear-gradient(135deg, var(--color-spring) 0%, var(--color-primary-lift) 38%, var(--color-secondary) 100%);
    --grad-brand-deep: linear-gradient(135deg, var(--color-primary-lift) 0%, var(--color-primary) 46%, #5b1343 100%);

    /*
     * THE DARK GROUND IS A COLOUR, NOT A DARKNESS.
     *
     * It was #133c5a → #03140d, which is essentially black with a green cast.
     * On screen that reads drab rather than rich: the accents float on top of
     * a void instead of glowing out of a surface, and the whole page looks
     * unlit however bright the highlights get.
     *
     * This ramp keeps real saturation all the way down — a deep emerald into
     * a petrol teal, never dropping to near-black. The end stop is still dark
     * enough for white text at better than 12:1, but it is a HUE, so the mint
     * and cyan highlights read as light falling on a surface.
     */
    --grad-deep: linear-gradient(160deg, #22587f 0%, #133c5a 34%, #18203c 70%, #00050d 100%);

    /* The gradient's first stop, as a flat colour. Anything that must butt up
       against the top of the hero without a visible seam uses this. */
    --grad-deep-top: #22587f;

    /* ── Easing ────────────────────────────────────────────────────────── */
    --ease-smooth: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

    /* ── Type scale (fluid) ────────────────────────────────────────────── */
    --text-display: clamp(2.5rem, 6vw, 5.5rem);
    --text-h1: clamp(2rem, 4vw, 3.75rem);
    --text-h2: clamp(1.6rem, 3vw, 2.75rem);
    --text-h3: clamp(1.2rem, 2vw, 1.6rem);
    --text-body: clamp(1rem, 1.2vw, 1.125rem);
    --text-sm: clamp(0.875rem, 1vw, 1rem);

    /* ── Till-screen palette ───────────────────────────────────────────────
       The hero and feature graphics are DRAWN, not photographed, so the
       "screenshot" needs its own small palette. Kept here as variables for
       the same reason every other colour is: one edit repaints every mockup
       on the site, and nothing is hardcoded inside the markup. */
    --ui-screen: #0b1124;
    --ui-panel: #18203c;
    --ui-panel-2: #133c5a;
    --ui-line: #5b1343;
    --ui-tile: #0e254716;
    --ui-ink: #fbeef5;
    --ui-ink-dim: #d9a9c6;

    /* ── Radii ─────────────────────────────────────────────────────────── */
    --radius-sm: 12px;
    --radius-md: 18px;
    --radius-lg: 24px;
    --radius-xl: 32px;
}

@media (prefers-color-scheme: dark) {
    :root {
        --color-bg: #00040b;
        --color-bg-alt: #05091a;
        --color-text: #f8eef4;
        --color-text-rgb: 238, 245, 255;
        --color-text-muted: #a9aec4;
        --color-line: rgba(248, 238, 244, 0.12);
        --glass-bg-light: rgba(5, 9, 26, 0.72);
        --glass-border-light: rgba(255, 255, 255, 0.12);
    }
}

/* ── Reset ─────────────────────────────────────────────────────────────── */
*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
    margin: 0;
    font-family: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    font-size: var(--text-body);
    line-height: 1.7;
    color: var(--color-text);
    background: var(--color-bg);
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

h1, h2, h3, h4 {
    font-family: 'Sora', 'Plus Jakarta Sans', system-ui, sans-serif;
    line-height: 1.12;
    letter-spacing: -0.025em;
    margin: 0 0 0.6em;
    font-weight: 700;
}

h1 { font-size: var(--text-display); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); }
p { margin: 0 0 1.1em; }

a { color: inherit; }

img, svg { max-width: 100%; height: auto; display: block; }

.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

:focus-visible {
    outline: 3px solid rgba(var(--color-primary-rgb), 0.55);
    outline-offset: 3px;
    border-radius: 6px;
}

/* ── Container ─────────────────────────────────────────────────────────── */
.container {
    width: 100%;
    max-width: 1280px;
    margin-inline: auto;
    padding-inline: clamp(1rem, 4vw, 4rem);
}

@media (min-width: 1536px) {
    .container { max-width: 1440px; padding-inline: clamp(2rem, 5vw, 6rem); }
}

section { padding-block: clamp(4rem, 8vw, 8rem); }

@media (min-width: 1536px) { section { padding-block: 10rem; } }

/* ── Shared bits ───────────────────────────────────────────────────────── */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.10);
    border: 1px solid rgba(var(--color-primary-rgb), 0.20);
    padding: 0.45rem 0.9rem;
    border-radius: 999px;
    margin-bottom: 1.25rem;
}

.eyebrow--onDark {
    color: var(--color-mint);
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.18);
}

.lede {
    font-size: clamp(1.02rem, 1.4vw, 1.2rem);
    color: var(--color-text-muted);
    max-width: 62ch;
}

.section-head { max-width: 760px; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.section-head--center { margin-inline: auto; text-align: center; }

/* ── Buttons ───────────────────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    min-height: 52px;
    padding: 0 1.6rem;
    border-radius: 999px;
    font-weight: 700;
    font-size: 0.98rem;
    text-decoration: none;
    border: 1px solid transparent;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: transform 0.35s var(--ease-spring), box-shadow 0.35s var(--ease-smooth);
}

/* The gloss streak that gives every button its wet, lacquered look. */
.btn::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--sheen-hard);
    pointer-events: none;
}

.btn--primary {
    background: var(--grad-brand-deep);
    color: #fff;
    box-shadow: var(--shadow-glow);
}

.btn--ghost {
    background: rgba(255, 255, 255, 0.08);
    color: var(--color-text-inverse);
    border-color: rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}

.btn--dark {
    background: var(--color-bg-deep);
    color: var(--color-text-inverse);
    box-shadow: var(--shadow-md);
}

.btn--line {
    background: transparent;
    color: var(--color-text);
    border-color: var(--color-line);
}
.btn--line::after { display: none; }

@media (hover: hover) {
    .btn:hover { transform: translateY(-3px) scale(1.02); box-shadow: var(--shadow-lg); }
    .btn--primary:hover { box-shadow: 0 22px 70px rgba(var(--color-primary-rgb), 0.45); }
}

.btn:active { transform: scale(0.97); }

/* ── Scroll progress ───────────────────────────────────────────────────── */
#scroll-progress-bar {
    position: fixed;
    top: 0; left: 0;
    width: 0%; height: 3px;
    background: linear-gradient(90deg, var(--color-primary), var(--color-mint), var(--color-accent));
    z-index: 9999;
    transition: width 0.1s linear, opacity 0.3s ease;
    opacity: 0;
    border-radius: 0 2px 2px 0;
    box-shadow: 0 0 8px rgba(var(--color-primary-rgb), 0.6);
}
#scroll-progress-bar.visible { opacity: 1; }

/* ── Navbar ────────────────────────────────────────────────────────────── */
.navbar {
    position: sticky;
    top: 0;
    z-index: 1000;
    padding-block: 0.85rem;
    transition: background 0.4s var(--ease-smooth), backdrop-filter 0.4s var(--ease-smooth),
                box-shadow 0.4s var(--ease-smooth), border-color 0.4s var(--ease-smooth);
    border-bottom: 1px solid transparent;
}

.navbar.scrolled {
    background: var(--glass-bg-dark);
    backdrop-filter: blur(22px) saturate(140%);
    -webkit-backdrop-filter: blur(22px) saturate(140%);
    box-shadow: var(--shadow-sm);
    border-bottom-color: var(--glass-border-dark);
}

.nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
    font-family: 'Sora', sans-serif;
    font-weight: 800;
    font-size: 1.05rem;
    letter-spacing: -0.02em;
    color: var(--color-text-inverse);
    text-decoration: none;

    /*
     * The wordmark is two words and must never become two LINES. Squeezed by
     * a full nav row at 1024px it broke after "ILX", which pushed the whole
     * navbar from 69px to 104px — the logo was the thing making the bar tall,
     * not the menu. `flex: none` stops it being shrunk in the first place.
     */
    white-space: nowrap;
    flex: none;
}

.brand__mark {
    width: 38px; height: 38px;
    border-radius: 11px;
    background: var(--grad-brand-deep);
    display: grid; place-items: center;
    box-shadow: var(--shadow-glow);
    position: relative;
    overflow: hidden;
    flex: none;
}
.brand__mark::after { content: ''; position: absolute; inset: 0; background: var(--sheen-hard); }
.brand__mark svg { width: 21px; height: 21px; position: relative; z-index: 1; }

/*
 * ── THE MARK AS ARTWORK ───────────────────────────────────────────────────
 *
 * The product logo carries its own colour, its own depth and a transparent
 * background, so everything the tile was doing for a flat white glyph now
 * works against it: the gradient becomes a second logo behind the first, and
 * the sheen lays a diagonal band across the middle of the cart.
 *
 * Slightly larger than the tile it replaces, because the artwork has its own
 * breathing room built in — a 38px illustration inside a 38px box reads as
 * cramped where a 21px glyph did not.
 */
.brand__mark--art {
    width: 42px; height: 42px;
    background: none;
    box-shadow: none;
    border-radius: 0;
    overflow: visible;
}
.brand__mark--art::after { content: none; }
.brand__mark--art img { width: 100%; height: 100%; object-fit: contain; display: block; }

/*
 * ── THE MARK STANDING ALONE ───────────────────────────────────────────────
 *
 * The header said "ILX POS" twice: once in the logo, which carries the words,
 * and once as text beside it — and the half inside the logo was too small to
 * read, so the pairing looked like a mistake rather than a lockup.
 *
 * With the text gone the mark has to carry the header on its own, so it grows
 * into the space the words left. 52px against a navbar of 0.85rem padding
 * keeps it inside the bar's height rather than setting the bar's height, which
 * is what would make the whole nav jump taller.
 *
 * The link keeps its accessible name from `aria-label` on the anchor, which
 * was already there — without it, removing the text would have left a link
 * whose only content is an image with an empty alt, and a screen reader would
 * announce nothing at all.
 */
.brand__mark--solo { width: 52px; height: 52px; }
.brand__sub { font-weight: 500; opacity: 0.72; font-size: 0.82rem; }

/*
 * ── THE MENU NEVER WRAPS ──────────────────────────────────────────────────
 *
 * Adding "Brochure" made a seventh item and the row broke onto two lines at
 * 1024px — the navbar grew from 69px to 97px, and every link moved under the
 * cursor as the user navigated. `nowrap` makes that impossible rather than
 * unlikely: if the items ever stop fitting again the row will overflow
 * visibly, which is a bug somebody notices, instead of silently reflowing.
 *
 * The 1024-1279 band tightens spacing to buy the room, which is the order the
 * rule asks for — tighten first, and only then consider scrolling.
 */
.nav-links {
    display: none;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: nowrap;
    white-space: nowrap;
}

@media (min-width: 1180px) { .nav-links { display: flex; } }

@media (min-width: 1180px) and (max-width: 1319px) {
    .nav-links { gap: 0.1rem; }
    .nav-links a { padding: 0.6rem 0.62rem; font-size: 0.86rem; }
    .nav-cta { padding: 0 1.1rem; font-size: 0.9rem; }
}

.nav-links a {
    padding: 0.6rem 0.95rem;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    text-decoration: none;
    font-size: 0.92rem;
    font-weight: 600;
    color: rgba(248, 238, 244, 0.92);
    transition: color 0.25s ease, background 0.25s ease;
}

@media (hover: hover) {
    .nav-links a:hover { color: #fff; background: rgba(255, 255, 255, 0.09); }
}

.nav-cta { display: none; }

@media (min-width: 1180px) {
    .nav-cta {
        display: inline-flex;
        min-height: 46px;

        /*
         * The squeeze has to stop somewhere. With the brand and the menu both
         * refusing to shrink, a full row pushed the whole deficit into this
         * button and "Book a demo" broke into three stacked words. `flex:none`
         * plus nowrap means nothing in this bar reflows: if the items ever
         * stop fitting, the row overflows where somebody will see it.
         */
        flex: none;
        white-space: nowrap;
    }
}

.hamburger {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 46px; height: 46px;
    padding: 0 12px;
    border-radius: 13px;
    background: rgba(255, 255, 255, 0.09);
    border: 1px solid rgba(255, 255, 255, 0.16);
    color: var(--color-text-inverse);
    cursor: pointer;
}
@media (min-width: 1180px) { .hamburger { display: none; } }

.hamburger span {
    display: block; width: 22px; height: 2px;
    background: currentColor; border-radius: 2px;
    transition: transform 0.3s var(--ease-smooth), opacity 0.2s ease;
}
.hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger.open span:nth-child(2) { opacity: 0; transform: scaleX(0); }
.hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* Mobile drawer */
.mobile-menu {
    position: fixed;
    inset: 0;
    z-index: 1500;
    background: var(--grad-deep);
    padding: 6rem clamp(1.25rem, 6vw, 3rem) calc(2rem + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    transform: translateY(-100%);
    visibility: hidden;
    transition: transform 0.45s var(--ease-out), visibility 0.45s;
    overflow-y: auto;
}
.mobile-menu.open { transform: translateY(0); visibility: visible; }

.mobile-menu a {
    color: var(--color-text-inverse);
    text-decoration: none;
    font-family: 'Sora', sans-serif;
    font-size: 1.35rem;
    font-weight: 600;
    padding: 0.85rem 0.25rem;
    min-height: 44px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.mobile-menu .btn { margin-top: 1.5rem; }

.mobile-close {
    position: absolute;
    top: 1.4rem; right: clamp(1.25rem, 6vw, 3rem);
    width: 46px; height: 46px;
    border-radius: 13px;
    background: rgba(255, 255, 255, 0.09);
    border: 1px solid rgba(255, 255, 255, 0.16);
    color: #fff;
    font-size: 1.4rem;
    cursor: pointer;
}

/* ============================================================================
   HERO
   ========================================================================= */
.hero {
    position: relative;
    min-height: 100svh;
    display: flex;
    align-items: center;
    padding-block: clamp(3rem, 7vw, 5rem) clamp(4rem, 9vw, 7rem);
    background: var(--grad-deep);
    color: var(--color-text-inverse);
    overflow: hidden;
    isolation: isolate;
}

/*
 * ── THE STRIP BEHIND THE NAVBAR ───────────────────────────────────────────
 *
 * The navbar's text is near-white because it was drawn for a dark hero. But
 * the navbar is a SIBLING above <main> in the document, not an overlay on the
 * hero — so at the top of the page it sat on the body's own background, which
 * is white in light mode. Near-white on white: the logo and every nav link
 * were invisible until the user scrolled and the glass kicked in. Reported
 * from a real browser; the dark-mode preview never showed it, because there
 * the body was already dark and the bug had nothing to reveal it.
 *
 * Painting the shell with the hero's own gradient makes that strip continuous
 * with the hero instead of a white band above it — which is what the design
 * always assumed. The sections inside paint their own backgrounds over it, so
 * nothing else changes.
 */
.hero-shell { position: relative; }

/*
 * The dark strip is painted on the NAVBAR, not on the shell.
 *
 * It was on `.hero-shell` for one revision and that was wrong in a way the
 * dark-mode preview could not show: the shell wraps every section, so any
 * section without a background of its own — the features band, the admin band
 * — inherited the dark gradient while its text stayed the LIGHT-mode near
 * black. Dark on dark, headings gone. Reported from a real browser.
 *
 * The navbar is the only element that actually needed it, so it is the only
 * element that gets it. A flat colour equal to the hero gradient's first stop
 * keeps the seam invisible — a 165deg gradient on a 60px bar would render a
 * different slice of the ramp than the 700px hero below it, and the join
 * would show as a faint band.
 */
.hero-shell .navbar { background: var(--grad-deep-top); }

/*
 * ── AND THE SCROLLED GLASS HAS TO BEAT THAT ───────────────────────────────
 *
 * `.hero-shell .navbar` and `.navbar.scrolled` are BOTH two classes, so they
 * carry identical specificity and the later rule in the file wins. This one
 * is later, so `background: transparent` above was quietly overriding the
 * glass — the navbar never darkened at all. Over the hero nobody could tell;
 * over a pale section the near-white nav links landed on a near-white
 * background and the whole menu vanished, leaving only the green button.
 * Reported from a real browser, twice.
 *
 * Restated at three classes so intent wins on merit rather than on the order
 * the two rules happen to appear in.
 */
.hero-shell .navbar.scrolled {
    background: var(--glass-bg-dark);
    border-bottom-color: var(--glass-border-dark);
}

/*
 * ── AND THE LINKS GO OPAQUE WITH IT ───────────────────────────────────────
 *
 * Restoring the glass was not enough on its own. The glass is 62% dark, so
 * over a PALE section it composites to about rgb(90,105,128) — mid grey-green,
 * not the near-black it is over the hero. Nav links at 80% opacity land on
 * that at 3.78:1, under the 4.5:1 that 15px text needs. Readable-ish, and
 * still a fail.
 *
 * Full opacity takes the same links to 5.35:1 against the same composite.
 * Measured over --color-bg-alt, which is the palest thing the navbar ever
 * travels across.
 */
.navbar.scrolled .nav-links a,
.navbar.scrolled .brand { color: var(--color-text-inverse); }

.navbar.scrolled .brand__sub { opacity: 0.78; }

/* Aurora blooms — the vivid, glossy light behind everything. */
.hero__aurora {
    position: absolute;
    border-radius: 50%;
    filter: blur(90px);
    opacity: 0.62;
    pointer-events: none;
    z-index: -1;
}
.hero__aurora--1 {
    width: min(60vw, 720px); aspect-ratio: 1;
    background: radial-gradient(circle, rgba(196, 110, 161, 0.95), transparent 68%);
    top: -18%; right: -12%;
    animation: drift 18s var(--ease-smooth) infinite alternate;
}
.hero__aurora--2 {
    width: min(52vw, 620px); aspect-ratio: 1;
    background: radial-gradient(circle, rgba(243, 207, 227, 0.72), transparent 68%);
    bottom: -22%; left: -14%;
    animation: drift 22s var(--ease-smooth) infinite alternate-reverse;
}
.hero__aurora--3 {
    width: min(34vw, 400px); aspect-ratio: 1;
    background: radial-gradient(circle, rgba(245, 184, 61, 0.55), transparent 70%);
    top: 42%; left: 44%;
    animation: drift 26s var(--ease-smooth) infinite alternate;
}

@keyframes drift {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(4%, 6%, 0) scale(1.12); }
}

/* A fine grid, so the dark space reads as a designed surface not a void. */
.hero::before {
    content: '';
    position: absolute; inset: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
    background-size: 64px 64px;
    mask-image: radial-gradient(ellipse 90% 70% at 50% 40%, #000 30%, transparent 78%);
    -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 40%, #000 30%, transparent 78%);
    z-index: -1;
}

.hero__grid {
    display: grid;
    gap: clamp(2.5rem, 5vw, 4rem);
    align-items: center;
}

@media (min-width: 1024px) {
    .hero__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: clamp(2rem, 4vw, 3.5rem); }
}

/*
 * The hero headline is SMALLER than the display scale, and capped by measure.
 *
 * --text-display tops out at 5.5rem, which is right for a headline that owns
 * a full-width band. Here it shares the row with the product graphic, so at
 * 1280px it ran to six lines, pushed the buttons and the stats down, and
 * drove the device off the bottom of a 100svh hero — the first impression
 * was a headline and a cropped screen.
 *
 * 4rem with a 15ch minimum measure keeps it to three or four lines at every
 * width from 1024px up, which is what leaves the whole device visible.
 */
.hero h1 {
    font-size: clamp(2.25rem, 4.4vw, 4rem);
    max-width: 15ch;
    margin-bottom: 1.1rem;
}

@media (max-width: 1023px) {
    /* Single column: the headline has the full measure, so it can breathe. */
    .hero h1 { max-width: 20ch; }
}

.hero h1 .grad {
    background: linear-gradient(115deg, var(--color-mint) 0%, #f3cfe3 45%, var(--color-accent) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.hero__lede {
    font-size: clamp(1.05rem, 1.5vw, 1.24rem);
    color: rgba(248, 238, 244, 0.92);
    max-width: 56ch;
    margin-bottom: 2rem;
}

.hero__cta { display: flex; flex-wrap: wrap; gap: 0.85rem; margin-bottom: 2.4rem; }

.hero__proof {
    display: flex;
    flex-wrap: wrap;
    gap: clamp(1.2rem, 3vw, 2.5rem);
    padding-top: 1.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.hero__proof div { min-width: 92px; }
.hero__proof dt {
    font-family: 'Sora', sans-serif;
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    font-weight: 800;
    line-height: 1;
    background: linear-gradient(120deg, #fff, var(--color-mint));
    -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero__proof dd {
    margin: 0.35rem 0 0;
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(248, 238, 244, 0.90);
}

/* ── The hero product graphic ──────────────────────────────────────────── */
/*
 * DRAWN, NOT PHOTOGRAPHED.
 *
 * The whole visual is inline SVG plus CSS. That is a deliberate answer to
 * "the product image must be perfect": vector geometry is exact at every
 * breakpoint and at every pixel density, it cannot arrive stretched, badly
 * cropped, mis-keyed or half-loaded, and it weighs a fraction of a
 * screenshot. There is no raster asset here that can look wrong.
 */
.hero__stage {
    position: relative;
    perspective: 1600px;
    /* Never below its natural proportions on small screens. */
    max-width: 700px;
    margin-inline: auto;
    width: 100%;
}

/*
 * The rig is real hardware, not a floating pane: a wide touchscreen till on a
 * brushed-metal pedestal with a smaller customer display standing in front of
 * it. All of it — housing, stand, contact shadows, the specular sweep on the
 * glass — is drawn inside the SVG, so the lighting stays consistent with the
 * geometry at any size. The only thing left to CSS is the turn towards the
 * reader and the shadow the whole unit drops on the section behind it.
 *
 * drop-shadow, not box-shadow: box-shadow would trace the element's rectangle
 * and print a hard-edged box in the empty corners around the stand.
 */
.rig {
    position: relative;
    transform: rotateY(-7deg) rotateX(3deg);
    transform-style: preserve-3d;
    transition: transform 0.6s var(--ease-smooth);
    filter: drop-shadow(0 34px 52px rgba(0, 0, 0, 0.55));
}

@media (min-width: 1024px) {
    .rig { transform: rotateY(-10deg) rotateX(4deg) translateZ(0); }
}

.rig__svg { display: block; width: 100%; height: auto; }

/* ── Floating glossy icons ─────────────────────────────────────────────── */
.floaty {
    position: absolute;
    width: clamp(52px, 8vw, 74px);
    aspect-ratio: 1;
    border-radius: 22px;
    display: grid;
    place-items: center;
    color: #fff;
    background: var(--grad-brand-deep);
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(255, 255, 255, 0.16) inset;
    z-index: 4;
    overflow: hidden;
    animation: bob 6s var(--ease-smooth) infinite alternate;
}
.floaty::after { content: ''; position: absolute; inset: 0; background: var(--sheen-hard); }
.floaty svg { width: 46%; height: 46%; position: relative; z-index: 1; }

/*
 * Placed around the hardware, not on it. The stands occupy the lower middle of
 * the stage and the two screens the upper right, so the icons take the margins
 * that are left; the bottom-right corner is given up entirely because the
 * fixed back-to-top and WhatsApp buttons live there.
 */
.floaty--cart   { top: -4%;  left: -6%;  animation-delay: 0s; }
.floaty--tag    { top: 28%;  left: -11%; animation-delay: 1.2s;
                  background: linear-gradient(135deg, #f7c948, var(--color-accent)); }
.floaty--card   { bottom: 14%; left: -9%; animation-delay: 2.1s;
                  background: linear-gradient(135deg, #c46ea1, var(--color-secondary)); }
.floaty--scan   { top: -7%;  right: 4%;  animation-delay: 0.7s;
                  background: linear-gradient(135deg, #c46ea1, #9c2968); }
.floaty--receipt{ bottom: 24%; right: -7%; animation-delay: 1.7s; }

/* Below 640px the icons crowd the device, so the two least-informative go. */
@media (max-width: 639px) {
    .floaty--tag, .floaty--card { display: none; }
    .floaty--cart { left: -2%; }
    .floaty--receipt { right: -1%; }
}

@keyframes bob {
    from { transform: translateY(0) rotate(-2deg); }
    to   { transform: translateY(-14px) rotate(2deg); }
}

/* A small glass chip that reads like a live figure from the till. */
.chip {
    position: absolute;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.7rem 0.95rem;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.13);
    border: 1px solid rgba(255, 255, 255, 0.22);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    box-shadow: var(--shadow-float);
    font-size: 0.8rem;
    line-height: 1.25;
    white-space: nowrap;
    animation: bob 7s var(--ease-smooth) infinite alternate;
}
.chip strong { display: block; font-family: 'Sora', sans-serif; font-size: 0.98rem; }
.chip small { color: rgba(248, 238, 244, 0.62); font-size: 0.7rem; }
.chip__dot { width: 9px; height: 9px; border-radius: 50%; background: var(--color-mint);
             box-shadow: 0 0 0 4px rgba(243, 207, 227, 0.22); flex: none; }

.chip--sale { right: -4%; top: 22%; animation-delay: 0.4s; }
/* Level with the floor, so it reads as standing in front of the stand rather
   than cutting across its neck. */
.chip--shift { left: 1%; bottom: 3%; animation-delay: 1.9s; }

@media (max-width: 767px) {
    .chip--shift { display: none; }
    .chip--sale { right: 0; top: 8%; }
}

/* ============================================================================
   MARQUEE — the trades strip
   ========================================================================= */
.marquee {
    padding-block: 1.4rem;
    background: var(--color-bg-deeper);
    border-block: 1px solid rgba(255, 255, 255, 0.07);
    overflow: hidden;
    color: rgba(248, 238, 244, 0.74);
}
.marquee__track {
    display: flex;
    gap: 3.5rem;
    width: max-content;
    animation: slide 28s linear infinite;
}
.marquee__track span {
    display: inline-flex; align-items: center; gap: 0.6rem;
    font-family: 'Sora', sans-serif; font-weight: 600; font-size: 0.95rem;
    letter-spacing: 0.02em; white-space: nowrap;
}
.marquee__track svg { width: 18px; height: 18px; color: var(--color-primary-lift); }

@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

@media (hover: hover) { .marquee:hover .marquee__track { animation-play-state: paused; } }

/* ============================================================================
   CARDS / FEATURES
   ========================================================================= */
.card-grid {
    display: grid;
    gap: clamp(1rem, 2.5vw, 1.75rem);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}

.card {
    position: relative;
    padding: clamp(1.5rem, 3vw, 2rem);
    border-radius: var(--radius-lg);
    background: var(--color-bg);
    border: 1px solid var(--color-line);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    transition: transform 0.4s var(--ease-smooth), box-shadow 0.4s var(--ease-smooth),
                border-color 0.4s var(--ease-smooth);
}

.card::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--grad-brand);
    opacity: 0;
    transition: opacity 0.4s var(--ease-smooth);
}

@media (hover: hover) {
    .card:hover {
        transform: translateY(-6px);
        box-shadow: var(--shadow-lg);
        border-color: rgba(var(--color-primary-rgb), 0.28);
    }
    .card:hover::before { opacity: 1; }
}

/*
 * ── THE 3D FEATURE OBJECT ─────────────────────────────────────────────────
 *
 * A flat icon in a rounded square is the safe choice and it looks like every
 * other SaaS page. These are built as real objects instead: a lit face, a
 * darker extruded side, a cast shadow on the surface below, and a specular
 * highlight across the top — the four things that make an eye read "solid"
 * rather than "picture of".
 *
 * Still vector, for the same reason the hero is: exact at any size, no raster
 * asset that can arrive stretched or half-loaded, and a few hundred bytes.
 * The depth comes from geometry and gradients, not from a photograph.
 */
.card__icon {
    /*
     * `display: block` is load-bearing, not tidiness.
     *
     * This is a <span>, so it defaulted to `display: inline` — and width and
     * height do not apply to an inline box. The element computed to 0×0, the
     * absolutely-positioned face inset into it collapsed with it, and every
     * feature card rendered with no icon at all while the CSS looked correct.
     */
    display: block;
    width: 76px;
    height: 76px;
    margin-bottom: 1.35rem;
    position: relative;
    perspective: 220px;
    flex: none;
}

.card__icon-face {
    position: absolute;
    inset: 0;
    border-radius: 20px;
    background: var(--grad-brand-deep);
    display: grid;
    place-items: center;
    color: #fff;
    overflow: hidden;
    transform: rotateX(14deg) rotateY(-16deg);
    transform-style: preserve-3d;
    box-shadow:
        /* the extruded body, faked with stacked offsets so it needs no extra
           element and cannot fall out of alignment */
        2px 3px 0 rgba(11, 17, 36, 0.55),
        4px 6px 0 rgba(11, 17, 36, 0.42),
        6px 9px 0 rgba(11, 17, 36, 0.28),
        8px 12px 0 rgba(11, 17, 36, 0.14),
        /* and the shadow it casts on the card */
        14px 22px 34px rgba(0, 0, 0, 0.30),
        0 0 0 1px rgba(255, 255, 255, 0.14) inset;
    transition: transform 0.5s var(--ease-spring), box-shadow 0.5s var(--ease-smooth);
}

/* Specular sweep — the thing that reads as a polished surface. */
.card__icon-face::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(120% 90% at 22% 12%, rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0) 46%),
        var(--sheen-hard);
    pointer-events: none;
}

.card__icon-face svg {
    width: 34px;
    height: 34px;
    position: relative;
    z-index: 1;
    filter: drop-shadow(0 2px 3px rgba(0, 5, 13, 0.55));
}

@media (hover: hover) {
    /* Turns toward the viewer on hover — the object rotates, it does not just
       scale, which is what keeps it reading as a solid rather than a sticker. */
    .card:hover .card__icon-face {
        transform: rotateX(6deg) rotateY(-6deg) translateY(-4px);
        box-shadow:
            2px 3px 0 rgba(11, 17, 36, 0.55),
            4px 6px 0 rgba(11, 17, 36, 0.42),
            6px 9px 0 rgba(11, 17, 36, 0.28),
            8px 12px 0 rgba(11, 17, 36, 0.14),
            18px 30px 44px rgba(0, 0, 0, 0.38),
            0 0 0 1px rgba(255, 255, 255, 0.2) inset;
    }
}

/* Accent variants, so a grid of six does not read as one repeated object. */
.card__icon--gold .card__icon-face { background: linear-gradient(135deg, #ffd469, var(--color-accent)); }
.card__icon--gold .card__icon-face { box-shadow:
        2px 3px 0 rgba(120, 82, 0, 0.5), 4px 6px 0 rgba(120, 82, 0, 0.38),
        6px 9px 0 rgba(120, 82, 0, 0.24), 8px 12px 0 rgba(120, 82, 0, 0.12),
        14px 22px 34px rgba(0, 0, 0, 0.28), 0 0 0 1px rgba(255, 255, 255, 0.24) inset; }

.card__icon--teal .card__icon-face { background: linear-gradient(135deg, #f3cfe3, var(--color-secondary)); }
.card__icon--teal .card__icon-face { box-shadow:
        2px 3px 0 rgba(156, 41, 104, 0.55), 4px 6px 0 rgba(156, 41, 104, 0.42),
        6px 9px 0 rgba(156, 41, 104, 0.28), 8px 12px 0 rgba(156, 41, 104, 0.14),
        14px 22px 34px rgba(0, 0, 0, 0.28), 0 0 0 1px rgba(255, 255, 255, 0.18) inset; }

@media (prefers-reduced-motion: reduce) {
    .card__icon-face,
    .card:hover .card__icon-face { transition: none; }
}

.card h3 { margin-bottom: 0.5rem; }
.card p { color: var(--color-text-muted); font-size: 0.97rem; margin: 0; }

.card__tag {
    display: inline-block;
    margin-top: 1rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-primary);
    background: rgba(var(--color-primary-rgb), 0.09);
    padding: 0.3rem 0.65rem;
    border-radius: 999px;
}

/* ============================================================================
   TRADE CARDS — isometric 3D objects
   ============================================================================
   The trade cards were a heading and a paragraph, which made the section read
   as a list rather than as seven products. Each now carries a small isometric
   object drawn in true 2:1 dimetric projection — a lit top face, two shaded
   side faces and a contact shadow, so it reads as a thing standing on the card
   rather than a picture printed on it.

   Vector for the same reason as everything else here: exact at any density,
   nothing to load, and no image that can arrive wrong. */
.trade-card { text-align: center; }

.trade-card .iso {
    width: 100%;
    max-width: 170px;
    margin: 0 auto 1.1rem;
    display: block;
    overflow: visible;
    filter: drop-shadow(0 16px 22px rgba(24, 32, 60, 0.22));
    transition: transform 0.5s var(--ease-spring), filter 0.5s var(--ease-smooth);
}

@media (hover: hover) {
    .card:hover .iso {
        transform: translateY(-6px) scale(1.04);
        filter: drop-shadow(0 24px 30px rgba(24, 32, 60, 0.30));
    }
}

@media (prefers-reduced-motion: reduce) {
    .trade-card .iso, .card:hover .iso { transition: none; transform: none; }
}

/* Alternating tinted band */
.band-alt { background: var(--color-bg-alt); }

.band-dark {
    background: var(--grad-deep);
    color: var(--color-text-inverse);
    position: relative;
    overflow: hidden;
}
.band-dark h2, .band-dark h3 { color: var(--color-text-inverse); }
.band-dark .lede { color: rgba(248, 238, 244, 0.88); }

/* ============================================================================
   SPLIT FEATURE ROWS
   ========================================================================= */
.split {
    display: grid;
    gap: clamp(2rem, 5vw, 4rem);
    align-items: center;
}
@media (min-width: 900px) {
    .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .split--flip .split__media { order: -1; }
}

.split + .split { margin-top: clamp(3.5rem, 7vw, 6rem); }

.split__media {
    position: relative;
    border-radius: var(--radius-xl);
    padding: clamp(1rem, 2.5vw, 1.75rem);
    background: linear-gradient(160deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.02));
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: var(--shadow-float);
    overflow: hidden;
}
.split__media::before {
    content: ''; position: absolute; inset: 0;
    background: var(--sheen-soft); pointer-events: none;
}
.split__media svg { border-radius: var(--radius-md); }

.tick-list { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: 0.85rem; }
.tick-list li { display: flex; gap: 0.8rem; align-items: flex-start; font-size: 0.98rem; }
.tick-list svg { width: 22px; height: 22px; flex: none; color: var(--color-primary-lift); margin-top: 2px; }

/*
 * ── INLINE MARKUP INSIDE A FLEX ROW ───────────────────────────────────────
 *
 * `.tick-list li` is a flex container, so EVERY child becomes a flex item —
 * including an <em> or <strong> sitting mid-sentence. "Void a basket and the
 * kitchen is <em>in real time</em>, so nothing keeps cooking" rendered as
 * three columns with the emphasis floating in a gap of its own, because the
 * text nodes either side and the <em> were laid out as siblings.
 *
 * Anonymous text nodes cannot be targeted, so the fix is to stop the inline
 * elements being flex items: they are given `display: inline` explicitly and
 * the row's gap is applied only between the icon and the text wrapper.
 */
.tick-list li > em,
.tick-list li > strong,
.tick-list li > span:not(.tick-list__text),
.tick-list li > a { display: inline; }

/* The whole sentence in one flex item, so emphasis flows inside it. */
.tick-list__text { flex: 1 1 auto; min-width: 0; }

/* ============================================================================
   PRICING
   ========================================================================= */
.plan-toggle {
    display: inline-flex;
    padding: 5px;
    border-radius: 999px;
    background: rgba(var(--color-text-rgb), 0.06);
    border: 1px solid var(--color-line);
    margin-inline: auto;
    margin-bottom: 3rem;
}
.plan-toggle button {
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    font: inherit;
    font-weight: 700;
    font-size: 0.9rem;
    padding: 0.6rem 1.15rem;
    min-height: 44px;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.3s var(--ease-smooth), color 0.3s var(--ease-smooth);
}
.plan-toggle button[aria-selected="true"] {
    background: var(--grad-brand-deep);
    color: #fff;
    box-shadow: 0 8px 22px rgba(var(--color-primary-rgb), 0.3);
}

.plans { display: grid; gap: clamp(1rem, 2.5vw, 1.75rem);
         grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }

.plan {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: clamp(1.6rem, 3vw, 2.2rem);
    border-radius: var(--radius-lg);
    background: var(--color-bg);
    border: 1px solid var(--color-line);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.plan--featured {
    border-color: rgba(var(--color-primary-rgb), 0.45);
    box-shadow: var(--shadow-lg);
}
.plan--featured::before {
    content: ''; position: absolute; inset: 0 0 auto 0; height: 4px; background: var(--grad-brand);
}

.plan__badge {
    position: absolute; top: 1.15rem; right: 1.15rem;
    font-size: 0.66rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
    color: #fff; background: var(--grad-brand-deep);
    padding: 0.3rem 0.6rem; border-radius: 999px;
}

.plan__name { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 1.15rem; margin-bottom: 0.15rem; }
.plan__for { color: var(--color-text-muted); font-size: 0.86rem; margin-bottom: 1.25rem; }

.plan__price { display: flex; align-items: baseline; gap: 0.35rem; margin-bottom: 0.3rem; }

/*
 * `[hidden]` is only `display: none` in the USER-AGENT stylesheet, which any
 * author rule with a real selector outranks. `.plan__price { display: flex }`
 * did exactly that, so hiding a price did nothing and every plan showed its
 * rupee AND its dirham line stacked on top of each other. The attribute is
 * doing its job; the rule above was quietly overruling it.
 */
.plan__price[hidden] { display: none; }

/*
 * ── THE UAE DIRHAM SYMBOL ─────────────────────────────────────────────────
 *
 * Drawn, not typed. The new dirham glyph was introduced in 2025 and system
 * font coverage is still patchy — on a machine without it the character
 * renders as a tofu box, which on a price is worse than writing "AED".
 *
 * Sized in `em` and never in pixels, so it takes the font size of whatever
 * line it sits on: 2.5rem in a plan headline, 0.9rem in a sentence. It also
 * takes `currentColor`, so it inherits the text colour with no per-context
 * rule. `vertical-align` seats it on the baseline rather than the text box,
 * which is what stops it riding high next to large numerals.
 */
.dirham {
    display: inline-block;

    /*
     * SIZED TO THE DIGITS, NOT TO THE EM BOX.
     *
     * The official glyph fills its viewBox top to bottom, so height:1em would
     * draw it a full em tall — noticeably bigger than the numerals beside it,
     * which only reach cap height. 0.74em matches the cap height of both
     * faces used here, so the symbol and the figure read as one unit.
     *
     * Width is auto and NEVER fixed: the artwork is 344.84 × 299.91, wider
     * than tall, and forcing a square would squash it. `em` throughout, so it
     * follows whatever line it sits on — 40px price, 14px sentence.
     */
    height: 0.74em;
    width: auto;

    /* The glyph has no descender, so its baseline is its bottom edge. */
    vertical-align: baseline;

    /* Filled artwork, not a stroked outline — and it takes the text colour. */
    fill: currentColor;
    stroke: none;

    /* A symbol is not a word: never let it wrap away from its number. */
    margin-inline-end: 0.16em;
    flex: none;
}
.plan__price b { font-family: 'Sora', sans-serif; font-size: clamp(2rem, 3.4vw, 2.5rem); font-weight: 800; line-height: 1; }
.plan__price span { color: var(--color-text-muted); font-size: 0.85rem; font-weight: 600; }
.plan__note { font-size: 0.78rem; color: var(--color-text-muted); margin-bottom: 1.4rem; }

.plan ul { list-style: none; margin: 0 0 1.75rem; padding: 0; display: grid; gap: 0.6rem; }
.plan li { display: flex; gap: 0.6rem; font-size: 0.9rem; align-items: flex-start; }
.plan li svg { width: 18px; height: 18px; flex: none; color: var(--color-primary-lift); margin-top: 3px; }
.plan .btn { margin-top: auto; width: 100%; }

/* ============================================================================
   FORMS
   ========================================================================= */
.form-input {
    width: 100%;
    min-height: 52px;
    /* 16px exactly. Anything smaller and iOS zooms the page on focus, which
       on a form inside a coloured panel looks like the layout breaking. */
    font-size: 1rem;
    font-family: inherit;
    padding: 0.875rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
    -webkit-appearance: none;
    appearance: none;
}

.form-input::placeholder { color: rgba(255, 255, 255, 0.68); }

.form-input:focus {
    outline: none;
    border-color: #fff;
    background: rgba(255, 255, 255, 0.22);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.28);
}

textarea.form-input { resize: vertical; min-height: 120px; }

/* The native dropdown list is drawn by the OS, so its options inherit nothing
   from here — without this they are white-on-white and unreadable. */
.form-input option { color: var(--color-text); background: #fff; }

/* The two-second flash that shows a plan was filled in for you. */
.form-input.is-prefilled {
    border-color: #fff;
    background: rgba(255, 255, 255, 0.30);
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.30);
}

.cf-status--ok { color: #fbeef5; font-weight: 600; }
.cf-status--err { color: #ffd9d9; font-weight: 600; }

/* ============================================================================
   FAQ
   ========================================================================= */
.faq { display: grid; gap: 0.85rem; max-width: 860px; margin-inline: auto; }

.faq details {
    border: 1px solid var(--color-line);
    border-radius: var(--radius-md);
    background: var(--color-bg);
    overflow: hidden;
    transition: border-color 0.3s var(--ease-smooth), box-shadow 0.3s var(--ease-smooth);
}
.faq details[open] { border-color: rgba(var(--color-primary-rgb), 0.32); box-shadow: var(--shadow-sm); }

.faq summary {
    cursor: pointer;
    list-style: none;
    padding: 1.15rem 1.35rem;
    min-height: 56px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    font-family: 'Sora', sans-serif;
    font-weight: 600;
    font-size: 1rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
    content: '+';
    font-size: 1.5rem;
    line-height: 1;
    color: var(--color-primary);
    transition: transform 0.3s var(--ease-spring);
    flex: none;
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq__body { padding: 0 1.35rem 1.35rem; color: var(--color-text-muted); font-size: 0.96rem; }

/* ============================================================================
   CTA + FOOTER
   ========================================================================= */
.cta-panel {
    position: relative;
    border-radius: var(--radius-xl);
    padding: clamp(2.5rem, 6vw, 4.5rem);
    background: var(--grad-brand-deep);
    color: #fff;
    overflow: hidden;
    box-shadow: var(--shadow-glow);
    text-align: center;
}
.cta-panel::before { content: ''; position: absolute; inset: 0; background: var(--sheen-soft); }
.cta-panel > * { position: relative; z-index: 1; }
.cta-panel h2 { color: #fff; }
.cta-panel p { color: rgba(255, 255, 255, 0.86); max-width: 56ch; margin-inline: auto; }
.cta-panel .btn--dark { background: #fff; color: var(--color-primary); }

.site-footer {
    background: var(--color-bg-deeper);
    color: rgba(248, 238, 244, 0.80);
    padding-block: clamp(3rem, 6vw, 5rem) 0;
    font-size: 0.92rem;
}
.footer-grid { display: grid; gap: 2.5rem; }
@media (min-width: 768px) { .footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: 3rem; } }

.site-footer h3 {
    color: #fff; font-size: 0.82rem; letter-spacing: 0.14em;
    text-transform: uppercase; margin-bottom: 1.1rem;
}
/*
 * ── FOOTER TOUCH TARGETS ──────────────────────────────────────────────────
 *
 * These links were 18px tall — an 18px target between two other 18px targets
 * is a thumb landing on the wrong one, and the footer is where the phone
 * number and the WhatsApp link live, so a mis-tap costs an actual enquiry.
 *
 * Each one is a 44px row now, with the list gap removed to pay for the extra
 * height: the block ends up almost exactly as tall as it was, because the
 * space that used to sit BETWEEN the links is now inside them where it can
 * catch a thumb.
 *
 * `width: fit-content` matters: stretched to the column, every row would be
 * a target several hundred pixels wide, so a tap anywhere near the text
 * follows a link the user was not aiming at.
 */
.site-footer ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0;
}

.site-footer a {
    color: inherit;
    text-decoration: none;
    transition: color 0.25s ease;
}

.site-footer ul a,
.site-footer address a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    width: fit-content;
    max-width: 100%;
}

@media (hover: hover) { .site-footer a:hover { color: var(--color-mint); } }

/*
 * The address block holds prose lines AND links. Its list items carry the
 * agents' street addresses, which must not become 44px-tall rows of plain
 * text, so the height is put on the links themselves above.
 */
.site-footer address { font-style: normal; line-height: 1.75; }

.site-footer address a { padding-block: 0.35rem; }

/* The agent list stacks, so the rows need the gap the nav lists gave up. */
.site-footer ul li { display: flex; flex-direction: column; }

.footer-bottom a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}

.footer-bottom p { margin: 0; }

.footer-legal { display: flex; flex-wrap: wrap; gap: 1.5rem; }

/* ── The vendor lock-up ─────────────────────────────────────────────────── */
.footer-vendor {
    margin-top: 1.75rem;
    display: grid;
    gap: 0.5rem;
    justify-items: start;
}

.footer-vendor > span {
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    opacity: 0.7;
}

.footer-vendor a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    opacity: 0.9;
    transition: opacity 0.25s ease;
}

@media (hover: hover) { .footer-vendor a:hover { opacity: 1; } }
.footer-vendor img { width: 150px; height: auto; }

/* ── Agents band ────────────────────────────────────────────────────────── */
.footer-agents {
    margin-top: clamp(2.5rem, 5vw, 3.5rem);
    padding-top: clamp(2rem, 4vw, 2.5rem);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.footer-agents__grid {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
}

@media (min-width: 768px) {
    .footer-agents__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.footer-agents address {
    display: grid;
    gap: 0.3rem;
    font-style: normal;
    line-height: 1.6;
}

.footer-agents strong { color: #fff; }

.site-footer address strong { color: #fff; }

.footer-bottom {
    margin-top: clamp(2.5rem, 5vw, 4rem);
    padding-block: 1.5rem;
    padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    display: flex; flex-wrap: wrap; gap: 1rem;
    align-items: center; justify-content: space-between;
    font-size: 0.85rem;
}

/* ============================================================================
   FLOATING UI
   ========================================================================= */
#whatsapp-float {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1.5rem);
    right: max(1.25rem, env(safe-area-inset-right, 1.25rem));
    width: 56px; height: 56px;
    border-radius: 50%;
    background: #25d366;
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    z-index: 900;
    box-shadow: 0 4px 16px rgba(37, 211, 102, 0.45), 0 8px 32px rgba(37, 211, 102, 0.25);
    text-decoration: none;
    transition: transform 0.3s var(--ease-spring), box-shadow 0.3s ease;
    animation: whatsapp-pulse 2.5s ease-in-out infinite;
    animation-delay: 3s;
}

@keyframes whatsapp-pulse {
    0%, 100% { box-shadow: 0 4px 16px rgba(37, 211, 102, 0.45), 0 8px 32px rgba(37, 211, 102, 0.25), 0 0 0 0 rgba(37, 211, 102, 0.5); }
    50%      { box-shadow: 0 4px 16px rgba(37, 211, 102, 0.45), 0 8px 32px rgba(37, 211, 102, 0.25), 0 0 0 12px rgba(37, 211, 102, 0); }
}

@media (hover: hover) {
    #whatsapp-float:hover {
        transform: scale(1.1) translateY(-2px);
        box-shadow: 0 8px 24px rgba(37, 211, 102, 0.55), 0 16px 48px rgba(37, 211, 102, 0.30);
        animation-play-state: paused;
    }
}
#whatsapp-float:active { transform: scale(0.95); }

.whatsapp-tooltip {
    position: absolute; right: calc(100% + 12px); top: 50%;
    background: var(--color-bg-deep); color: var(--color-text-inverse);
    font-size: 0.8125rem; font-weight: 500; white-space: nowrap;
    padding: 0.375rem 0.75rem; border-radius: 8px;
    opacity: 0; pointer-events: none;
    transform: translateY(-50%) translateX(6px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
@media (hover: hover) {
    #whatsapp-float:hover .whatsapp-tooltip { opacity: 1; transform: translateY(-50%) translateX(0); }
}
@media (hover: none) { .whatsapp-tooltip { display: none; } }

#scroll-to-top {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 1.5rem + 68px);
    right: max(1.25rem, env(safe-area-inset-right, 1.25rem));
    width: 48px; height: 48px;
    border-radius: 14px;
    background: var(--glass-bg-light);
    color: var(--color-text);
    border: 1px solid var(--color-line);
    box-shadow: var(--shadow-float);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    z-index: 800;
    opacity: 0;
    transform: translateY(16px) scale(0.9);
    transition: opacity 0.35s var(--ease-smooth), transform 0.35s var(--ease-smooth), box-shadow 0.2s ease;
    pointer-events: none;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
}
#scroll-to-top.visible { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
@media (hover: hover) { #scroll-to-top:hover { box-shadow: var(--shadow-lg); transform: translateY(-2px) scale(1.05); } }
#scroll-to-top:active { transform: scale(0.95); }

/* ============================================================================
   MOTION
   ========================================================================= */
.page-enter { opacity: 0; transform: translateY(20px); animation: pageEnter 0.7s var(--ease-out) forwards; }
.page-enter-delay-1 { animation-delay: 0.1s; }
.page-enter-delay-2 { animation-delay: 0.22s; }
.page-enter-delay-3 { animation-delay: 0.36s; }
.page-enter-delay-4 { animation-delay: 0.5s; }
@keyframes pageEnter { to { opacity: 1; transform: translateY(0); } }

/*
 * SCOPED TO `.js`, and that scoping is the whole safety net.
 *
 * Unscoped, `[data-reveal] { opacity: 0 }` means the entire page below the
 * fold is invisible until JavaScript says otherwise — so a blocked script, a
 * failed CDN, an old browser or one thrown error leaves a visitor looking at
 * a hero and then nothing at all. The class is added by a tiny inline script
 * at the top of <body>, so the hiding only ever exists where something is
 * guaranteed to undo it.
 *
 * Content visible by default; the animation is the enhancement.
 */
.js [data-reveal] {
    opacity: 0;
    transform: translateY(32px);
    transition: opacity 0.65s var(--ease-out), transform 0.65s var(--ease-out);
}
.js [data-reveal="left"]  { transform: translateX(-32px); }
.js [data-reveal="right"] { transform: translateX(32px); }
.js [data-reveal="scale"] { transform: scale(0.94); }
.js [data-reveal].revealed { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    /* Scoped the same way, and it must also beat `.js [data-reveal]` — hence
       matching the class here rather than relying on the bare attribute. */
    .js [data-reveal] { opacity: 1; transform: none; transition: none; }
    .page-enter { opacity: 1; transform: none; animation: none; }
    .rig { transform: none; }
}

/*
 * ── Pricing toggles: two rows, Books pattern ──────────────────────────────
 *
 * Deployment on its own line, then currency and period sharing the next.
 *
 * The three pills used to stack, each carrying `.plan-toggle`'s own 3rem
 * bottom margin — that margin is sized for a toggle standing alone above a
 * grid, and inside this stack it repeated three times, so nine rems of empty
 * page sat between the intro and the plans. Reset it here rather than
 * shrinking it at the source, which would leave any lone toggle cramped.
 */
.plan-toggles {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 1.25rem;
}

.plan-toggles .plan-toggle { margin: 0; }

.plan-toggles__row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem;
}

.plan-intro {
    max-width: 720px;
    margin: 0 auto 1.5rem;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.96rem;
}

/*
 * The storage line only appears on vendor-hosted plans, where the price
 * genuinely includes it. Saying "includes 5 GB" on a self-hosted plan would
 * be claiming to supply disk on a server we do not run.
 */
.plan__storage {
    margin: 0 0 1.1rem;
    padding: 0.5rem 0.75rem;
    border-radius: 10px;
    background: rgba(var(--color-secondary-rgb), 0.10);
    border: 1px solid rgba(var(--color-secondary-rgb), 0.22);
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--color-text);
}

/* Deployment labels carry an emoji, so they need room to breathe. */
.plan-toggle button { white-space: nowrap; }

@media (max-width: 560px) {
    .plan-toggle { flex-wrap: wrap; justify-content: center; }
    .plan-toggle button { font-size: 0.82rem; padding: 0.6rem 0.85rem; }
}

/*
 * THE SAME [hidden] TRAP, A SECOND TIME.
 *
 * `[hidden]` is only `display: none` in the user-agent stylesheet, so any
 * author rule with a real selector beats it. `.plans { display: grid }` and
 * `.plan-intro { ... }` did exactly that, and hiding a deployment group did
 * nothing — all three showed at once, so every plan appeared three times over
 * with three different prices. Caught by counting what was visible rather than
 * by looking, because at a glance it just looks like a long pricing table.
 *
 * Anything this page hides with the attribute needs a matching rule.
 */
.plans[hidden],
.plan-intro[hidden],
.plan-toggle[hidden] { display: none; }

/* ============================================================================
   PROPERTIES — drawn-screen extras. The mockups are vector, so the colours of
   their "paper" documents and of the Books screen live here as variables too,
   never as hex inside the markup (DESIGN_SYSTEM_RULES §2.2).
   ========================================================================= */
:root {
    --ui-alert: #fb7185;
    --ui-paper: #ffffff;
    --ui-paper-ink: #b894a8;
    --ui-paper-line: #e1cbd7;
    --ui-paper-tint: #fbf0f6;
    --ui-paper-dark: #00050d;
    --ui-books: #d23e92;
    --ui-books-tint: #fbf1f7;
    --ui-gold-hi: #ffe08a;
    --ui-shell-hi: #133c5a;
    --ui-shell: #0b1124;
}
.marquee__track span { font-family: 'Sora', sans-serif; font-weight: 600; }

/* The split rows reveal from the side, offset before they arrive; clip that
   offset so a phone can never pan sideways (body overflow alone is not enough on iOS). */
main { overflow-x: clip; }

/*
 * The ILX Properties logo has navy lettering, which vanishes on the dark
 * navbar and footer. It sits on a white tile there, the way an app icon does.
 * It is in a <picture> (WebP, PNG fallback), so the img inside fills the tile.
 */
.brand__mark--art {
    width: 48px; height: 48px;
    background: var(--ui-paper);
    border-radius: 12px;
    padding: 3px;
    box-shadow: var(--shadow-glow);
}
.brand__mark--art picture { display: contents; }

/* Four plans fit one row on a desktop instead of three and an orphan. */
.plans--four { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
