/* Quantom Schematics — main site theme.
   Builds on auth.css palette. Used by base.html and all non-auth pages. */

:root {
    /* New violet palette (May 2026) — anchored on the user-supplied
       eight-shade ramp #7b5dff (deepest) → #f0edff (lightest). The
       darker tones outside the ramp are computed so hover and heading
       emphasis still have enough contrast on white. */
    --qs-primary:      #7b5dff;       /* === primary anchor */
    --qs-primary-dark: #5a3fd6;       /* hover / gradient end */
    --qs-primary-deep: #4a2bba;       /* heading emphasis */
    --qs-primary-soft: #f0edff;       /* lightest backdrop */
    --qs-primary-50:   #f0edff;
    --qs-primary-100:  #d3c9ff;
    --qs-primary-200:  #c4b7ff;
    --qs-primary-300:  #b6a5ff;
    --qs-primary-400:  #a793ff;
    --qs-primary-500:  #9881ff;
    --qs-primary-600:  #896fff;
    --qs-primary-700:  #7b5dff;
    --qs-bg: #faf9ff;
    --qs-card-bg: #ffffff;
    --qs-text: #4d4866;
    --qs-heading: #2b1f55;
    --qs-muted: #8e889e;
    --qs-border: #ece5f3;
    --qs-success: #1aae6f;
    --qs-danger:  #e63b3b;
    --qs-warning: #f59e0b;
    --qs-info:    #06b6d4;
    --qs-shadow-sm: 0 2px 8px rgba(123, 93, 255, 0.08);
    --qs-shadow-md: 0 6px 18px rgba(123, 93, 255, 0.12);
    --qs-shadow-lg: 0 14px 36px rgba(123, 93, 255, 0.16);
}

html, body {
    height: 100%;
}

/* Smooth scroll for in-page anchors (Home / Features / Services /
   Contact navbar links land softly on each section). The
   scroll-margin-top keeps section headings clear of the sticky navbar. */
html { scroll-behavior: smooth; }
section[id] { scroll-margin-top: 80px; }

/* ── Floating social-action stack ─────────────────────────────────
   Three circular buttons (YouTube → Facebook → WhatsApp) stacked
   vertically at the bottom-right of every page. Each circle uses
   its native brand colour so the platform reads at a glance. */
.qs-fab-stack {
    position: fixed;
    right: 24px;
    bottom: 24px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    z-index: 1019;
}
.qs-fab {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    color: #ffffff !important;
    display: grid;
    place-items: center;
    font-size: 1.45rem;
    text-decoration: none;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18), 0 2px 4px rgba(0, 0, 0, 0.06);
    transition: transform 0.18s, box-shadow 0.18s, filter 0.18s;
}
.qs-fab:hover {
    transform: translateY(-2px) scale(1.05);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.22), 0 3px 8px rgba(0, 0, 0, 0.10);
    filter: brightness(1.06);
}
.qs-fab:focus-visible {
    outline: 3px solid #ffffff;
    outline-offset: 2px;
}

/* Brand-coloured circles. */
.qs-fab-youtube  { background: #ff0033; }
.qs-fab-facebook { background: #1877f2; }
.qs-fab-whatsapp {
    background: #25d366;
    /* Pulse animation runs only on the WhatsApp button — it's the
       primary contact channel, the other two are passive social. */
    animation: qsWhatsappPulse 1.4s ease-out 2;
}

@keyframes qsWhatsappPulse {
    0%   { box-shadow: 0 0 0 0 rgba(37, 211, 102, 0.45),
                       0 4px 14px rgba(37, 211, 102, 0.45); }
    70%  { box-shadow: 0 0 0 18px rgba(37, 211, 102, 0),
                       0 4px 14px rgba(37, 211, 102, 0.45); }
    100% { box-shadow: 0 0 0 0 rgba(37, 211, 102, 0),
                       0 4px 14px rgba(37, 211, 102, 0.45); }
}

body {
    background: var(--qs-bg);
    color: var(--qs-text);
    font-family: 'Segoe UI', 'Public Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    display: flex;
    flex-direction: column;
}

main.site-main {
    flex: 1;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--qs-heading);
    font-weight: 600;
}

a {
    color: var(--qs-primary);
    text-decoration: none;
}
a:hover { color: var(--qs-primary-dark); }

/* ---------- Navbar ---------- */
.qs-navbar {
    /* Light-violet themed background — picks up the new palette across
       the entire top bar. The container inside is narrowed so the row
       reads as a focused official strip rather than edge-to-edge. */
    background: linear-gradient(180deg, var(--qs-primary-soft) 0%, #fbfaff 100%);
    border-bottom: 1px solid var(--qs-primary-100);
    box-shadow: var(--qs-shadow-sm);
    padding: 10px 0;
    position: sticky;
    top: 0;
    z-index: 1020;
}
/* Narrow the navbar content. Bootstrap's .container is 1320 px on
   wide screens — too long. Cap at 1140 so the row feels official. */
.qs-navbar .container { max-width: 1140px; }

/* Force every nav action chip onto one row at desktop widths —
   Home / Features / Contact / Sign in / Register / Download /
   Get Free Activation. Bootstrap's .nav defaults to flex-wrap:wrap
   which lets the row break to a second line on narrow desktops
   (992-1100 px). Locking the wrap + trimming the gap and pill
   padding makes them all sit inline. The hamburger collapse still
   takes over below 992 px via Bootstrap's d-lg-none toggle so the
   mobile menu isn't squashed. */
@media (min-width: 992px) {
    .qs-navbar .nav {
        flex-wrap: nowrap !important;
        gap: 6px !important;
        white-space: nowrap;
    }
    .qs-navbar .qs-nav-link,
    .qs-navbar .qs-nav-free-cta,
    .qs-navbar .btn-qs-register,
    .qs-navbar .btn-qs-outline {
        padding-left: 12px;
        padding-right: 12px;
    }
}

.qs-brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: 800;
    font-size: 1.05rem;
    /* Themed brand wordmark — sits on the violet navbar in the
       deepest theme shade so it reads as the primary brand mark
       rather than plain black text. */
    color: var(--qs-primary-deep, #4a2bba);
    letter-spacing: 0.3px;
    text-decoration: none;
    /* Force "Quantom Schematics" + logo to stay on a single line. */
    white-space: nowrap;
}

.qs-brand:hover { color: var(--qs-primary); }

.qs-brand-mark {
    height: 32px;
    width: auto;
    object-fit: contain;
    display: block;
    /* The bundled brand PNG is the older vibrant-violet shade
       (#9540ed-ish). Shifting hue + dropping saturation a touch
       brings it onto the new theme violet (#7b5dff) without having
       to re-export the asset. Applies to every place the wordmark
       is rendered. */
    filter: hue-rotate(-12deg) saturate(0.9);
}

.qs-brand-mark.sm {
    height: 26px;
}

/* Nav links — boxed pills, themed like the Download button so the
   whole top row reads as one set of consistent action chips. */
.qs-nav-link {
    display: inline-block;
    background: #ffffff;
    border: 1px solid var(--qs-primary-100);
    color: var(--qs-primary-dark);
    font-weight: 600;
    font-size: 0.86rem;
    padding: 5px 14px;
    border-radius: 8px;
    transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.08s;
    text-decoration: none;
    letter-spacing: 0.2px;
    line-height: 1.7;
}

.qs-nav-link:hover {
    background: var(--qs-primary-soft);
    border-color: var(--qs-primary);
    color: var(--qs-primary-deep, #4a2bba);
    transform: translateY(-1px);
}

.qs-nav-link.active {
    background: var(--qs-primary);
    border-color: var(--qs-primary);
    color: #ffffff;
}

/* ---------- Logged-in nav: Dashboard + license pills ----------
   Redesigned as flat solid chips (no gradient). All three share the
   same pill geometry so the row reads as one set of action buttons
   with three colour states:
     • Dashboard            → solid brand violet (primary destination)
     • License "Activated"  → solid PURE GREEN  (license is active on
                                                 a device)
     • License "Active"     → solid brand-dark violet  (license is
                                                 active but not yet
                                                 bound to a device) */
.qs-nav-dashboard,
.qs-nav-license {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    /* Wider padding + min-width so the action chips feel substantial
       next to the public links. The min-width also evens out the
       "Active" / "Activated" / "Enter key" labels so they line up. */
    padding: 9px 24px;
    min-width: 130px;
    border-radius: 10px;
    font-weight: 700;
    font-size: 0.86rem;
    line-height: 1;
    letter-spacing: 0.3px;
    color: #ffffff !important;
    text-decoration: none;
    /* No outer border — earlier versions had a 1 px line that read as
       a hard "dark box edge" on Active/Activated; flat fill + a soft
       coloured drop-shadow is enough to lift the pill off the navbar
       cleanly. */
    border: 0;
    outline: 0;
    white-space: nowrap;
    transition: background 0.15s, box-shadow 0.15s, transform 0.10s;
}
.qs-nav-dashboard:focus,
.qs-nav-dashboard:focus-visible,
.qs-nav-license:focus,
.qs-nav-license:focus-visible {
    outline: 0;
    box-shadow: 0 0 0 3px rgba(123, 93, 255, 0.25),
                0 4px 12px rgba(123, 93, 255, 0.35);
}
.qs-nav-dashboard:hover,
.qs-nav-license:hover {
    transform: translateY(-1px);
    text-decoration: none;
    color: #ffffff !important;
}
.qs-nav-dashboard i,
.qs-nav-license i { font-size: 0.95rem; line-height: 1; }

/* Dashboard — solid brand violet. Replaces the old gradient look. */
.qs-nav-dashboard {
    background: #7b5dff;
    box-shadow: 0 2px 8px rgba(123, 93, 255, 0.28);
}
.qs-nav-dashboard:hover {
    background: #5a3fd6;
    box-shadow: 0 6px 16px rgba(123, 93, 255, 0.40);
}

/* Activated — PURE flat green per user request. No gradient, just
   one saturated green tone with a matching green drop shadow so it
   pops against the navbar's light tint. */
.qs-nav-license.activated {
    background: #16a34a;
    box-shadow: 0 2px 8px rgba(22, 163, 74, 0.35);
}
.qs-nav-license.activated:hover {
    background: #15803d;
    box-shadow: 0 6px 16px rgba(22, 163, 74, 0.45);
}

/* Active (not yet device-bound) — brand-dark violet so it's clearly
   distinguishable from the lighter Dashboard violet without going
   off-palette. Tells the user "this is a license state, not the
   primary nav action". */
.qs-nav-license.active {
    background: #5a3fd6;
    box-shadow: 0 2px 8px rgba(90, 63, 214, 0.28);
}
.qs-nav-license.active:hover {
    background: #4a2bba;
    box-shadow: 0 6px 16px rgba(90, 63, 214, 0.40);
}

/* The Logout button piggybacks on .qs-logout-btn — it stays plain
   text so the destructive action doesn't compete with the nav pills. */

/* Logout button (renders as link in navbar) */
.qs-logout-btn {
    background: none;
    border: none;
    color: var(--qs-text);
    font-weight: 500;
    padding: 8px 14px;
    border-radius: 8px;
    cursor: pointer;
}
.qs-logout-btn:hover {
    background: rgba(234, 84, 85, 0.1);
    color: var(--qs-danger);
}

/* ---------- Buttons ---------- */
.btn-qs-primary {
    background: linear-gradient(120deg, var(--qs-primary), var(--qs-primary-dark));
    border: 0;
    color: #fff;
    font-weight: 600;
    letter-spacing: 0.2px;
    border-radius: 9px;
    padding: 10px 22px;
    box-shadow: 0 4px 12px rgba(149, 64, 237, 0.28);
    transition: transform 0.12s, box-shadow 0.12s, filter 0.12s;
}

/* ── "Free for now" scrolling marquee ──────────────────────────
   A single-line ticker beneath the navbar. The track holds the
   bilingual message twice — once visible and once duplicated for
   seamless looping. The animation translates the track by -50%
   (= one copy's width), so by the time the first copy has fully
   scrolled off the left edge, the duplicate is at the same
   starting position and the cycle repeats with no visible gap.

   Pauses on hover so a reader can finish a sentence. Respects
   prefers-reduced-motion by switching the loop off and centring
   the static text instead. */
.qs-free-banner {
    /* Soft themed pill — sits below the navbar with margin on every
       side instead of touching the viewport edges, giving it rounded
       corners and a "floating capsule" feel. Background is a faded
       violet gradient (lower opacity than before) so it complements
       the page rather than dominating it. */
    margin: 10px 16px 0;
    background:
        linear-gradient(90deg,
            rgba(123, 93, 255, 0.88) 0%,
            rgba(90, 63, 214, 0.88) 60%,
            rgba(74, 43, 186, 0.88) 100%);
    color: #ffffff;
    padding: 11px 0;
    min-height: 42px;
    overflow: hidden;
    position: relative;
    border-radius: 14px;
    border: 1px solid rgba(123, 93, 255, 0.30);
    box-shadow: 0 4px 14px rgba(123, 93, 255, 0.16);
    display: flex;
    align-items: center;
}
.qs-free-banner-track {
    display: inline-flex;
    align-items: center;
    flex-wrap: nowrap;
    white-space: nowrap;
    /* Slower scroll (80 s end-to-end) so the eye has time to read
       a full sentence before it leaves the right edge. */
    animation: qsFreeBannerMarquee 80s linear infinite;
    will-change: transform;
}
.qs-free-banner:hover .qs-free-banner-track {
    animation-play-state: paused;
}
.qs-free-banner-text {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 0.95rem;
    font-weight: 700;
    color: #ffffff;
    letter-spacing: 0.2px;
    line-height: 1.4;
    padding-right: 3rem;   /* gap between the two copies */
    /* Subtle text shadow so the white text stays legible on the
       semi-transparent violet without going harsh. */
    text-shadow: 0 1px 2px rgba(74, 43, 186, 0.35);
}
.qs-free-banner-text i {
    color: #ffd166;          /* warm gold for the gift icon */
    font-size: 1.15rem;
}
.qs-free-banner-sep {
    color: rgba(255, 255, 255, 0.72);
    font-weight: 900;
    margin: 0 0.8rem;
    font-size: 1.25rem;
}
@keyframes qsFreeBannerMarquee {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}
@media (max-width: 540px) {
    .qs-free-banner {
        margin: 8px 10px 0;
        padding: 9px 0;
        min-height: 38px;
        border-radius: 12px;
    }
    .qs-free-banner-text {
        font-size: 0.86rem;
        padding-right: 2rem;
    }
    .qs-free-banner-track {
        animation-duration: 60s;
    }
}
@media (prefers-reduced-motion: reduce) {
    /* Some users have motion-sensitivity / vestibular concerns —
       stop the marquee and let them read at their own pace. */
    .qs-free-banner-track {
        animation: none;
        white-space: normal;
        text-align: center;
        justify-content: center;
        padding: 0 1rem;
    }
}

/* ── Dashboard "Get Free Activation" CTA — green pill ──────────
   Mirrors the navbar's green pill so the two CTAs feel like the
   same brand action. Sits next to "Request a license" on the
   Account-approval tile (and the same tile while pending too). */
.qs-dashboard-free-cta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #1aae6f;
    border: 1px solid #1aae6f;
    color: #ffffff !important;
    font-weight: 700;
    font-size: 0.9rem;
    padding: 8px 16px;
    border-radius: 9px;
    text-decoration: none;
    letter-spacing: 0.2px;
    box-shadow: 0 2px 8px rgba(26, 174, 111, 0.32);
    transition: background 0.15s, border-color 0.15s, transform 0.08s, box-shadow 0.12s;
}
.qs-dashboard-free-cta:hover,
.qs-dashboard-free-cta:focus {
    background: #128a55;
    border-color: #128a55;
    color: #ffffff !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(26, 174, 111, 0.42);
}
.qs-dashboard-free-cta i { font-size: 0.95rem; }

/* ── Navbar "Get Free Activation" CTA — green pill ──────────────
   This single nav-link is themed differently from the rest of the
   navbar (Home / Features / Contact) so it visually pops as a free
   call-to-action. Green (#1aae6f) background with white text +
   subtle WhatsApp-style elevation on hover. */
.qs-nav-free-cta {
    display: inline-block;
    background: #1aae6f;
    border: 1px solid #1aae6f;
    color: #ffffff !important;
    font-weight: 700;
    font-size: 0.86rem;
    padding: 5px 14px;
    border-radius: 8px;
    transition: background 0.15s, border-color 0.15s, transform 0.08s, box-shadow 0.12s;
    text-decoration: none;
    letter-spacing: 0.2px;
    line-height: 1.7;
    box-shadow: 0 2px 8px rgba(26, 174, 111, 0.32);
}
.qs-nav-free-cta:hover {
    background: #128a55;
    border-color: #128a55;
    color: #ffffff !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(26, 174, 111, 0.42);
}
.qs-nav-free-cta:focus-visible {
    outline: 3px solid rgba(26, 174, 111, 0.45);
    outline-offset: 2px;
}

/* ── Activation status pill (homepage hero, logged-in users) ────
   Sits next to the "Dashboard" button. Two variants:
     .qs-status-pill--ok   — green, when the user has an active license
     .qs-status-pill--warn — amber, when the user hasn't redeemed a key
                              yet (clickable, jumps to /portal/licenses/redeem)
   Both share a rounded-pill base + medium font so they read as a
   status indicator next to the primary CTA, not as a duplicate button. */
.qs-status-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    font-size: 0.92rem;
    letter-spacing: 0.2px;
    padding: 8px 16px;
    border-radius: 999px;
    border: 1.5px solid transparent;
    text-decoration: none;
    transition: transform 0.12s, box-shadow 0.12s, filter 0.12s;
    line-height: 1.4;
}
.qs-status-pill i { font-size: 1.05rem; }
.qs-status-pill--ok {
    background: rgba(26, 174, 111, 0.12);
    color: #117a4a;
    border-color: rgba(26, 174, 111, 0.32);
}
.qs-status-pill--warn {
    background: rgba(245, 158, 11, 0.14);
    color: #92580f;
    border-color: rgba(245, 158, 11, 0.36);
}
.qs-status-pill--warn:hover {
    color: #6d3f06;
    filter: brightness(1.04);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(245, 158, 11, 0.22);
}

/* Compact variant for the navbar Register button — same gradient
   as .btn-qs-primary but slimmer so it sits inline with the .qs-nav-link
   pills (Home/Features/Contact/Sign in) without towering over them. */
.btn-qs-register {
    background: linear-gradient(120deg, var(--qs-primary), var(--qs-primary-dark));
    border: 0;
    color: #fff !important;
    font-weight: 700;
    font-size: 0.86rem;
    letter-spacing: 0.2px;
    border-radius: 8px;
    padding: 5px 14px;
    line-height: 1.7;
    box-shadow: 0 2px 8px rgba(123, 93, 255, 0.28);
    transition: transform 0.12s, box-shadow 0.12s, filter 0.12s;
    text-decoration: none;
    display: inline-block;
}
.btn-qs-register:hover,
.btn-qs-register:focus {
    color: #fff !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(123, 93, 255, 0.38);
    filter: brightness(1.05);
}

.btn-qs-primary:hover,
.btn-qs-primary:focus {
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(149, 64, 237, 0.40);
    filter: brightness(1.05);
}

.btn-qs-outline {
    background: transparent;
    border: 1.5px solid var(--qs-primary);
    color: var(--qs-primary);
    font-weight: 600;
    border-radius: 9px;
    padding: 9px 20px;
    transition: background 0.12s, color 0.12s;
}

.btn-qs-outline:hover {
    background: var(--qs-primary);
    color: #fff;
}

.btn-qs-ghost {
    background: transparent;
    color: var(--qs-text);
    font-weight: 500;
    border: 0;
    padding: 9px 16px;
    border-radius: 9px;
}
.btn-qs-ghost:hover {
    background: rgba(149, 64, 237, 0.08);
    color: var(--qs-primary-dark);
}

/* ---------- Cards ---------- */
.qs-card {
    background: var(--qs-card-bg);
    border: 0;
    border-radius: 14px;
    box-shadow: var(--qs-shadow-sm);
    transition: box-shadow 0.18s, transform 0.18s;
}

.qs-card:hover {
    box-shadow: var(--qs-shadow-md);
}

.qs-card-hover-lift:hover {
    transform: translateY(-3px);
    box-shadow: var(--qs-shadow-md);
}

.qs-card .card-header,
.qs-card-header {
    background: transparent;
    border-bottom: 1px solid var(--qs-border);
    padding: 16px 22px;
    font-weight: 600;
    color: var(--qs-heading);
}

.qs-card .card-body { padding: 22px; }

/* Stat / icon tile */
.qs-stat-icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    display: grid;
    place-items: center;
    font-size: 1.3rem;
    background: var(--qs-primary-soft);
    color: var(--qs-primary-dark);
    margin-bottom: 14px;
}

/* Boosted opacity on the success-state tile (Account approved /
   Activated). The original ~14 % alpha was too faint to register as
   "this is the active state" — bumped to a solid filled chip with
   white text so the green stands out. */
.qs-stat-icon.success { background: #1aae6f; color: #ffffff; box-shadow: 0 4px 12px rgba(26, 174, 111, 0.35); }
.qs-stat-icon.warning { background: rgba(255, 159, 67, 0.14); color: #d77324; }
.qs-stat-icon.danger  { background: rgba(234, 84, 85, 0.14);  color: #c43536; }
.qs-stat-icon.info    { background: rgba(0, 207, 232, 0.14);  color: #008ba0; }

/* ---------- Hero (landing) ---------- */
.qs-hero {
    background:
        radial-gradient(circle at 12% 20%, rgba(149, 64, 237, 0.12), transparent 40%),
        radial-gradient(circle at 88% 80%, rgba(149, 64, 237, 0.08), transparent 50%),
        linear-gradient(180deg, #fdfbff 0%, var(--qs-bg) 100%);
    padding: 64px 0 80px;
    position: relative;
    overflow: hidden;
}

.qs-hero::before {
    /* subtle decorative grid */
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(149, 64, 237, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(149, 64, 237, 0.05) 1px, transparent 1px);
    background-size: 38px 38px;
    pointer-events: none;
    mask-image: radial-gradient(ellipse at center, black 40%, transparent 80%);
}

.qs-hero-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--qs-primary-soft);
    color: var(--qs-primary-dark);
    padding: 6px 14px;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 600;
    margin-bottom: 18px;
    letter-spacing: 0.2px;
}

.qs-hero h1 {
    font-size: clamp(2rem, 4vw, 3rem);
    line-height: 1.12;
    color: var(--qs-heading);
    font-weight: 700;
    letter-spacing: -0.5px;
}

.qs-hero h1 .accent { color: var(--qs-primary); }

.qs-hero p.lead {
    font-size: 1.12rem;
    color: var(--qs-muted);
    line-height: 1.6;
    max-width: 520px;
}

.qs-hero-actions {
    margin-top: 26px;
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.qs-hero-illustration {
    background: linear-gradient(140deg, #ad62f3 0%, #8137d8 50%, #5e2398 100%);
    border-radius: 22px;
    color: #fff;
    padding: 44px 40px;
    box-shadow: var(--qs-shadow-lg);
    position: relative;
    overflow: hidden;
    min-height: 280px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* ---------- Animated text rotator (pure CSS, no JS) ---------- */
.qs-rotator-label {
    text-transform: uppercase;
    font-size: 0.78rem;
    letter-spacing: 1.6px;
    color: rgba(255,255,255,0.78);
    font-weight: 600;
    margin-bottom: 14px;
}

.qs-rotator {
    display: grid;
    grid-template-columns: 1fr;
    height: 56px;
    position: relative;
    margin-bottom: 18px;
}

.qs-rotator-item {
    grid-column: 1;
    grid-row: 1;
    opacity: 0;
    transform: translateY(18px);
    color: #fff;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: -0.4px;
    line-height: 1.15;
    animation: qsRotate 12s ease-in-out infinite;
    will-change: opacity, transform;
}

/* Stagger each phrase 3s apart */
.qs-rotator-item:nth-child(1) { animation-delay:  0s; }
.qs-rotator-item:nth-child(2) { animation-delay:  3s; }
.qs-rotator-item:nth-child(3) { animation-delay:  6s; }
.qs-rotator-item:nth-child(4) { animation-delay:  9s; }

@keyframes qsRotate {
    0%   { opacity: 0; transform: translateY(18px); }
    6%   { opacity: 1; transform: translateY(0); }
    25%  { opacity: 1; transform: translateY(0); }
    31%  { opacity: 0; transform: translateY(-18px); }
    100% { opacity: 0; transform: translateY(-18px); }
}

.qs-rotator-foot {
    color: rgba(255,255,255,0.78);
    font-size: 0.96rem;
    margin-bottom: 0;
}

@media (prefers-reduced-motion: reduce) {
    .qs-rotator-item { animation: none; opacity: 1; transform: none; }
    .qs-rotator-item:not(:first-child) { display: none; }
}

.qs-hero-illustration::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255,255,255,0.06) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.06) 1px, transparent 1px);
    background-size: 30px 30px;
    pointer-events: none;
}

.qs-illustration-stat {
    background: rgba(255,255,255,0.12);
    backdrop-filter: blur(10px);
    border-radius: 14px;
    padding: 16px 20px;
    margin-bottom: 14px;
}

.qs-illustration-stat .num {
    font-size: 1.8rem;
    font-weight: 700;
    line-height: 1;
}

.qs-illustration-stat .lbl {
    color: rgba(255,255,255,0.78);
    font-size: 0.88rem;
    margin-top: 4px;
}

/* ---------- Section spacing ---------- */
.qs-section {
    padding: 60px 0;
}
.qs-section-title {
    font-size: 1.85rem;
    font-weight: 700;
    margin-bottom: 8px;
    color: var(--qs-heading);
}
.qs-section-sub {
    color: var(--qs-muted);
    font-size: 1.02rem;
    margin-bottom: 36px;
}

/* ---------- Feature card (landing) ---------- */
.qs-feature {
    background: #fff;
    border-radius: 14px;
    padding: 24px;
    height: 100%;
    box-shadow: var(--qs-shadow-sm);
    transition: transform 0.18s, box-shadow 0.18s;
}
.qs-feature:hover {
    transform: translateY(-4px);
    box-shadow: var(--qs-shadow-md);
}

.qs-feature-icon {
    width: 48px;
    height: 48px;
    border-radius: 12px;
    background: var(--qs-primary-soft);
    color: var(--qs-primary-dark);
    display: grid;
    place-items: center;
    font-size: 1.3rem;
    margin-bottom: 16px;
}

.qs-feature h5 {
    font-size: 1.08rem;
    font-weight: 600;
    margin-bottom: 6px;
}

.qs-feature p {
    color: var(--qs-muted);
    font-size: 0.94rem;
    margin: 0;
    line-height: 1.55;
}

/* ---------- Footer ---------- */
.qs-footer {
    background: #fff;
    border-top: 1px solid var(--qs-border);
    padding: 28px 0;
    text-align: center;
    color: var(--qs-muted);
    font-size: 0.9rem;
}

.qs-footer a { color: var(--qs-primary); }

/* ---------- Tables ---------- */
.qs-card .table {
    margin: 0;
    color: var(--qs-text);
}
.qs-card .table thead th {
    text-transform: uppercase;
    font-size: 0.74rem;
    letter-spacing: 0.4px;
    background: #fafafa;
    color: var(--qs-muted);
    font-weight: 600;
    border-bottom: 1px solid var(--qs-border);
    padding: 14px 18px;
}
.qs-card .table tbody td { padding: 14px 18px; vertical-align: middle; }
.qs-card .table tbody tr:hover { background: rgba(149, 64, 237, 0.04); }

/* ---------- Form controls in main app ---------- */
.qs-form .form-control,
.qs-form .form-select {
    border: 1px solid var(--qs-border);
    border-radius: 9px;
    padding: 10px 14px;
    color: var(--qs-text);
}
.qs-form .form-control:focus,
.qs-form .form-select:focus {
    border-color: var(--qs-primary);
    box-shadow: 0 0 0 0.16rem rgba(149, 64, 237, 0.16);
}

/* ---------- Page header ---------- */
.qs-page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 28px;
}

.qs-page-header h1 {
    font-size: 1.6rem;
    font-weight: 700;
    margin: 0;
    color: var(--qs-heading);
}

.qs-page-header .lead {
    color: var(--qs-muted);
    font-size: 0.96rem;
    margin: 4px 0 0 0;
}

/* ---------- Dashboard hero ----------
   Replaces the old "Welcome / email / badge" header with a themed
   block: a small uppercase eyebrow ("Welcome"), then the user's
   first + last name as a large gradient title, then a prominent
   "N days remaining" line which is the single most useful piece of
   info on the dashboard. */
.qs-dashboard-hero {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 32px;
    padding: 24px 28px;
    border-radius: 16px;
    background: linear-gradient(135deg, #f5f1ff 0%, #ebe4ff 100%);
    border: 1px solid var(--qs-primary-100);
    box-shadow: 0 6px 22px rgba(123, 93, 255, 0.10);
}
.qs-dashboard-hero-text { display: flex; flex-direction: column; gap: 4px; }
.qs-hero-eyebrow {
    text-transform: uppercase;
    letter-spacing: 1.5px;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--qs-primary-dark);
    opacity: 0.85;
}
.qs-hero-name {
    margin: 0;
    font-size: 2rem;
    font-weight: 800;
    line-height: 1.15;
    background: linear-gradient(120deg, var(--qs-primary-deep), var(--qs-primary));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.qs-hero-days {
    margin-top: 10px;
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    padding: 8px 16px;
    border-radius: 12px;
    background: #ffffff;
    border: 1px solid var(--qs-primary-100);
    box-shadow: 0 2px 8px rgba(123, 93, 255, 0.10);
    width: max-content;
    max-width: 100%;
}
.qs-hero-days-num {
    font-size: 1.6rem;
    font-weight: 800;
    color: var(--qs-primary-deep);
    letter-spacing: -0.5px;
}
.qs-hero-days-unit {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--qs-primary-dark);
}
.qs-hero-days.qs-hero-days-none {
    background: rgba(234, 84, 85, 0.08);
    border-color: rgba(234, 84, 85, 0.25);
}
.qs-hero-days.qs-hero-days-none .qs-hero-days-unit { color: #c43536; }

/* Email line under the admin's "Welcome / Admin" title — smaller and
   subtler so it reads as a footnote on the hero. */
.qs-hero-admin-email {
    margin-top: 8px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--qs-primary-dark);
    font-size: 0.92rem;
    font-weight: 500;
    opacity: 0.85;
}
.qs-hero-admin-email i { font-size: 0.92rem; }

/* ---------- Partner directory + per-partner detail ---------- */

/* Round-rect placeholder for partners without a logo URL. Sits in
   the spot a logo image would otherwise occupy. */
.qs-partner-mark {
    display: inline-grid;
    place-items: center;
    width: 28px; height: 28px;
    background: var(--qs-primary-soft);
    color: var(--qs-primary-dark);
    border-radius: 6px;
    font-size: 0.9rem;
}
.qs-partner-mark.big {
    width: 72px; height: 72px;
    font-size: 1.8rem;
    border-radius: 16px;
}

/* Logo image on the per-partner detail hero card. */
.qs-partner-logo {
    width: 72px; height: 72px;
    object-fit: contain;
    border-radius: 16px;
    background: var(--qs-primary-soft);
    padding: 8px;
}

/* Hero strip on the per-partner detail page. */
.qs-partner-hero {
    background: linear-gradient(120deg,
        var(--qs-primary-soft) 0%,
        #ffffff 100%);
    border: 1px solid var(--qs-primary-100);
    border-radius: 18px;
    padding: 20px 22px;
    box-shadow: 0 6px 22px rgba(123, 93, 255, 0.08);
}
.qs-partner-hero h1 {
    font-size: 1.6rem;
    font-weight: 800;
    color: var(--qs-primary-deep);
    margin: 0;
}

/* Stat cards on the per-partner detail page. */
.qs-stat-card {
    background: #ffffff;
    border: 1px solid var(--qs-primary-100);
    border-radius: 14px;
    padding: 16px 18px;
    height: 100%;
    box-shadow: 0 3px 12px rgba(123, 93, 255, 0.06);
}
.qs-stat-card .qs-stat-num {
    font-size: 1.6rem;
    font-weight: 800;
    color: var(--qs-primary-deep);
    line-height: 1;
}
.qs-stat-card .qs-stat-lbl {
    font-size: 0.84rem;
    color: var(--qs-muted);
    margin-top: 6px;
    font-weight: 600;
}
.qs-stat-card.success { background: #ECFDF5; border-color: #A7F3D0; }
.qs-stat-card.success .qs-stat-num { color: #15803D; }
.qs-stat-card.warning { background: #FFFBEB; border-color: #FDE68A; }
.qs-stat-card.warning .qs-stat-num { color: #B45309; }
.qs-stat-card.danger  { background: #FEF2F2; border-color: #FECACA; }
.qs-stat-card.danger  .qs-stat-num { color: #B91C1C; }
.qs-stat-card.primary { background: var(--qs-primary-soft); border-color: var(--qs-primary-100); }
.qs-stat-card.primary .qs-stat-num { color: var(--qs-primary-deep); }

/* ---------- License-keys toolbar + pager ---------- */
.qs-keys-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    background: #faf9ff;
}
.qs-keys-search { flex: 1 1 220px; min-width: 180px; }
.qs-keys-pp-label {
    color: var(--qs-muted);
    font-size: 0.85rem;
    margin: 0 4px 0 4px;
}
.qs-keys-pp { width: auto; min-width: 80px; }

.qs-keys-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px;
    background: #faf9ff;
}
.qs-keys-pager-num,
.qs-keys-pager-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 32px;
    padding: 0 10px;
    border-radius: 8px;
    border: 1px solid var(--qs-primary-100);
    background: #ffffff;
    color: var(--qs-primary-dark);
    font-weight: 600;
    font-size: 0.86rem;
    text-decoration: none;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.qs-keys-pager-num:hover,
.qs-keys-pager-btn:hover {
    background: var(--qs-primary-soft);
    border-color: var(--qs-primary);
    color: var(--qs-primary-deep);
}
.qs-keys-pager-num.active {
    background: var(--qs-primary);
    border-color: var(--qs-primary);
    color: #ffffff;
}
.qs-keys-pager-btn.disabled {
    pointer-events: none;
    opacity: 0.45;
    background: #f3effd;
}
.qs-keys-pager-gap {
    color: var(--qs-muted);
    padding: 0 4px;
    user-select: none;
}

/* Profile tile — keep the column layout but tighten the row spacing
   and let long fields (email, mobile) wrap cleanly. */
.qs-profile-dl dt { padding: 4px 0; }
.qs-profile-dl dd { padding: 4px 0; margin-bottom: 0; word-break: break-word; }

/* Activated! toast — full-width green success card shown on the
   licenses page after a successful license-key redeem. Slides in
   from the top, holds for ~3 s, then fades out (driven by the
   inline <script> in licenses.html). */
.qs-activated-toast {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    margin-bottom: 22px;
    background: linear-gradient(120deg, #16a34a, #15803d);
    color: #ffffff;
    border-radius: 14px;
    box-shadow: 0 6px 22px rgba(22, 163, 74, 0.35);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.3px;
    animation: qs-toast-in 0.45s ease-out;
    transition: opacity 0.6s ease-in, transform 0.6s ease-in;
}
.qs-activated-toast-icon {
    width: 36px; height: 36px;
    display: inline-grid; place-items: center;
    background: rgba(255, 255, 255, 0.20);
    border-radius: 10px;
    font-size: 1.25rem;
}
.qs-activated-toast--out {
    opacity: 0;
    transform: translateY(-12px);
}
@keyframes qs-toast-in {
    from { opacity: 0; transform: translateY(-14px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Password row — masked dots + eye toggle. The eye is a small,
   borderless violet glyph button that swaps the .qs-pwd-mask text
   between the masked dots and the plaintext password (held in
   data-plain). */
.qs-pwd-row {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.qs-pwd-mask {
    font-family: ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
    letter-spacing: 2px;
    color: var(--qs-text);
    font-size: 0.95rem;
    user-select: text;
}
.qs-pwd-eye {
    background: var(--qs-primary-soft);
    border: 1px solid var(--qs-primary-100);
    color: var(--qs-primary-dark);
    border-radius: 6px;
    padding: 2px 8px;
    line-height: 1;
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.qs-pwd-eye:hover {
    background: var(--qs-primary);
    color: #ffffff;
    border-color: var(--qs-primary);
}
.qs-pwd-eye i { font-size: 0.95rem; }

/* ---------- Badges ---------- */
.qs-badge {
    display: inline-block;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.2px;
}
.qs-badge.primary { background: var(--qs-primary-soft); color: var(--qs-primary-dark); }
/* Success badge — solid filled green with white text, bumped opacity
   per user request so the "Active / Approved" badge actually pops in
   the profile card and the dashboard. */
.qs-badge.success { background: #1aae6f; color: #ffffff; }
.qs-badge.warning { background: rgba(255, 159, 67, 0.14); color: #d77324; }
.qs-badge.danger  { background: rgba(234, 84, 85, 0.14);  color: #c43536; }
.qs-badge.muted   { background: var(--qs-border); color: var(--qs-muted); }

/* ---------- Catalog tree ---------- */
/* ── Catalog tree rows ──────────────────────────────────────────
   Two row variants exist:
     .qs-tree-row  — top-level categories on /portal/admin/catalog
     .tree-row     — every nested level (brand → series → model →
                      sub-model → file) inside HTMX partials.
   Both should highlight the FULL row (folder name *and* the action
   buttons strip) in soft theme violet on hover, so the user always
   knows which row their mouse is over. */
.qs-tree-row,
.tree-row {
    padding: 8px 12px;
    border-radius: 9px;
    transition: background 0.12s, box-shadow 0.12s;
}
.qs-tree-row:hover,
.tree-row:hover {
    background: rgba(123, 93, 255, 0.10);
    box-shadow: inset 0 0 0 1px rgba(123, 93, 255, 0.18);
}

.qs-tree-link,
.tree-link {
    color: var(--qs-text);
    text-decoration: none;
    flex-grow: 1;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.qs-tree-link:hover,
.tree-link:hover {
    color: var(--qs-primary-dark);
}

.qs-tree-link i.bi-chevron-right,
.tree-link  i.bi-chevron-right {
    transition: transform 0.15s;
    display: inline-block;
}
.qs-tree-link[aria-expanded="true"] i.bi-chevron-right,
.tree-link[aria-expanded="true"]  i.bi-chevron-right {
    transform: rotate(90deg);
}

/* ---------- Carousel banner ---------- */
.qs-carousel {
    border-radius: 18px;
    overflow: hidden;
    box-shadow: var(--qs-shadow-md);
    background: #fff;
}

.qs-carousel-slide {
    min-height: 360px;
    color: #fff;
    padding: 56px 56px;
    position: relative;
    overflow: hidden;
}

.qs-carousel-slide::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255,255,255,0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px);
    background-size: 30px 30px;
    pointer-events: none;
}

/* All four banners share the SAME brand violet gradient — one cohesive look. */
.qs-carousel-slide.bg-1,
.qs-carousel-slide.bg-2,
.qs-carousel-slide.bg-3,
.qs-carousel-slide.bg-4 {
    background: linear-gradient(135deg, #9881ff 0%, #7b5dff 60%, #5a3fd6 100%);
}

.qs-carousel-slide h2 {
    color: #fff;
    font-size: 2rem;
    font-weight: 700;
    line-height: 1.15;
    margin-bottom: 14px;
    max-width: 620px;
}

.qs-carousel-slide p {
    color: rgba(255, 255, 255, 0.86);
    font-size: 1.05rem;
    max-width: 560px;
    line-height: 1.6;
    margin-bottom: 22px;
}

.qs-carousel-slide .btn {
    background: #fff;
    color: #5e2398;
    font-weight: 600;
    padding: 10px 22px;
    border-radius: 9px;
    border: 0;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.16);
}
.qs-carousel-slide .btn:hover { color: var(--qs-primary-dark); transform: translateY(-1px); }

.qs-carousel-decor {
    position: absolute;
    right: -40px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 12rem;
    color: rgba(255, 255, 255, 0.10);
    pointer-events: none;
    line-height: 1;
}

.carousel-indicators [data-bs-target] {
    width: 28px;
    height: 4px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.5);
    border: 0;
}
.carousel-indicators .active {
    background: #fff;
}

/* ---------- Sub-page hero (services, resellers, etc.) ---------- */
.qs-page-hero {
    background:
        radial-gradient(circle at 70% 0%, rgba(149, 64, 237, 0.08), transparent 50%),
        var(--qs-bg);
    padding: 60px 0 32px;
    border-bottom: 1px solid var(--qs-border);
}

.qs-page-hero h1 {
    font-size: 2.2rem;
    font-weight: 700;
    color: var(--qs-heading);
    letter-spacing: -0.4px;
    margin-bottom: 8px;
}

.qs-page-hero .lead {
    color: var(--qs-muted);
    font-size: 1.08rem;
    max-width: 680px;
    margin: 0;
}

/* ---------- Mobile tweaks ---------- */
@media (max-width: 767px) {
    .qs-hero { padding: 36px 0 48px; }
    .qs-section { padding: 40px 0; }
    .qs-carousel-slide { padding: 32px 28px; min-height: 280px; }
    .qs-carousel-slide h2 { font-size: 1.4rem; }
    .qs-carousel-decor { font-size: 7rem; opacity: 0.7; }
}
