/* ═══════════════════════════════════════════════════════════════════════════
   Qubitry Landing Page — layout, sections, and award-winning styles
   ═══════════════════════════════════════════════════════════════════════════
 *
 * Every section follows this pattern:
 *
 *   section {                              <- full-viewport shell
 *     .fyn-container.fyn-container-wide    <- fyrn container (1280px)
 *       .ql-*-layout                       <- section-specific layout
 *
 * Token reference:
 *   --fy-brand-primary      deep violet (light: oklch(38% 0.15 275))
 *   --fy-duration-fast      150ms
 *   --fy-duration-normal    200ms
 *   --fy-duration-slow      300ms
 *   --fy-easing-standard    cubic-bezier(0.4 0 0.2 1)
 *   --fy-easing-decelerate  cubic-bezier(0 0 0.2 1)
 *   --fy-easing-accelerate  cubic-bezier(0.4 0 1 1)
 *
 * All ql-* classes are scoped to the landing page.
 */

/* ═══════════════════════════════════════════════════════════════════════════
   Self-hosted fonts — eliminates render-blocking Google Fonts request
   ═══════════════════════════════════════════════════════════════════════════ */

/* Font stack tokens — Google Fonts loads Inter, Plus Jakarta Sans, JetBrains Mono, Lora */
:root {
    --fy-font-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --fy-font-heading: 'Lora', 'Plus Jakarta Sans', 'Inter', system-ui, -apple-system, sans-serif;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Global: Smooth scroll & base
   ═══════════════════════════════════════════════════════════════════════════ */

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

:root {
    /* Clearance under the floating pill nav for anchor-jump targets
       (`scroll-margin-top`) — 12px top offset + ~50px pill + breathing room. */
    --ql-anchor-offset: 100px;
}

html {
    scroll-behavior: smooth;
}

body {
    overflow-x: hidden;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Fyrn Container — width constraint + centering (SSOT for landing page)
   Rendered by fyrn_dom::component::container::Container in every section.
   ═══════════════════════════════════════════════════════════════════════════ */

.fyn-container {
    width: 100%;
    margin: 0 auto;
}

.fyn-container-wide {
    max-width: var(--fy-container-width-wide, 1280px);
    padding-left: var(--fy-spacing-padding-lg);
    padding-right: var(--fy-spacing-padding-lg);
}

.fyn-container-page {
    max-width: 960px;
}

.fyn-container-text {
    max-width: 720px;
}

.fyn-container-full {
    max-width: none;
}

.fyn-container-padded {
    padding-left: var(--fy-spacing-padding-md);
    padding-right: var(--fy-spacing-padding-md);
}

/* ═══════════════════════════════════════════════════════════════════════════
   WASM loading overlay — full-screen fixed container.
   Spinner and text inside are rendered by Fyrn components.
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-loading {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--fy-surface-background);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--fy-spacing-gap-md);
    z-index: 9999;
    transition: opacity 0.3s ease-out;
}

.ql-loading .fyn-spinner {
    width: 48px;
    height: 48px;
}

.ql-loading-text {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
}

.ql-loading-error {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-semantic-error);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Navigation — floating pill mega-nav
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-nav {
    position: fixed;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 200;
    width: calc(100% - 32px);
    /* Matches the hero/footer content grid (`--fy-container-width-wide`)
       exactly, so the nav's edges line up with the hero heading and
       terminal card below it instead of floating ~100px narrower. */
    max-width: var(--fy-container-width-wide);
    pointer-events: none;
}

.ql-nav-inner {
    display: flex;
    align-items: center;
    gap: var(--fy-spacing-gap-xs);
    padding: 6px 6px 6px 16px;
    background: var(--fy-surface-background);
    backdrop-filter: blur(20px) saturate(1.6);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-full);
    box-shadow: none;
    pointer-events: auto;
    transition:
        background var(--fy-duration-normal) var(--fy-easing-standard),
        border-color var(--fy-duration-normal) var(--fy-easing-standard),
        box-shadow var(--fy-duration-normal) var(--fy-easing-standard);
}

/* ── Brand lockup ──────────────────────────────────────────────────── */

.ql-nav-brand {
    display: flex;
    align-items: center;
    gap: var(--fy-spacing-gap-sm);
    text-decoration: none;
    flex-shrink: 0;
    color: var(--fy-text-primary);
    margin-right: var(--fy-spacing-gap-sm);
}

.ql-nav-logo-mark {
    height: 30px;
    width: auto;
    display: block;
    flex-shrink: 0;
}

.ql-nav-logo-text {
    height: 19px;
    width: auto;
    display: block;
}

/* ── Centre nav area ───────────────────────────────────────────────── */

.ql-nav-centre {
    display: flex;
    align-items: center;
    gap: 2px;
    flex: 1;
    justify-content: center;
}

/* Nav link (both plain and dropdown triggers) */
.ql-nav-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 7px 12px;
    font-family: var(--fy-font-sans);
    font-size: 13px;
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-secondary);
    text-decoration: none;
    white-space: nowrap;
    border: none;
    background: transparent;
    border-radius: var(--fy-radius-full);
    cursor: pointer;
    line-height: 1;
    transition:
        color var(--fy-duration-fast) var(--fy-easing-standard),
        background var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-link:hover {
    color: var(--fy-text-primary);
    background: var(--fy-surface-alt);
}

.ql-nav-link svg {
    width: 10px;
    height: 10px;
    color: var(--fy-text-tertiary);
    transition:
        transform var(--fy-duration-fast) var(--fy-easing-standard),
        color var(--fy-duration-fast) var(--fy-easing-standard);
}

/* ── Nav dropdown trigger wrapper ──────────────────────────────────── */

.ql-nav-item {
    position: relative;
}

.ql-nav-item--has-dropdown:hover > .ql-nav-link svg,
.ql-nav-item--has-dropdown:focus-within > .ql-nav-link svg {
    transform: rotate(180deg);
    color: var(--fy-text-secondary);
}

/* ── Mega dropdown panel ───────────────────────────────────────────── */

.ql-nav-dropdown {
    position: absolute;
    top: calc(100% + 12px);
    left: 50%;
    transform: translateX(-50%) translateY(-10px) scale(0.97);
    min-width: 520px;
    padding: 10px;
    background: var(--fy-surface-background);
    backdrop-filter: blur(24px) saturate(1.5);
    -webkit-backdrop-filter: blur(24px) saturate(1.5);
    border: 1px solid var(--fy-border);
    border-radius: 18px;
    box-shadow:
        inset 0 1px 0 var(--fy-border);
    filter: blur(4px);
    visibility: hidden;
    pointer-events: none;
    /* Close: blur/scale animate out, then hide */
    transition:
        filter var(--fy-duration-normal) var(--fy-easing-standard),
        transform var(--fy-duration-normal) var(--fy-easing-standard),
        visibility 0ms var(--fy-duration-normal);
}

.ql-nav-item--has-dropdown:hover > .ql-nav-dropdown,
.ql-nav-item--has-dropdown:focus-within > .ql-nav-dropdown {
    visibility: visible;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0) scale(1);
    filter: blur(0px);
    /* Open: show immediately, animate in fast */
    transition:
        filter var(--fy-duration-fast) var(--fy-easing-decelerate),
        transform var(--fy-duration-fast) var(--fy-easing-decelerate),
        visibility 0ms 0ms;
}

/* Bridge element to prevent hover gap */
.ql-nav-item--has-dropdown::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 16px;
}

/* ── Dropdown grid (Product) ───────────────────────────────────────── */

.ql-nav-dropdown-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px;
}

.ql-nav-dropdown-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 10px;
    border-radius: 12px;
    text-decoration: none;
    color: var(--fy-text-primary);
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        box-shadow var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-dropdown-item:hover {
    background: var(--fy-surface-alt);
    box-shadow: inset 0 0 0 1px var(--fy-border);
}

.ql-nav-dropdown-item:hover .ql-nav-dropdown-icon {
    background: var(--fy-surface-alt);
    border-color: var(--fy-border-accent);
}

.ql-nav-dropdown-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--fy-radius-md);
    background: var(--fy-surface-alt);
    border: 1px solid var(--fy-border);
    flex-shrink: 0;
    color: var(--fy-brand-primary);
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        border-color var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-dropdown-text {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.ql-nav-dropdown-title {
    font-size: 13px;
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-primary);
    line-height: 1.25;
    letter-spacing: -0.01em;
}

.ql-nav-dropdown-desc {
    font-size: 12px;
    color: var(--fy-text-secondary);
    line-height: 1.45;
}

/* ── Dropdown section label ────────────────────────────────────────── */

.ql-nav-dropdown-section-label {
    font-size: 10px;
    font-weight: var(--fy-font-weight-semibold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--fy-text-tertiary);
    padding: 2px 10px 10px;
    margin: 0;
    border-bottom: 1px solid var(--fy-border);
    margin-bottom: 4px;
}

/* ── Compact dropdown (Developers) ─────────────────────────────────── */

.ql-nav-dropdown--compact {
    min-width: 200px;
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.ql-nav-dropdown-link {
    display: block;
    padding: 8px 12px;
    font-size: 13px;
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-secondary);
    text-decoration: none;
    border-radius: var(--fy-radius-md);
    transition:
        color var(--fy-duration-fast) var(--fy-easing-standard),
        background var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-dropdown-link:hover {
    color: var(--fy-text-primary);
    background: var(--fy-surface-alt);
}

.ql-nav-dropdown-link--disabled {
    cursor: default;
    opacity: 0.55;
    pointer-events: none;
}

.ql-nav-mobile-link--disabled {
    cursor: default;
    opacity: 0.55;
    pointer-events: none;
    display: flex;
    align-items: center;
    padding: 9px 12px;
    font-size: var(--fy-font-size-sm);
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-secondary);
    text-decoration: none;
    border-radius: var(--fy-radius-md);
}

.ql-footer-link-disabled {
    cursor: default;
    opacity: 0.55;
    pointer-events: none;
    display: inline-block;
    width: fit-content;
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    text-decoration: none;
    padding: 2px 0;
    position: relative;
}

.ql-badge-coming-soon {
    display: inline-block;
    font-size: 10px;
    font-weight: var(--fy-font-weight-semibold);
    letter-spacing: var(--fy-letter-spacing-wider);
    text-transform: uppercase;
    padding: 1px 5px;
    border-radius: var(--fy-radius-sm);
    background: color-mix(in oklch, var(--fy-brand-primary) 15%, transparent);
    color: var(--fy-brand-primary);
    vertical-align: middle;
    margin-left: 4px;
    line-height: 1.4;
}

/* ── Right-side actions ────────────────────────────────────────────── */

.ql-nav-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    margin-left: var(--fy-spacing-gap-sm);
}

/* Ghost icon button (GitHub) */
.ql-nav-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    color: var(--fy-text-tertiary);
    text-decoration: none;
    transition:
        color var(--fy-duration-fast) var(--fy-easing-standard),
        background var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-icon-btn svg {
    width: 16px;
    height: 16px;
}

.ql-nav-icon-btn:hover {
    color: var(--fy-text-primary);
    background: var(--fy-surface-alt);
}

/* Nav CTA button override for pill shape */
.ql-nav-cta {
    border-radius: var(--fy-radius-full);
    font-size: 13px;
    padding: 6px 14px;
    min-height: 32px;
    flex-shrink: 0;
}

/* ── Mobile hamburger ──────────────────────────────────────────────── */

.ql-nav-hamburger {
    display: none;
    background: none;
    border: none;
    color: var(--fy-text-primary);
    cursor: pointer;
    padding: 6px;
    line-height: 0;
    border-radius: var(--fy-radius-md);
    transition: background var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-hamburger:hover {
    background: var(--fy-surface-alt);
}

/* ── Legacy aliases ────────────────────────────────────────────────── */

.ql-nav-links {
    display: none;
}

/* ── Nav responsive ────────────────────────────────────────────────── */

@media (max-width: 900px) {
    .ql-nav {
        top: 8px;
        width: calc(100% - 16px);
    }

    .ql-nav-inner {
        padding: 6px 8px 6px 14px;
    }

    .ql-nav-centre {
        display: none;
    }

    .ql-nav-actions {
        display: none;
    }

    .ql-nav-hamburger {
        display: flex;
        margin-left: auto;
    }
}

/* On very small screens, compress nav pill further */
@media (max-width: 360px) {
    .ql-nav {
        width: calc(100% - 12px);
    }
}

/* ── Mobile navigation panel ──────────────────────────────────────────── */

.ql-nav-mobile {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    right: 0;
    background: var(--fy-surface-background);
    backdrop-filter: blur(20px) saturate(1.4);
    -webkit-backdrop-filter: blur(20px) saturate(1.4);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    box-shadow: none;
    padding: var(--fy-spacing-padding-md);
    display: flex;
    flex-direction: column;
    gap: 6px;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    pointer-events: none;
    transition:
        opacity var(--fy-duration-normal) var(--fy-easing-decelerate),
        transform var(--fy-duration-normal) var(--fy-easing-decelerate),
        visibility var(--fy-duration-normal);
}

.ql-nav-mobile.ql-nav-mobile--open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
}

/* Only visible on mobile */
@media (min-width: 901px) {
    .ql-nav-mobile { display: none; }
}

/* Scroll lock when mobile nav is open */
html.ql-nav-open {
    overflow: hidden;
}

.ql-nav-mobile-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ql-nav-mobile-group-title {
    font-size: 10px;
    font-weight: var(--fy-font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fy-text-tertiary);
    padding: 4px 12px 2px;
    margin: 0;
}

.ql-nav-mobile-link {
    display: flex;
    align-items: center;
    padding: 9px 12px;
    font-size: var(--fy-font-size-sm);
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-secondary);
    text-decoration: none;
    border-radius: var(--fy-radius-md);
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        color var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-nav-mobile-link:hover {
    background: var(--fy-surface-alt);
    color: var(--fy-text-primary);
}

.ql-nav-mobile-sep {
    height: 1px;
    background: var(--fy-border);
    margin: 4px 0;
    border: none;
}

.ql-nav-mobile-cta {
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--fy-radius-full);
    font-size: var(--fy-font-size-sm);
    padding: 10px 20px;
    text-decoration: none;
    text-align: center;
    margin-top: 4px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Scroll reveal animation
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes ql-fade-up {
    from {
        opacity: 0;
        transform: translateY(24px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes ql-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Global eyebrow label and section utilities
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-eyebrow,
.ql-hero-eyebrow {
    display: inline-block;
    font-size: var(--fy-font-size-xs);
    font-weight: var(--fy-font-weight-semibold);
    letter-spacing: var(--fy-letter-spacing-wider);
    text-transform: uppercase;
    color: var(--fy-brand-primary);
    text-shadow: 0 0 16px color-mix(in oklch, var(--fy-brand-primary) 60%, transparent);
    margin: 0 0 var(--fy-spacing-gap-sm);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Section shells
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-page {
    display: flex;
    flex-direction: column;
}

/* SSOT for vertical section rhythm: this is the ONLY place standard
   content sections should get vertical padding (96px desktop, 64px at
   ≤640px below). Section-specific inner content wrappers
   (`.ql-brief`, `.ql-features-layout`, `.ql-cta-content`, etc.) must NOT
   add their own vertical padding — doing so stacks on top of this rule
   and produces inconsistent gaps between sections (audited: previously
   ranged from 192px to 288px depending on which section had a leftover
   wrapper padding, instead of a single deliberate rhythm). Sections that
   genuinely need a different rhythm (Hero, full-bleed colour sections)
   should override this rule directly on their own `.ql-section--*` class,
   once, rather than adding a second padding source inside. */
.ql-section {
    min-height: auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--fy-spacing-stack-3xl) 0;
    /* Clear the floating pill nav when this section is an anchor-jump
       target (nav/footer deep links, e.g. #interactive, #feature-ampligrid). */
    scroll-margin-top: var(--ql-anchor-offset);
}

@media (max-width: 640px) {
    .ql-section {
        padding: var(--fy-spacing-stack-2xl) 0;
    }


}



/* Section header — shared across features, testimonials, etc. */
.ql-section-header {
    max-width: 720px;
    margin: 0 auto var(--fy-spacing-stack-xl);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--fy-spacing-gap-sm);
}

/* Extends fyn-heading styles with Qubitry-specific sizing and spacing */
.ql-section-title {
    font-family: var(--fy-font-heading);
    font-size: clamp(1.75rem, 3vw, 2.25rem);
    font-weight: 500;
    color: var(--fy-text-primary);
    line-height: 1.2;
    margin: 0;
    letter-spacing: -0.028em;
    text-wrap: balance;
    text-align: center;
}

/* Extends fyn-text styles with section-specific subtitle treatment */
.ql-section-sub {
    color: var(--fy-text-secondary);
    max-width: 55ch;
    line-height: 1.6;
    margin: 0;
}

@media (max-width: 480px) {
    .ql-section-sub {
        font-size: 14px;
    }

    .ql-section-header {
        margin: 0 auto var(--fy-spacing-stack-lg);
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   1. Hero section — full viewport, soft gradient, 2-col layout
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-section--hero {
    min-height: 100dvh;
    padding: 0;
    position: relative;
    overflow: hidden;
}

.ql-hero-layout {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    width: 100%;
    min-height: 100dvh;
}

/* Content: two rows stacked — text above, chart below */
.ql-hero-content {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 64px;
    padding: 120px 0 80px;
    max-width: var(--fy-container-width-wide);
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
}

/* ── Hero text column ────────────────────────────────────────────── */

.ql-hero-text {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--fy-spacing-gap-lg);
    max-width: var(--fy-container-width-page);
    width: 100%;
    min-width: 0;
}

/* Pill badge: green dot + text — elevated glassmorphism style */
.ql-hero-badge {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 18px 7px 12px;
    border: 1px solid oklch(62% 0.16 275 / 0.3);
    border-radius: var(--fy-radius-full);
    background: linear-gradient(
        135deg,
        oklch(38% 0.15 275 / 0.10) 0%,
        oklch(55% 0.22 240 / 0.06) 100%
    );
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    font-size: 13px;
    font-weight: 500;
    color: var(--fy-text-secondary);
    width: fit-content;
    line-height: 1.2;
    flex-shrink: 0;
    letter-spacing: 0.01em;
}




/* Heading — two-tier composition rather than one uniform 800-weight
   block. The lead line is deliberately smaller and lighter (a "kicker"
   that sets up the sentence); the differentiator phrase lands large,
   heavy and gradient-lit on its own line, so the eye has one clear
   landing point instead of scanning four equal-weight lines. */
.ql-hero-heading {
    font-family: var(--fy-font-heading);
    font-size: clamp(2.75rem, 5.6vw, 4.75rem);
    font-weight: 700;
    color: var(--fy-text-primary);
    line-height: 1.04;
    letter-spacing: -0.055em;
    margin: 0;
    text-wrap: balance;
}

.ql-hero-heading-lead {
    display: block;
    font-size: max(0.40em, 1rem);
    font-weight: 500;
    letter-spacing: -0.015em;
    line-height: 1.3;
    margin-bottom: 0.22em;
}

.ql-hero-accent {
    font-weight: 800;
    position: relative;
    background-image:
        radial-gradient(ellipse at 50% 50%, oklch(55% 0.22 240 / 0.45) 0%, transparent 50%),
        url('/assets/47.webp');
    background-size: 200% auto;
    background-position: 50% 50%;
    background-repeat: no-repeat;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    animation: ql-hero-accent-shimmer 20s ease-in-out infinite;
    filter:
        drop-shadow(0 0 30px oklch(60% 0.25 285 / 0.55))
        drop-shadow(0 0 80px oklch(55% 0.22 275 / 0.25));
}

@keyframes ql-hero-accent-shimmer {
    0%   { background-position: 0% 0%; }
    25%  { background-position: 100% 0%; }
    50%  { background-position: 100% 100%; }
    75%  { background-position: 0% 100%; }
    100% { background-position: 0% 0%; }
}

@media (prefers-reduced-motion: reduce) {
    .ql-hero-accent {
        animation: none;
        background-position: 50% 50%;
    }
}

/* Subheadline */
.ql-hero-sub {
    color: var(--fy-text-secondary);
    line-height: 1.65;
    max-width: 70ch;
    margin: 0;
}

/* Trust strip */
.ql-hero-sub {
    color: var(--fy-text-secondary);
    line-height: 1.65;
    max-width: 70ch;
    margin: 0;
}
/* ── Scroll cue ──── an animated brand line at the bottom centre of
   the hero viewport, inviting the user to scroll down. */
.ql-hero-scroll-cue {
    position: absolute;
    bottom: 28px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.ql-hero-scroll-line {
    display: block;
    width: 1.5px;
    height: 44px;
    background: linear-gradient(
        to bottom,
        var(--fy-brand-primary) 0%,
        transparent 100%
    );
    transform-origin: top center;
    animation: ql-scroll-drop 2.2s var(--fy-easing-decelerate) infinite;
}

@keyframes ql-scroll-drop {
    0%   { transform: scaleY(0); opacity: 1; }
    65%  { transform: scaleY(1); opacity: 1; }
    100% { transform: scaleY(1); opacity: 0; }
}

/* Hero chart row — full-width container below text */
/* Chart image block — reusable SSOT for benchmark/screenshot images.
   Any section can use .ql-chart-wrap > .ql-chart-img to render a
   consistently-styled image card. */
.ql-chart-row {
    width: 100%;
    display: flex;
    justify-content: center;
}

.ql-chart-wrap {
    padding: var(--fy-spacing-padding-xs);
    border-radius: var(--fy-radius-xl);
    background: var(--fy-surface);
    border: 1px solid var(--fy-border);
    width: 100%;
    max-width: var(--fy-container-width-page);
    box-sizing: border-box;
}

.ql-chart-img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--fy-radius-lg);
    cursor: pointer;
}

/* Click-to-zoom lightbox — created at runtime by WASM mount_image_lightbox() */
.ql-lightbox {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: oklch(0% 0 0 / 0.88);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: zoom-out;
}

.ql-lightbox-img {
    max-width: 92vw;
    max-height: 90vh;
    background: var(--fy-surface);
    padding: var(--fy-spacing-padding-xl);
    border-radius: var(--fy-radius-xl);
    box-shadow: var(--fy-shadow-xl);
    cursor: default;
}

.ql-lightbox-close {
    position: absolute;
    top: 20px;
    right: 24px;
    background: none;
    border: none;
    color: oklch(100% 0 0 / 0.7);
    font-size: 32px;
    line-height: 1;
    cursor: pointer;
}

/* ── Hero responsive ─────────────────────────────────────────────── */

@media (max-width: 900px) {
    .ql-hero-content {
        flex-direction: column;
        padding: 100px 0 60px;
        gap: 40px;
        align-items: flex-start;
    }

    .ql-hero-text {
        flex: 1 1 100%;
        max-width: none;
    }

    .ql-hero-heading {
        font-size: clamp(3.25rem, 11vw, 3.5rem);
    }
}

@media (max-width: 480px) {
    .ql-hero-content {
        padding: 88px 0 40px;
        gap: 32px;
    }

    .ql-hero-sub {
        font-size: 15px;
    }
}

/* Hide all float chips in single-column mobile layout */
@media (max-width: 640px) {
    .ql-hero-scroll-cue {
        display: none;
    }
}

/* Extra-small mobile hero refinements */
@media (max-width: 480px) {
    .ql-hero-sub {
        max-width: none;
    }
}
    .ql-hero-scroll-line {
        animation: none;
        opacity: 0.35;
        transform: scaleY(1);
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   3. Brief section + stats
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-section--brief {
    position: relative;
    overflow: hidden;
    align-items: center;
    text-align: center;
}

/* Subtle background glow behind the numbers — radial gradient
   reinforces the "concentrated capability" theme. */
.ql-section--brief::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 900px;
    height: 600px;
    background: radial-gradient(
        ellipse at center,
        oklch(38% 0.15 275 / 0.04) 0%,
        oklch(55% 0.22 240 / 0.02) 35%,
        transparent 70%
    );
    pointer-events: none;
}




/* No vertical padding here — the section's own base padding (see
   `.ql-section`) is the single source of vertical rhythm. Adding a second
   one here previously stacked to 160px top/bottom vs. 96px everywhere
   else, an accidental inconsistency rather than a deliberate one. */
.ql-brief {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: var(--fy-spacing-gap-xl);
    position: relative;
}

/* Headline stats — CSS Grid container. 3 columns >480px, 1 column ≤480px.
   No nested flex wrapper: items sit directly in the grid for zero extra
   nesting. `justify-items: center` aligns every stat-item to the column
   centre. */
.ql-stats-block {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--fy-spacing-gap-2xl);
    justify-items: center;
    width: 100%;
}

.ql-stat-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--fy-spacing-gap-xs);
    position: relative;
    width: 100%;
}

.ql-stat-number {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-hero);
    font-weight: var(--fy-font-weight-extrabold);
    line-height: 1;
    letter-spacing: var(--fy-letter-spacing-tightest);
    color: var(--fy-text-primary);
}

/* All three headline stats are inline SVGs with their own gradients.
   The SVG's viewBox + font-size are calibrated so the rendered
   height matches --fy-font-size-hero when the SVG container is
   sized to that value. */
.ql-stat-number--svg {
    display: inline-block;
}

.ql-stat-number--svg svg {
    display: block;
    /* Fluid scaling between the 480px hard-minimum and the desktop hero
       size removes the abrupt jump that a single breakpoint would cause;
       the viewport crosses this range continuously between roughly
       750px and 1280px, and sits at the floor below that. */
    height: clamp(1.75rem, 3.75vw, var(--fy-font-size-hero));
    width: auto;
    max-width: 100%;
}

.ql-stat-label {
    font-size: var(--fy-font-size-xs);
    color: var(--fy-text-secondary);
    text-transform: uppercase;
    letter-spacing: var(--fy-letter-spacing-wide);
    text-align: center;
    width: 100%;
    text-wrap: balance;
}

.ql-stat-badge {
    display: inline-block;
    padding: 3px 12px;
    border-radius: var(--fy-radius-full);
    background: linear-gradient(
        135deg,
        oklch(38% 0.15 275 / 0.08) 0%,
        oklch(55% 0.22 240 / 0.04) 100%
    );
    border: 1px solid oklch(62% 0.16 275 / 0.2);
    font-family: var(--fy-font-mono);
    font-size: 11px;
    font-weight: 500;
    color: var(--fy-text-tertiary);
    letter-spacing: 0.02em;
}

/* Secondary stats row — card-style with inline SVG icons.
   Each stat gets a subtle card background with hover lift so the
   eye can distinguish them at a glance. */

.ql-stat-secondary {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--fy-spacing-gap-xs);
    padding: 12px 20px;
    border-radius: var(--fy-radius-lg);
    background: oklch(38% 0.15 275 / 0.03);
    transition: background var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-stat-secondary:hover {
    background: oklch(38% 0.15 275 / 0.07);
}

.ql-stat-secondary-icon {
    color: var(--fy-text-tertiary);
    opacity: 0.55;
    transition: opacity var(--fy-duration-fast) var(--fy-easing-standard),
                color var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-stat-secondary:hover .ql-stat-secondary-icon {
    opacity: 0.85;
    color: var(--fy-brand-primary);
}

.ql-stat-secondary-number {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-bold);
    line-height: 1.15;
    color: var(--fy-text-primary);
    transition: color var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-stat-secondary:hover .ql-stat-secondary-number {
    color: var(--fy-brand-primary);
}

.ql-stat-secondary-label {
    font-size: var(--fy-font-size-xs);
    color: var(--fy-text-tertiary);
    letter-spacing: var(--fy-letter-spacing-wide);
    text-transform: uppercase;
    text-align: center;
}

.ql-stats-row--secondary {
    gap: var(--fy-spacing-gap-xl);
    padding-top: var(--fy-spacing-stack-md);
    position: relative;
}

.ql-stats-row--secondary::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--fy-border) 20%,
        var(--fy-border) 80%,
        transparent 100%
    );
    pointer-events: none;
}

/* ── Brief responsive ────────────────────────────────────────────── */

@media (max-width: 768px) {
    /* Secondary stats: 4 items → 2×2 grid. */
    .ql-stats-row--secondary {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--fy-spacing-gap-lg);
        justify-items: center;
    }

    .ql-stat-item {
        padding: 0;
    }

    .ql-stat-secondary {
        padding: 10px 14px;
    }
}

@media (max-width: 640px) {
    /* Background glow: shrink to viewport width, lower opacity for mobile */
    .ql-section--brief::before {
        width: 100vw;
        max-width: 640px;
        opacity: 0.6;
    }
}

@media (max-width: 480px) {
    /* Headline stats: 3-col → 1-col, stacked vertically. */
    .ql-stats-block {
        grid-template-columns: 1fr;
        gap: var(--fy-spacing-gap-xl);
    }

    .ql-stats-row--secondary {
        grid-template-columns: 1fr 1fr;
        row-gap: var(--fy-spacing-gap-md);
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   4. Features — Bento grid
   ═══════════════════════════════════════════════════════════════════════════ */





/* No explicit background override — shares the page's default background
   with every other standard content section (Signature, Algorithms),
   rather than an arbitrary lighter tint that happened to only land on
   two of the six content sections and broke any alternating rhythm. */

/* Gradient treatment for eyebrow text in the features section */
.ql-section--features .ql-eyebrow {
    background: linear-gradient(
        90deg,
        var(--fy-brand-primary) 0%,
        var(--fy-brand-primary) 100%
    );
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* No vertical padding here — same single-source-of-rhythm rule as
   `.ql-brief` above; the section's own base padding is authoritative. */
.ql-features-layout {
    display: flex;
    flex-direction: column;
}

/* ── Bento grid — capabilities bento (2026) ─────────────────────────── */

.ql-bento-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: auto auto;
    gap: var(--fy-spacing-gap-lg);
    align-items: stretch;
    position: relative;
}

/* Card placement — desktop 3-column asymmetric grid. */
.ql-bento-decoder     { grid-area: 1 / 1 / 2 / 3; }
.ql-bento-discovery   { grid-area: 1 / 3 / 2 / 4; }
.ql-bento-qml         { grid-area: 2 / 1 / 3 / 2; }
.ql-bento-chemistry   { grid-area: 2 / 2 / 3 / 4; }

/* Background images per bento block — cover the full card area. */
.ql-bento-decoder     { background-image: url('/assets/neural-decoder.webp'); }
.ql-bento-discovery   { background-image: url('/assets/autonomous-drug-discovery.webp'); }
.ql-bento-qml         { background-image: url('/assets/ml.webp'); }
.ql-bento-chemistry   { background-image: url('/assets/chemistry.webp'); }

.ql-bento-card {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 0;
    padding: var(--fy-spacing-padding-xl);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-color: var(--fy-surface);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    overflow: hidden;
    min-height: 384px;
}

/* Text content wrapper — sits at the bottom of the card above the
   overlay gradient. margin-top: auto pushes to the bottom of the
   flex column; z-index places it above the ::after overlay. */
.ql-bento-content {
    margin-top: auto;
    position: relative;
    z-index: 1;
}

/* Text-readability overlay: solid surface colour at the bottom where
   text sits, fading to transparent at the top where the image shows. */
.ql-bento-card::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to top,
        var(--fy-surface) 0%,
        var(--fy-surface) 45%,
        transparent 100%
    );
    pointer-events: none;
    z-index: 0;
    border-radius: inherit;
}

/* Scroll-reveal entrance animation — staggered via inline --delay */
.ql-bento-card[data-reveal="bento"] {
    opacity: 0;
    transform: translateY(24px);
    transition:
        opacity var(--fy-duration-slow) var(--fy-easing-decelerate) var(--delay, 0ms),
        transform var(--fy-duration-slow) var(--fy-easing-decelerate) var(--delay, 0ms);
}

.ql-bento-card[data-reveal="bento"].ql-reveal--visible {
    opacity: 1;
    transform: translateY(0);
}

.ql-bento-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    background: var(--fy-surface-alt);
    border: 1px solid var(--fy-border-accent);
    border-radius: var(--fy-radius-lg);
    flex-shrink: 0;
    box-shadow:
        inset 0 1px 0 var(--fy-border);
    margin-bottom: 18px;
    position: relative;
    z-index: 1;
}

.ql-bento-icon svg {
    color: var(--fy-brand-primary);
}

.ql-bento-title {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: 0 0 10px;
    line-height: 1.22;
    letter-spacing: -0.022em;
    position: relative;
    z-index: 1;
}

.ql-bento-title--wide {
    font-size: clamp(1.3rem, 2.2vw, 1.625rem);
    letter-spacing: -0.03em;
}

.ql-bento-desc {
    font-size: 0.9375rem;
    color: var(--fy-text-secondary);
    margin: 0;
    line-height: 1.65;
    position: relative;
    z-index: 1;
}

/* Metric chips row */
.ql-bento-metrics {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
    position: relative;
    z-index: 1;
}

.ql-bento-metric-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px;
    border-radius: var(--fy-radius-full);
    background: var(--fy-surface-alt);
    border: 1px solid var(--fy-border);
    font-size: 11px;
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-secondary);
    font-family: var(--fy-font-mono);
    line-height: 1.4;
}

.ql-bento-metric-chip strong {
    color: var(--fy-brand-primary);
    font-weight: var(--fy-font-weight-bold);
}

/* Tech badge row — used on wide card */
.ql-bento-tech-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: auto;
    padding-top: 20px;
    position: relative;
    z-index: 1;
}

/* ── AmpliGrid dark inverted card ────────────────────────────────────── */

/* ── Bento responsive ────────────────────────────────────────────────────
   All breakpoints AFTER theme overrides so they win in the cascade.
   ──────────────────────────────────────────────────────────────────────── */



/* Tablet (641px – 1024px): 2-column grid, cards reflow */
@media (max-width: 1024px) and (min-width: 641px) {
    .ql-bento-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--fy-spacing-gap-md);
    }

    .ql-bento-decoder     { grid-area: 1 / 1 / 2 / 3; }
    .ql-bento-discovery   { grid-area: 2 / 1 / 3 / 2; }
    .ql-bento-qml         { grid-area: 2 / 2 / 3 / 3; }
    .ql-bento-chemistry   { grid-area: 3 / 1 / 4 / 3; }
}

/* Mobile (≤640px): single column, 5-row stack */
@media (max-width: 640px) {
    .ql-bento-grid {
        grid-template-columns: 1fr;
        gap: var(--fy-spacing-gap-md);
    }

    .ql-bento-card {
        padding: var(--fy-spacing-padding-lg);
    }

    .ql-bento-decoder     { grid-area: 1 / 1 / 2 / 2; }
    .ql-bento-discovery   { grid-area: 2 / 1 / 3 / 2; }
    .ql-bento-qml         { grid-area: 3 / 1 / 4 / 2; }
    .ql-bento-chemistry   { grid-area: 4 / 1 / 5 / 2; }

    .ql-bento-icon {
        margin-bottom: 12px;
    }
}

/* ───────────────────────────────────────────────────────────────────────────
   Section 2b: Signature feature — AmpliGrid spotlight

   A dedicated, larger-than-a-bento-card moment for the platform's rarest
   differentiator, rather than one of five equally-weighted feature cards.
   The dark, glowing gradient treatment previously lived on the AmpliGrid
   bento card; it now belongs to this section instead — the signature
   capability keeps the most premium visual treatment on the page.
   ─────────────────────────────────────────────────────────────────────────── */

/* ═══════════════════════════════════════════════════════════════════════════
   4. Features — Bento grid
/* ── Bento responsive ────────────────────────────────────────────────────
/* Glowing pivot orb — the moment of choice between two paths */
.ql-amp-plus {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: linear-gradient(
        135deg,
        oklch(22% 0.08 268),
        oklch(20% 0.08 275)
    );
    border: 1px solid oklch(55% 0.18 275 / 0.3);
    color: oklch(78% 0.14 275);
    font-size: 1.25rem;
    font-weight: var(--fy-font-weight-bold);
    line-height: 1;
    user-select: none;
    align-self: center;
}

/* ── Verified badge ───────────────────────────────────────── */


@media (max-width: 900px) {
    .ql-signature-grid {
        grid-template-columns: 1fr;
        gap: var(--fy-spacing-gap-xl);
    }

    .ql-amp-compare {
        grid-template-columns: 1fr;
    }

    .ql-amp-plus {
        justify-self: center;
    }
}

@media (max-width: 480px) {
    .ql-ampligrid-explorer {
        padding: var(--fy-spacing-padding-lg);
    }

    .ql-amp-qubit-num {
        font-size: 1.75rem;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   5. CTA section — saturated Lapis colour block, own background

   The closing statement's climax comes from bold, saturated brand colour
   rather than a dark/black theme. This is a self-contained colour block —
   the footer below it is a separate, plain section with no shared
   background. Decorative layers (grid, clouds, ascii, grain) are direct
   children of `.ql-section--cta`, siblings of the container rather than
   nested inside it, so the pattern is full-bleed with no rectangular
   seam (the same approach the hero uses).
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-section--cta {
    position: relative;
    overflow: hidden;
    /* Lapis-dominant base — brand hue stays the majority of the gradient,
       just varying in hue/lightness within the violet family. Straight
       vertical (180deg), not diagonal: a diagonal gradient's bottom edge
       isn't a flat colour band (it varies left-to-right), so it can never
       line up cleanly with the footer's own vertical gradient below it.
       180deg guarantees the bottom edge is a uniform band that matches
       the footer's top edge exactly — no seam. */
    background: linear-gradient(
        180deg,
        oklch(44% 0.17 268) 0%,
        oklch(38% 0.155 279) 45%,
        oklch(33% 0.135 288) 100%
    );
}



/* Hairline checker grid — the structural "pattern" a flat colour field
   needs to read as considered rather than basic. Faint graph-paper lines,
   feathered out top and bottom via mask so they don't hard-cut at the
   section's edges. */
.ql-cta-grid {
    position: absolute;
    inset: 0;
    z-index: 0;
    background-image:
        linear-gradient(oklch(100% 0 0 / 0.06) 1px, transparent 1px),
        linear-gradient(90deg, oklch(100% 0 0 / 0.06) 1px, transparent 1px);
    background-size: 56px 56px;
    -webkit-mask-image: linear-gradient(180deg, transparent, oklch(0% 0 0) 14%, oklch(0% 0 0) 86%, transparent);
    mask-image: linear-gradient(180deg, transparent, oklch(0% 0 0) 14%, oklch(0% 0 0) 86%, transparent);
    pointer-events: none;
}

/* Soft cloud blooms — large, feathered highlights that read as painted
   light rather than a cluster of small saturated dots. Bottom-fade mask
   tapers density before the footer boundary, so the footer's own
   (differently-positioned, lower-opacity) clouds pick up gradually
   rather than the two colliding at a hard cut line. */
.ql-cta-clouds {
    position: absolute;
    inset: -10%;
    z-index: 0;
    background-image:
        radial-gradient(ellipse 55% 42% at 16% 10%, oklch(100% 0 0 / 0.18) 0%, transparent 72%),
        radial-gradient(ellipse 50% 40% at 88% 72%, oklch(100% 0 0 / 0.14) 0%, transparent 72%),
        radial-gradient(ellipse 46% 46% at 58% 46%, oklch(80% 0.09 250 / 0.22) 0%, transparent 70%);
    -webkit-mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 80%, transparent 100%);
    mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 80%, transparent 100%);
    pointer-events: none;
}

/* Subtle ASCII texture — scattered monospace code/qubit notation
   (binary, register ops, gate calls) tiled at very low opacity. A nod to
   the product itself (the hero's code editor mock) rather than generic
   stroked iconography — quiet enough to read as texture, not a message. */
.ql-cta-ascii {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0.09;
    mix-blend-mode: overlay;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Ctext x='8' y='22' font-family='monospace' font-size='11' fill='white'%3E01001010%3C/text%3E%3Ctext x='150' y='18' font-family='monospace' font-size='11' fill='white'%3E10%3C/text%3E%3Ctext x='18' y='64' font-family='monospace' font-size='11' fill='white'%3Eqc()%3C/text%3E%3Ctext x='150' y='60' font-family='monospace' font-size='11' fill='white'%3E0x1F%3C/text%3E%3Ctext x='60' y='98' font-family='monospace' font-size='11' fill='white'%3EH(0)%3C/text%3E%3Ctext x='10' y='134' font-family='monospace' font-size='11' fill='white'%3E01%3C/text%3E%3Ctext x='128' y='124' font-family='monospace' font-size='11' fill='white'%3ECNOT%3C/text%3E%3Ctext x='30' y='164' font-family='monospace' font-size='11' fill='white'%3E10110%3C/text%3E%3Ctext x='150' y='178' font-family='monospace' font-size='11' fill='white'%3E-%3E1%3C/text%3E%3Ctext x='68' y='205' font-family='monospace' font-size='11' fill='white'%3E00%3C/text%3E%3C/svg%3E");
    background-size: 220px 220px;
    background-repeat: repeat;
    -webkit-mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 80%, transparent 100%);
    mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 80%, transparent 100%);
}

/* Grain — fractal-noise SVG filter (no binary asset), blended over the
   gradient at very low opacity. This *is* the modern pattern language for
   colour sections right now (Stripe/Linear-era “grainy gradient mesh”) —
   deliberate texture, not decoration, and nothing that reads as dated
   stroked line-art. */
.ql-cta-grain {
    position: absolute;
    inset: 0;
    z-index: 1;
    opacity: 0.1;
    mix-blend-mode: overlay;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    -webkit-mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 80%, transparent 100%);
    mask-image: linear-gradient(180deg, oklch(0% 0 0) 0%, oklch(0% 0 0) 80%, transparent 100%);
}

/* Asymmetric two-column layout — text anchored left, a validated-qubit
   stat pulled out as its own visual on the right. One genuine layout
   risk for the closing section, instead of another centred column.
   No vertical padding here — the section's own base padding (see
   `.ql-section`) is the single source of rhythm; this previously stacked
   to 192px top/bottom vs. 96px everywhere else. Bold colour, disciplined
   proportions: the CTA stands out through saturation, not through
   breaking the page's own spacing rhythm. */
.ql-cta-content {
    position: relative;
    z-index: 2;
    display: grid;
    grid-template-columns: 1.15fr 0.85fr;
    align-items: center;
    gap: var(--fy-spacing-gap-2xl);
    margin: 0 auto;
    max-width: var(--fy-container-width-page);
    width: 100%;
}

.ql-cta-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    gap: var(--fy-spacing-gap-lg);
}

.ql-cta-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--fy-spacing-gap-xs);
    padding: 5px 14px 5px 10px;
    border: 1px solid oklch(100% 0 0 / 0.32);
    border-radius: var(--fy-radius-full);
    background: oklch(100% 0 0 / 0.14);
    font-size: 12px;
    font-weight: var(--fy-font-weight-semibold);
    color: oklch(100% 0 0 / 0.92);
    width: fit-content;
    line-height: 1;
}


.ql-cta-heading {
    font-family: var(--fy-font-heading);
    font-size: clamp(2rem, 6.5vw, var(--fy-font-size-hero-lg));
    font-weight: var(--fy-font-weight-extrabold);
    color: oklch(100% 0 0);
    margin: 0;
    line-height: 1.02;
    letter-spacing: -0.045em;
    text-wrap: balance;
}

/* Subtle, slow gradient shimmer on the closing word — the background is
   already colourful, so the accent reads as a sweep of *light* (pale
   lavender → white → pale cyan) rather than another hue fighting for
   attention. An 8s ease sweep, frozen for reduced-motion users. */
.ql-cta-heading-accent {
    background: linear-gradient(
        100deg,
        oklch(90% 0.08 275) 0%,
        oklch(93% 0.09 80) 35%,
        oklch(100% 0 0) 50%,
        oklch(93% 0.09 80) 65%,
        oklch(90% 0.08 275) 100%
    );
    background-size: 240% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    animation: ql-cta-shimmer 8s ease-in-out infinite;
}

@keyframes ql-cta-shimmer {
    0%, 100% { background-position: 0% 50%; }
    50%      { background-position: 100% 50%; }
}

.ql-cta-desc {
    font-weight: var(--fy-font-weight-medium);
    color: oklch(100% 0 0 / 0.88);
    margin: 0;
    max-width: 38ch;
    line-height: 1.5;
    letter-spacing: -0.005em;
}

.ql-cta-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-md);
    justify-content: flex-start;
    margin-top: 4px;
}

/* ── Stat visual: a glass panel pulling "43 qubits" out of the description
   as its own hero number ── */
.ql-cta-visual {
    display: flex;
    justify-content: center;
}

.ql-cta-stat-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 4px;
    padding: var(--fy-spacing-padding-2xl) var(--fy-spacing-padding-xl);
    background: oklch(100% 0 0 / 0.07);
    border: 1px solid oklch(100% 0 0 / 0.16);
    border-radius: var(--fy-radius-xl);
    backdrop-filter: blur(20px) saturate(140%);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    box-shadow:
        0 20px 60px -20px oklch(15% 0.05 275 / 0.5),
        inset 0 1px 0 oklch(100% 0 0 / 0.14);
}

.ql-cta-stat-number {
    font-family: var(--fy-font-heading);
    font-size: clamp(3.5rem, 7vw, 5rem);
    font-weight: var(--fy-font-weight-extrabold);
    line-height: 1;
    letter-spacing: -0.04em;
    color: oklch(100% 0 0);
    text-shadow: 0 0 40px oklch(100% 0 0 / 0.35);
}

.ql-cta-stat-label {
    font-size: var(--fy-font-size-md);
    font-weight: var(--fy-font-weight-semibold);
    color: oklch(100% 0 0 / 0.92);
}

.ql-cta-stat-sub {
    font-size: var(--fy-font-size-xs);
    color: oklch(100% 0 0 / 0.6);
    letter-spacing: var(--fy-letter-spacing-wide);
    text-transform: uppercase;
    margin-top: 6px;
}

@media (max-width: 900px) {
    .ql-cta-content {
        grid-template-columns: 1fr;
        gap: var(--fy-spacing-gap-xl);
    }

    .ql-cta-text {
        align-items: center;
        text-align: center;
    }

    .ql-cta-actions {
        justify-content: center;
    }

    .ql-cta-visual {
        order: -1;
    }
}

/* Primary button is inverted — solid white against the saturated colour
   block reads unmistakably as “the one to press”, the same way a white
   button pops on any bold colour background. */
.ql-cta-btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: oklch(99% 0 0);
    color: oklch(38% 0.15 275);
    border-color: transparent;
    box-shadow: 0 10px 28px -10px oklch(15% 0.05 275 / 0.55);
    transition:
        transform var(--fy-duration-fast) var(--fy-easing-standard),
        box-shadow var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-cta-btn-primary:hover {
    background: oklch(100% 0 0);
    transform: translateY(-1px);
    box-shadow: 0 14px 32px -10px oklch(15% 0.05 275 / 0.6);
}

.ql-cta-btn-primary svg {
    transition: transform var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-cta-btn-primary:hover svg {
    transform: translateX(3px);
}

/* ── CTA responsive ───────────────────────────────────── */

@media (max-width: 640px) {
    .ql-cta-content {
        gap: var(--fy-spacing-gap-md);
    }
}

@media (max-width: 640px) {
    .ql-cta-actions {
        flex-direction: column;
        align-items: stretch;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ql-cta-heading-accent {
        animation: none;
        background-position: 50% 50%;
    }

    .ql-cta-btn-primary:hover svg {
        transform: none;
    }
}

/* Consistent CTA button sizing — override fyrn's touch-device bump */


@media (max-width: 480px) {
    .ql-cta-desc {
        max-width: none;
        text-align: center;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   7. Back to top button
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-back-to-top {
    position: fixed;
    bottom: var(--fy-spacing-padding-xl);
    right: var(--fy-spacing-padding-xl);
    z-index: 50;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--fy-surface-raised);
    border: 1px solid var(--fy-border);
    color: var(--fy-text-secondary);
    font-size: var(--fy-font-size-lg);
    cursor: pointer;
    box-shadow: var(--fy-shadow-md);
    opacity: 0;
    pointer-events: none;
    transition:
        opacity var(--fy-duration-normal) var(--fy-easing-standard),
        transform var(--fy-duration-normal) var(--fy-easing-standard),
        box-shadow var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-back-to-top:hover {
    transform: translateY(-2px);
    box-shadow: var(--fy-shadow-lg);
    color: var(--fy-brand-primary);
}

/* Visibility is toggled purely via `.ql-visible` (added/removed by a
   scroll listener — see page.rs). A bare `:not([hidden])` fallback here
   would match by default (the button never carries a `hidden` attribute)
   and defeat the `opacity: 0` above, showing the button permanently from
   page load regardless of scroll position. */
.ql-back-to-top.ql-visible {
    opacity: 1;
    pointer-events: auto;
}

@media (max-width: 480px) {
    .ql-back-to-top {
        width: 40px;
        height: 40px;
        right: 12px;
        bottom: 16px;
    }

    .ql-back-to-top svg {
        width: 16px;
        height: 16px;
    }
}



/* ═══════════════════════════════════════════════════════════════════════════
   9. Interactive tools section
   ═══════════════════════════════════════════════════════════════════════════ */

/* No explicit background override — shares the page's default background
   with the other standard content sections, for the same consistency
   reason as `.ql-section--features` above. */
#interactive {
    position: relative;
    scroll-margin-top: var(--ql-anchor-offset);
}



#interactive .fyn-container {
    position: relative;
    z-index: 1;
}

.ql-tool-row + .ql-tool-row {
    margin-top: var(--fy-spacing-stack-xl);
}

.ql-tool-row {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-lg);
    padding: var(--fy-spacing-padding-xl);
    backdrop-filter: blur(20px) saturate(140%);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    box-shadow: var(--fy-shadow-sm);
    overflow: hidden;
    transition:
        border-color var(--fy-duration-normal) var(--fy-easing-standard),
        box-shadow var(--fy-duration-normal) var(--fy-easing-standard),
        transform var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-tool-row:hover {
    border-color: var(--tool-accent, var(--fy-brand-primary));
    box-shadow: var(--fy-shadow-md);
    transform: translateY(-2px);
}

/* Scroll-reveal entrance animation — staggered via inline --delay, mirrors
   the bento cards' pattern so this flagship section gets the same
   considered first-impression treatment instead of snapping into view. */
.ql-tool-row[data-reveal="tool"] {
    opacity: 0;
    transform: translateY(28px);
    transition:
        opacity var(--fy-duration-slow) var(--fy-easing-decelerate) var(--delay, 0ms),
        transform var(--fy-duration-slow) var(--fy-easing-decelerate) var(--delay, 0ms),
        border-color var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-tool-row[data-reveal="tool"].ql-reveal--visible {
    opacity: 1;
    transform: translateY(0);
}



/* Per-tool accent — three stacked demos otherwise read as identical grey
   panels; a distinct hue per tool (same consistent-lightness OKLCH approach
   used for the algorithm category chips) gives each one its own identity
   at a glance while scrolling past. */
/* All three demos share the Lapis brand hue family (265-288deg) rather than
   three unrelated colours, so the section reads as one cohesive brand
   experience while each tool keeps a subtly distinct identity. */
.ql-tool-row[data-tool="bloch"]   { --tool-accent: oklch(50% 0.15 266); }
.ql-tool-row[data-tool="decoder"] { --tool-accent: oklch(42% 0.16 277); }
.ql-tool-row[data-tool="circuit"] { --tool-accent: oklch(54% 0.13 288); }

/* A quiet "this is live" pulse next to each tool's title — signals that the
   demo below is a running program, not a screenshot, at a glance before a
   visitor even touches it. Same ping pattern as the hero's status badge,
   retinted to each tool's own accent instead of the semantic-success green
   used there for "system online". */
.ql-tool-live-dot {
    position: relative;
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-left: 2px;
    border-radius: 50%;
    background: var(--tool-accent, var(--fy-brand-primary));
    flex-shrink: 0;
}

.ql-tool-header h3 {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-xl);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: 0;
    letter-spacing: var(--fy-letter-spacing-tight);
}

/* A small tool-specific glyph (sphere, neural net, circuit) rather than a
   plain colour dot — ties this section's identity back to the "Features"
   bento icons using the same visual language. */
.ql-tool-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: var(--fy-radius-md);
    background: color-mix(in oklch, var(--tool-accent, var(--fy-brand-primary)) 14%, transparent);
    color: var(--tool-accent, var(--fy-brand-primary));
}

.ql-tool-icon svg {
    width: 18px;
    height: 18px;
}

.ql-tool-header p {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    margin: 4px 0 0;
}



.ql-preset-card {
    position: relative;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--fy-spacing-gap-sm);
    padding: var(--fy-spacing-padding-sm) var(--fy-spacing-padding-md);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-lg);
    cursor: pointer;
    background: var(--fy-surface-alt);
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        border-color var(--fy-duration-fast) var(--fy-easing-standard),
        transform var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-preset-card:hover {
    background: var(--fy-surface);
    border-color: var(--tool-accent, var(--fy-brand-primary));
    transform: translateY(-1px);
}

/* Active state gets a genuine tinted fill, not just a ring — clearer at a
   glance which preset is live when scanning the row. A slow-breathing
   outline (border + opacity, no box-shadow) adds a quiet "currently
   selected" pulse on top. */
.ql-preset-card.ql-preset-active {
    background: color-mix(in oklch, var(--tool-accent, var(--fy-brand-primary)) 8%, var(--fy-surface-alt));
    border-color: var(--tool-accent, var(--fy-brand-primary));
    box-shadow: 0 0 0 1px color-mix(in oklch, var(--tool-accent, var(--fy-brand-primary)) 25%, transparent);
}

/* Text wrapper: stacks label above description vertically. */
.ql-preset-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* Small glyph identifying the preset at a glance — ket notation, a
   severity dot, a gate count — rather than plain text-only rows. Tint
   is mixed with the surface itself (not the accent's own dark base), so
   the chip stays light and calm instead of reading as a muddy dark tile. */
.ql-preset-badge {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: 26px;
    height: 26px;
    padding: 0 4px;
    border-radius: var(--fy-radius-md);
    background: color-mix(in oklch, var(--tool-accent, var(--fy-brand-primary)) 12%, var(--fy-surface));
    color: var(--tool-accent, var(--fy-brand-primary));
    font-family: var(--fy-font-mono);
    font-size: var(--fy-font-size-sm);
    font-weight: var(--fy-font-weight-bold);
}

.ql-preset-dot {
    width: 10px;
    height: 10px;
    border-radius: var(--fy-radius-full);
    background: currentColor;
}

.ql-preset-dot[data-severity="ok"] { color: var(--fy-semantic-success, #4ade80); }
.ql-preset-dot[data-severity="warn"] { color: var(--fy-semantic-warning, #fbbf24); }
.ql-preset-dot[data-severity="error"] { color: var(--fy-semantic-error, #f87171); }

.ql-preset-label {
    font-size: var(--fy-font-size-sm);
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-primary);
}

.ql-preset-card.ql-preset-active .ql-preset-label {
    color: var(--tool-accent, var(--fy-brand-primary));
}

.ql-preset-desc {
    font-size: var(--fy-font-size-xs);
    color: var(--fy-text-tertiary);
}

.ql-tool-result {
    display: none;
}

/* Flattened deliberately: no background/border/shadow of its own. The
   canvas frame below is the one "screen" box; wrapping it in a second,
   separately tinted+bordered panel here just doubled the framing and
   made the whole demo read as boxes-within-boxes rather than one calm
   surface. */
.ql-tool-result.ql-result-active {
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-md);
    flex: 1 1 auto;
}

/* Canvas frame: gives each canvas its own elevated "screen" chrome inside
   the result panel, rather than floating transparently on the flat grey
   background behind it. */
.ql-canvas-frame {
    display: inline-flex;
    flex-shrink: 0;
    padding: var(--fy-spacing-padding-md);
    background: var(--fy-surface);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-lg);
    box-shadow: var(--fy-shadow-sm);
    transition:
        border-color var(--fy-duration-fast) var(--fy-easing-standard),
        box-shadow var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-canvas-frame:hover {
    border-color: var(--tool-accent, var(--fy-brand-primary));
    box-shadow: var(--fy-shadow-md);
}

/* ── Bloch sphere ─────────────────────────────────────────────────────── */

.ql-bloch-layout {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-xl);
    align-items: flex-start;
    padding: var(--fy-spacing-padding-md);
}

.ql-bloch-canvas {
    display: block;
    width: 320px;
    height: 320px;
    flex-shrink: 0;
    cursor: grab;
    touch-action: none;
}

.ql-bloch-canvas:active {
    cursor: grabbing;
}

/* Action buttons row (Measure + Reset) */
.ql-bloch-actions {
    margin-bottom: var(--fy-spacing-stack-sm);
}

.ql-bloch-readout {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-md);
    min-width: 160px;
}

.bloch-readout-grid { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.bloch-readout-section { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.bloch-readout-hint { font-size: var(--fy-font-size-xs); color: var(--fy-text-tertiary); }
.bloch-readout-label { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); font-weight: var(--fy-font-weight-semibold); }
.bloch-readout-row { display: flex; gap: var(--fy-spacing-gap-xs); }
.bloch-readout-cell { flex: 1; }
.bloch-readout-val { font-family: var(--fy-font-mono); font-size: var(--fy-font-size-xs); color: var(--fy-text-primary); }
.bloch-z-meter { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.bloch-z-track { height: 8px; background: var(--fy-border); border-radius: var(--fy-radius-full); overflow: hidden; }
.bloch-z-fill { height: 100%; background: linear-gradient(90deg, var(--tool-accent, var(--fy-brand-primary)), var(--tool-accent, var(--fy-brand-primary))); border-radius: var(--fy-radius-full); transition: width var(--fy-duration-fast) linear; }
.bloch-z-labels { display: flex; justify-content: space-between; }
.bloch-readout-ket-section { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
/* Hero chip for the state formula (the payoff of dragging the sphere) --
   a plain left accent bar rather than a filled, bordered tile: the
   payoff is the coloured monospace value itself, not another box. */
.bloch-readout-ket-box {
    display: flex;
    align-items: baseline;
    gap: var(--fy-spacing-gap-xs);
    padding: 2px 0 2px var(--fy-spacing-padding-sm);
    border-left: 2px solid var(--tool-accent, var(--fy-brand-primary));
}
.bloch-readout-ket {
    font-family: var(--fy-font-mono);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-bold);
    color: var(--tool-accent, var(--fy-brand-primary));
    letter-spacing: var(--fy-letter-spacing-tight);
}

/* ── Decoder ──────────────────────────────────────────────────────────── */

.ql-decoder-layout {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-xl);
    align-items: flex-start;
    padding: var(--fy-spacing-padding-md);
}

.ql-decoder-canvas {
    display: block;
    width: 320px;
    height: 320px;
    flex-shrink: 0;
    cursor: pointer;
    touch-action: none;
}

.ql-decoder-readout {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-md);
    min-width: 160px;
}

.ql-decoder-confidence-region { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-sm); }
.ql-decoder-result { display: flex; flex-direction: column; gap: 0; }
/* Hero readout: the one number this whole demo is building up to, sized and
   glowed well above every label around it (Von Restorff — the one thing
   that should be remembered is the one thing that looks different). */
.ql-decoder-confidence {
    font-size: var(--fy-font-size-3xl);
    font-weight: var(--fy-font-weight-extrabold);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--fy-letter-spacing-tight);
    line-height: 1.1;
    color: var(--fy-text-primary);
}
.ql-decoder-confidence-unit { font-size: var(--fy-font-size-lg); font-weight: var(--fy-font-weight-semibold); opacity: 0.7; margin-left: 1px; }
.ql-decoder-status { font-size: var(--fy-font-size-xs); color: var(--fy-text-tertiary); text-transform: uppercase; letter-spacing: var(--fy-letter-spacing-wide); }
.decoder-gauge-track { height: 8px; background: var(--fy-border); border-radius: var(--fy-radius-full); overflow: hidden; }
.decoder-gauge-fill { height: 100%; background: linear-gradient(90deg, var(--tool-accent, var(--fy-brand-primary)), var(--tool-accent, var(--fy-brand-primary))); border-radius: var(--fy-radius-full); transition: width var(--fy-duration-normal) linear; }
.decoder-gauge-label { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); }
.ql-decoder-detail-region { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.decoder-detail { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.decoder-detail-label { font-size: var(--fy-font-size-xs); color: var(--fy-text-tertiary); }
.decoder-detail-code { font-family: var(--fy-font-mono); font-size: var(--fy-font-size-xs); color: var(--tool-accent, var(--fy-brand-primary)); }
.decoder-detail-status { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); }
.decoder-detail-violations { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); }

/* ── Circuit ──────────────────────────────────────────────────────────── */

.ql-circuit-layout {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-xl);
    align-items: flex-start;
    padding: var(--fy-spacing-padding-md);
}

.ql-circuit-canvas {
    display: block;
    width: 480px;
    height: 280px;
    flex-shrink: 0;
    cursor: pointer;
    touch-action: none;
}

.ql-circuit-readout {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-md);
    min-width: 160px;
}

.circuit-readout-grid { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.circuit-readout-section { display: flex; flex-direction: column; gap: var(--fy-spacing-gap-xs); }
.circuit-readout-name { font-size: var(--fy-font-size-md); font-weight: var(--fy-font-weight-bold); color: var(--fy-text-primary); }
.circuit-readout-desc { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); }
.circuit-readout-meta { font-size: var(--fy-font-size-xs); color: var(--fy-text-tertiary); }
/* Hero panel for the "inspect a gate" payoff -- a plain left accent bar
   rather than a filled tile, so clicking a gate reveals a clear
   typographic moment instead of another dark box. */
.circuit-gate-info {
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-xs);
    padding: 2px 0 2px var(--fy-spacing-padding-sm);
    border-left: 2px solid var(--tool-accent, var(--fy-brand-primary));
}
.circuit-gate-name {
    font-family: var(--fy-font-mono);
    font-size: var(--fy-font-size-lg);
    color: var(--tool-accent, var(--fy-brand-primary));
    font-weight: var(--fy-font-weight-bold);
}
.circuit-gate-target { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); }
.circuit-gate-matrix { font-family: var(--fy-font-mono); font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); white-space: pre; }
.circuit-status { font-size: var(--fy-font-size-xs); color: var(--fy-text-secondary); }
.circuit-readout-hint { font-size: var(--fy-font-size-xs); color: var(--fy-text-tertiary); }

/* State vector result panel shown after Run completes — same plain
   left-accent treatment as the gate-info chip above. */
.circuit-result-section {
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-xs);
    padding: 2px 0 2px var(--fy-spacing-padding-sm);
    border-left: 2px solid var(--tool-accent, var(--fy-brand-primary));
}
.circuit-result-ket {
    font-family: var(--fy-font-mono);
    font-size: var(--fy-font-size-sm);
    color: var(--tool-accent, var(--fy-brand-primary));
    font-weight: var(--fy-font-weight-semibold);
    word-break: break-all;
}
.circuit-prob-grid {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.circuit-prob-row {
    display: flex;
    align-items: center;
    gap: var(--fy-spacing-gap-sm);
    font-size: var(--fy-font-size-xs);
}
.circuit-prob-label {
    font-family: var(--fy-font-mono);
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-secondary);
    min-width: 18px;
}
.circuit-prob-track {
    flex: 1;
    height: 6px;
    background: var(--fy-border);
    border-radius: var(--fy-radius-full);
    overflow: hidden;
}
.circuit-prob-fill {
    height: 100%;
    background: var(--tool-accent, var(--fy-brand-primary));
    border-radius: var(--fy-radius-full);
    transition: width 0.3s ease;
}
.circuit-prob-val {
    font-family: var(--fy-font-mono);
    font-size: var(--fy-font-size-xs);
    color: var(--fy-text-tertiary);
    min-width: 56px;
}

.ql-tool-actions {
    display: flex;
    gap: var(--fy-spacing-gap-sm);
}

/* ── Interactive tools mobile/tablet ────────────────────────
   900px, not 700px: the circuit canvas alone (480px) plus its readout's
   160px min-width need ~672px of row space once the tool-row's own
   padding is subtracted. Between 700–820px that no longer fit but the
   row layout was still selected, silently clipping the readout column
   (the row's `overflow: hidden`) on common tablet widths like iPad
   portrait (768px). Stacking earlier avoids that dead zone entirely, and
   900px also matches the breakpoint already used elsewhere on this page
   (hero, infrastructure, signature grid). */

@media (max-width: 900px) {
    .ql-bloch-layout,
    .ql-decoder-layout,
    .ql-circuit-layout {
        flex-direction: column;
        align-items: stretch;
    }

    .ql-bloch-canvas {
        width: 100%;
        height: auto;
        aspect-ratio: 1 / 1;
        max-height: 360px;
    }

    .ql-decoder-canvas {
        width: 100%;
        max-width: 320px;
        height: auto;
        aspect-ratio: 1 / 1;
        max-height: 320px;
    }

    .ql-circuit-canvas {
        width: 100%;
        height: auto;
        aspect-ratio: 12 / 7;
    }

    .ql-bloch-readout {
        font-size: var(--fy-font-size-sm);
    }

    .ql-decoder-readout {
        font-size: var(--fy-font-size-sm);
    }

    .ql-decoder-readout .ql-decoder-status,
    .ql-decoder-readout .decoder-gauge-label,
    .ql-decoder-readout .ql-decoder-detail-label,
    .ql-decoder-readout .decoder-detail-status,
    .ql-decoder-readout .decoder-detail-violations {
        font-size: var(--fy-font-size-sm);
    }

    .ql-decoder-readout .decoder-detail-code {
        font-size: var(--fy-font-size-sm);
        word-break: break-all;
    }

    .ql-circuit-readout {
        font-size: var(--fy-font-size-sm);
    }

    .ql-preset-card {
        padding: var(--fy-spacing-padding-sm) var(--fy-spacing-padding-md);
        font-size: var(--fy-font-size-sm);
        min-height: 44px;
    }

    .ql-tool-row {
        padding: var(--fy-spacing-padding-lg);
    }
}

/* Phones: the card-in-card-in-card nesting (tool row → result panel →
   canvas + a full raw bit-string dump) that reads as loosely-related
   panels on desktop compresses into a wall of concentric boxes on a
   360–480px screen. Tighten the outer chrome and drop the raw syndrome
   bit-string — it's a 72-character duplicate of the dot grid directly
   above it, and costs 2–3 wrapped lines of vertical space for
   information the grid already shows more legibly. The one-line summary
   ("No violations detected" / "Violations at positions: …") stays, since
   that's the one thing the grid can't say in words. */
@media (max-width: 560px) {
    .ql-tool-row {
        padding: var(--fy-spacing-padding-md);
        gap: var(--fy-spacing-gap-md);
    }

    .ql-bloch-layout,
    .ql-decoder-layout,
    .ql-circuit-layout {
        padding: var(--fy-spacing-padding-sm);
        gap: var(--fy-spacing-gap-md);
    }

    .decoder-detail-label,
    .decoder-detail-code {
        display: none;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   10. Footer — continues the CTA's Lapis colour story

   The footer picks up exactly where the CTA section's gradient ends
   (oklch 33% 0.135 288) and deepens further, so scrolling from CTA into
   footer reads as one continuous saturated-brand closing sequence — not
   a vivid colour block followed by an unrelated grey panel. Shares the
   CTA's decorative language (soft cloud bloom + film grain) for the same
   reason. All footer text/border colours are scoped to local
   `--footer-*` custom properties (not the shared `--fy-text-*` tokens),
   since those are tuned for the light page and would fail contrast here.
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-footer {
    --footer-text-primary: oklch(97% 0 0);
    --footer-text-secondary: oklch(82% 0.03 280);
    --footer-text-tertiary: oklch(68% 0.04 282);
    --footer-border: oklch(50% 0.06 282 / 0.45);
    --footer-accent: oklch(80% 0.11 275);
    position: relative;
    /* Continues the CTA gradient's final stop (oklch 33% 0.135 288),
       deepening toward a moodier resting tone — chroma never drops to
       near-zero, so the Lapis hue stays legible all the way down. */
    background: linear-gradient(
        180deg,
        oklch(33% 0.135 288) 0%,
        oklch(24% 0.10 284) 40%,
        oklch(16% 0.075 280) 100%
    );
    overflow: hidden;
    padding: var(--fy-spacing-stack-2xl) 0 var(--fy-spacing-stack-2xl);
}

/* Bold brand-gradient top accent — marks the transition out of the CTA
   section above as a deliberate new chapter, not a fade. */
.ql-footer-top-accent {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--footer-accent) 50%,
        transparent 100%
    );
    z-index: 2;
}

/* Soft cloud bloom — the same painted-light technique as the CTA's
   `.ql-cta-clouds`, toned down since this is the resting point of the
   colour story rather than its climax. */
.ql-footer-clouds {
    position: absolute;
    inset: -10%;
    z-index: 0;
    background-image:
        radial-gradient(ellipse 55% 42% at 20% 0%, oklch(100% 0 0 / 0.10) 0%, transparent 70%),
        radial-gradient(ellipse 46% 40% at 85% 30%, oklch(80% 0.09 250 / 0.12) 0%, transparent 72%);
    pointer-events: none;
}

/* Film grain — identical technique to the CTA's `.ql-cta-grain`, so both
   sections feel like one artistic family rather than two different dark
   treatments. */
.ql-footer-grain {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0.07;
    mix-blend-mode: overlay;
    pointer-events: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Giant watermark wordmark — a soft glowing fill (matching the CTA
   heading's white-on-colour treatment) rather than a faint stroke
   outline, so it reads as a confident brand statement, not a ghost.
   A slow, continuous breathing animation gives it a "living" quality
   rather than a static print. */
.ql-footer-watermark {
    position: absolute;
    left: 50%;
    bottom: -0.12em;
    transform: translateX(-50%);
    font-family: var(--fy-font-heading);
    font-weight: 800;
    font-size: clamp(6rem, 18vw, 14rem);
    letter-spacing: -0.02em;
    line-height: 1;
    color: oklch(100% 0 0 / 0.05);
    text-shadow: 0 0 80px oklch(100% 0 0 / 0.18);
    white-space: nowrap;
    pointer-events: none;
    z-index: 0;
    user-select: none;
    animation: ql-footer-watermark-breathe 14s ease-in-out infinite;
    transform-origin: center;
}

@keyframes ql-footer-watermark-breathe {
    0%, 100% { transform: translateX(-50%) scale(1); opacity: 1; }
    50%      { transform: translateX(-50%) scale(1.025); opacity: 0.82; }
}

/* Scroll-linked parallax (progressive enhancement, no JS) — the cloud
   bloom drifts slightly as the footer scrolls into view. Browsers
   without scroll-driven animation support simply keep the static clouds
   defined above; nothing breaks. */
@supports (animation-timeline: view()) {
    .ql-footer-clouds {
        animation: ql-footer-clouds-parallax linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 60%;
    }

    @keyframes ql-footer-clouds-parallax {
        from { transform: translateY(-32px); }
        to   { transform: translateY(16px); }
    }
}

@media (prefers-reduced-motion: reduce) {
    .ql-footer-watermark {
        animation: none;
    }

    .ql-footer-clouds {
        animation: none;
    }
}

.ql-footer-inner {
    position: relative;
    z-index: 1;
    max-width: var(--fy-container-width-wide);
    margin: 0 auto;
    padding: 0 var(--fy-spacing-padding-lg);
}

.ql-footer-panel {
    position: relative;
}

.ql-footer-row {
    display: flex;
    flex-wrap: wrap;
}

/* ── Masthead: brand + tagline (left), social icon buttons (right) ────
   Horizontal gutter comes solely from `.ql-footer-inner`'s own padding —
   no extra horizontal padding here, to avoid the doubled-up spacing that
   nesting a second horizontal padding inside an already-padded container
   produces. */
.ql-footer-masthead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-lg);
    padding: 8px 0 32px;
}

.ql-footer-masthead-brand {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.ql-footer-tagline {
    font-size: var(--fy-font-size-sm);
    color: var(--footer-text-secondary);
    margin: 0;
    max-width: 34ch;
}

.ql-footer-masthead-social {
    display: flex;
    gap: 10px;
    flex-shrink: 0;
}

.ql-footer-social-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--fy-radius-full);
    border: 1px solid var(--footer-border);
    background: oklch(100% 0 0 / 0.04);
    color: var(--footer-text-secondary);
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        border-color var(--fy-duration-fast) var(--fy-easing-standard),
        color var(--fy-duration-fast) var(--fy-easing-standard),
        transform var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-footer-social-btn:hover {
    background: oklch(100% 0 0 / 0.08);
    border-color: var(--footer-accent);
    color: var(--footer-accent);
    transform: translateY(-2px);
}

.ql-footer-sep {
    display: block;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--footer-border) 20%,
        var(--footer-border) 80%,
        transparent 100%
    );
}



/* Reusable classes matching the fade-edge pattern used throughout the landing page. */

.ql-fade-sep {
    display: block;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--fy-border) 20%,
        var(--fy-border) 80%,
        transparent 100%
    );
    pointer-events: none;
    border: none;
}

.ql-fade-sep-v {
    display: block;
    width: 1px;
    background: linear-gradient(
        180deg,
        transparent 0%,
        var(--fy-border) 20%,
        var(--fy-border) 80%,
        transparent 100%
    );
    pointer-events: none;
    border: none;
}

.ql-footer-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    color: var(--footer-text-primary);
    text-decoration: none;
}

/* Logo assets are dark-on-transparent (tuned for the light nav/page) —
   force pure white via filter so they read on the footer's dark panel. */

.ql-footer-logo-mark {
    height: 50px;
    width: auto;
    display: block;
    flex-shrink: 0;
}

.ql-footer-logo-text {
    height: 31px;
    width: auto;
    display: block;
}

/* Nav columns */
/* Frosted glass panel holding the whole nav grid — so the link columns
   read as one considered surface floating on the colour field, not
   plain text dropped straight onto the gradient. Same rule as the
   masthead above: no extra horizontal margin, since `.ql-footer-inner`
   already provides the page gutter — the panel spans it edge to edge,
   flush with the masthead and copyright row above/below it. */
.ql-footer-row--nav {
    margin: 0;
    background: oklch(100% 0 0 / 0.035);
    border: 1px solid var(--footer-border);
    border-radius: var(--fy-radius-xl);
    backdrop-filter: blur(16px) saturate(140%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
}

.ql-footer-row--nav .ql-footer-cell {
    flex: 1 1 200px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 28px 32px;
    min-width: 0;
}

/* Hairline dividers between columns — a considered touch inside the glass
   panel, matching the footer's original "spreadsheet" structural idea.
   Switches to border-top the moment the row itself stacks to a column
   (see the 720px breakpoint below) — both changes happen at the same
   breakpoint so a divider is never left stranded mid-wrap. */
.ql-footer-row--nav .ql-footer-cell + .ql-footer-cell {
    border-left: 1px solid var(--footer-border);
}

.ql-footer-heading {
    font-family: var(--fy-font-sans);
    font-size: var(--fy-font-size-xs);
    font-weight: var(--fy-font-weight-bold);
    letter-spacing: var(--fy-letter-spacing-wider);
    text-transform: uppercase;
    color: var(--footer-text-tertiary);
    margin: 0;
}

/* Footer-scoped override: the "Available Soon" badge uses a lighter brand
   tint here so it stays legible on the dark panel (the nav/light-page
   version of this badge is unaffected). */
.ql-footer .ql-badge-coming-soon {
    background: oklch(100% 0 0 / 0.1);
    color: var(--footer-accent);
}

.ql-footer .ql-footer-link-disabled {
    color: var(--footer-text-secondary);
}

.ql-footer-links {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Growing underline on hover — a small, considered micro-interaction
   instead of a flat colour swap.

   Selector note: the fyrn base reset (`a:not(.fyn-btn):not(.fyn-dropdown-item)`)
   carries specificity (0,2,1) — two `:not(<class>)` clauses count as class
   selectors. A plain `.ql-footer-links a` (0,1,1) loses to it, so every
   footer link selector below is qualified with `.ql-footer-panel` to reach
   (0,2,1) and win on source order (landing.css loads after main.css). */
.ql-footer-panel .ql-footer-links a {
    display: inline-block;
    width: fit-content;
    font-size: var(--fy-font-size-sm);
    color: var(--footer-text-secondary);
    text-decoration: none;
    background-image: linear-gradient(90deg, var(--footer-accent), var(--footer-accent));
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 1px;
    padding-bottom: 2px;
    transition:
        color var(--fy-duration-fast) var(--fy-easing-standard),
        background-size var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-footer-panel .ql-footer-links a:hover {
    color: var(--footer-accent);
    background-size: 100% 1px;
}

@media (prefers-reduced-motion: reduce) {
    .ql-footer-panel .ql-footer-links a {
        transition: color var(--fy-duration-fast) var(--fy-easing-standard);
    }
}

/* Bottom row — copyright notice, centred across full width. Vertical
   padding only, for the same reason as the masthead above. */
.ql-footer-row--copyright {
    display: flex;
    justify-content: center;
    padding: 24px 0 0;
}

.ql-footer-copyright {
    font-size: var(--fy-font-size-xs);
    color: var(--footer-text-tertiary);
}

/* Tablet — masthead stacks brand/tagline above the social icons, and the
   nav grid switches to a stacked column *at the same breakpoint*: a
   single threshold means a divider is never left stranded mid-wrap
   between "3 columns in a row" and "3 columns stacked". */
@media (max-width: 720px) {
    .ql-footer-masthead {
        flex-direction: column;
        align-items: flex-start;
        padding: 8px 0 24px;
    }

    .ql-footer-row--nav {
        flex-direction: column;
    }

    .ql-footer-row--nav .ql-footer-cell {
        padding: 20px 24px;
    }

    .ql-footer-row--nav .ql-footer-cell + .ql-footer-cell {
        border-left: none;
        border-top: 1px solid var(--footer-border);
    }

    .ql-footer-row--copyright {
        padding: 20px 0 0;
    }
}

/* .ql-section-algorithms intentionally removed: it only set
   `min-height: unset`, which resolves to the same initial value (`auto`)
   the base `.ql-section` rule already sets — a no-op override. */

/* ═══════════════════════════════════════════════════════════════════════════
   11. Algorithms carousel section (2026 edition)
   ═══════════════════════════════════════════════════════════════════════════ */





.ql-algorithms-heading-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--fy-spacing-gap-lg);
}

.ql-algorithms-heading-text {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.ql-algorithms-title {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-2xl);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: 0;
    line-height: 1.25;
    letter-spacing: var(--fy-letter-spacing-tight);
}

/* Hero stat treatment: pulls "271" out of plain heading text into an
   oversized, brand-gradient number — the scale of the library is the
   first thing noticed, matching the hero/hardware-validation stat blocks
   elsewhere on the page instead of reading as a plain sentence. */
.ql-algorithms-stat-row {
    display: flex;
    align-items: baseline;
    gap: var(--fy-spacing-gap-sm);
    flex-wrap: wrap;
}

.ql-algorithms-stat-number {
    display: inline-block;
    line-height: 1;
}

.ql-algorithms-stat-number svg {
    display: block;
    height: clamp(2.5rem, 5vw, 3.5rem);
    width: auto;
    max-width: 100%;
}

.ql-algorithms-stat-label {
    font-size: var(--fy-font-size-md);
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-secondary);
}

.ql-algorithms-sub {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    margin: 0;
    line-height: 1.55;
}

.ql-algo-top-nav {
    display: flex;
    gap: var(--fy-spacing-gap-sm);
    flex-shrink: 0;
    padding-bottom: 2px;
}

/* Filter pills — turns a passive scroll into an explorable library.
   Driven entirely by WASM (carousel_interactive.rs) toggling slide
   visibility via `data-category`. */
.ql-algo-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-xs);
}

.ql-algo-filter {
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    border-radius: var(--fy-radius-full);
    border: 1px solid var(--fy-border);
    background: var(--fy-surface-alt);
    color: var(--fy-text-secondary);
    font-size: var(--fy-font-size-xs);
    font-weight: var(--fy-font-weight-medium);
    cursor: pointer;
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        border-color var(--fy-duration-fast) var(--fy-easing-standard),
        color var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-algo-filter:hover {
    border-color: var(--fy-brand-primary);
    color: var(--fy-text-primary);
}

.ql-algo-filter-active {
    background: var(--fy-brand-primary);
    border-color: var(--fy-brand-primary);
    color: var(--fy-text-inverse);
}

.ql-algo-filter-active:hover {
    color: var(--fy-text-inverse);
}

/* Carousel container with edge fade masks */
.ql-algo-carousel-container {
    position: relative;
    overflow: hidden;
    border-radius: var(--fy-radius-lg);
    width: calc(100% + 2 * var(--fy-spacing-padding-lg));
    margin-left: calc(-1 * var(--fy-spacing-padding-lg));
}

.ql-algo-carousel-container::before,
.ql-algo-carousel-container::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 52px;
    z-index: 2;
    pointer-events: none;
}

.ql-algo-carousel-container::before {
    left: 0;
    background: linear-gradient(90deg, var(--fy-surface-background) 0%, transparent 100%);
}

.ql-algo-carousel-container::after {
    right: 0;
    background: linear-gradient(270deg, var(--fy-surface-background) 0%, transparent 100%);
}

/* Nav buttons — frosted glass */
.ql-algo-nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--fy-border);
    background: var(--fy-surface-raised);
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    color: var(--fy-text-secondary);
    font-size: 18px;
    cursor: pointer;
    box-shadow: var(--fy-shadow-sm);
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        color var(--fy-duration-fast) var(--fy-easing-standard),
        border-color var(--fy-duration-fast) var(--fy-easing-standard),
        box-shadow var(--fy-duration-fast) var(--fy-easing-standard),
        transform var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-algo-nav:hover {
    background: var(--fy-surface-alt);
    color: var(--fy-brand-primary);
    border-color: var(--fy-border-accent);
    box-shadow:
        var(--fy-shadow-md);
    transform: translateY(-1px);
}

/* Edge-aware disabled state — set by WASM when the carousel is scrolled
   all the way to the start/end, so the controls never invite a no-op click. */
.ql-algo-nav--disabled {
    opacity: 0.35;
    cursor: default;
    pointer-events: none;
}

.ql-algo-carousel {
    display: flex;
    gap: var(--fy-spacing-gap-md);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding: var(--fy-spacing-padding-sm) 0 var(--fy-spacing-padding-md);
    scrollbar-width: none;
    cursor: grab;
    touch-action: pan-y;
    user-select: none;
}

/* Pointer drag-to-scroll — momentarily disable snap so the drag feels
   direct, and swap to a “grabbing” cursor for clear affordance. */
.ql-algo-carousel--dragging {
    cursor: grabbing;
    scroll-snap-type: none;
}

.ql-algo-carousel::-webkit-scrollbar {
    display: none;
}

.ql-algo-slide {
    flex: 0 0 320px;
    scroll-snap-align: start;
}

@media (max-width: 900px) {
    .ql-algo-slide { flex: 0 0 280px; }
}

@media (max-width: 600px) {
    .ql-algo-slide { flex: 0 0 240px; }
    .ql-algo-nav { display: none; }
}

/* Algorithm card — tinted per category via --cat-color, picked up from the
   icon's category class through :has() so a single source of truth (the
   ten hues already defined for .ql-algo-cat-*) drives icon colour, the
   shimmer line, and the hover glow together. Falls back to brand-primary
   in browsers without :has() support — a non-breaking enhancement. */
.ql-algo-card {
    --cat-color: var(--fy-brand-primary);
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-gap-md);
    padding: var(--fy-spacing-padding-xl);
    min-height: 300px;
    background: linear-gradient(
        165deg,
        var(--fy-surface) 0%,
        color-mix(in oklch, var(--fy-brand-primary) 3%, var(--fy-surface)) 100%
    );
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    height: 100%;
    box-sizing: border-box;
    position: relative;
    overflow: hidden;
    transition:
        transform var(--fy-duration-normal) var(--fy-easing-standard),
        box-shadow var(--fy-duration-normal) var(--fy-easing-standard),
        border-color var(--fy-duration-normal) var(--fy-easing-standard);
}

/* All ten categories share the Lapis brand hue family (265deg-290deg),
   varying only in lightness, rather than ten unrelated colours — category
   is distinguished by icon shape and badge label, not by a competing
   colour wheel. */
.ql-algo-card:has(.ql-algo-icon--state-prep)     { --cat-color: oklch(48% 0.15 265); }
.ql-algo-card:has(.ql-algo-icon--transform)      { --cat-color: oklch(52% 0.15 269); }
.ql-algo-card:has(.ql-algo-icon--algorithm)      { --cat-color: oklch(45% 0.16 272); }
.ql-algo-card:has(.ql-algo-icon--optimisation)   { --cat-color: oklch(50% 0.14 275); }
.ql-algo-card:has(.ql-algo-icon--ansatz)         { --cat-color: oklch(42% 0.16 277); }
.ql-algo-card:has(.ql-algo-icon--encoding)       { --cat-color: oklch(54% 0.13 280); }
.ql-algo-card:has(.ql-algo-icon--arithmetic)     { --cat-color: oklch(47% 0.15 282); }
.ql-algo-card:has(.ql-algo-icon--simulation)     { --cat-color: oklch(51% 0.14 285); }
.ql-algo-card:has(.ql-algo-icon--benchmark)      { --cat-color: oklch(44% 0.16 287); }
.ql-algo-card:has(.ql-algo-icon--tensor-network) { --cat-color: oklch(49% 0.15 290); }

/* Shimmer top line — now tinted per category */
.ql-algo-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 22%;
    right: 22%;
    height: 1px;
    background: linear-gradient(
        90deg,
        transparent,
        var(--cat-color),
        transparent
    );
    pointer-events: none;
    z-index: 1;
    transition: background var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-algo-card:hover {
    transform: translateY(-4px);
    border-color: var(--cat-color);
    box-shadow:
        var(--fy-shadow-md),
        0 0 32px color-mix(in oklch, var(--cat-color) 18%, transparent);
}

/* Glow bloom — a soft, contained corner glow on hover: a "lit-up AI
   product" cue rather than a flat colour swap. Kept small and low-opacity
   so it reads as a light source, not a colour wash over the text. */
.ql-algo-card::after {
    content: "";
    position: absolute;
    top: -20%;
    right: -20%;
    width: 55%;
    height: 55%;
    background: radial-gradient(
        circle,
        color-mix(in oklch, var(--cat-color) 16%, transparent) 0%,
        transparent 70%
    );
    opacity: 0;
    pointer-events: none;
    z-index: 0;
    transition: opacity var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-algo-card:hover::after {
    opacity: 1;
}

/* Algorithm icon — SVG container, tinted to match its card's category.
   Generously sized with a soft glow ring so it reads as a considered
   product mark rather than a small utility dot. */
.ql-algo-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: var(--fy-radius-lg);
    background: color-mix(in oklch, var(--cat-color) 12%, var(--fy-surface-alt));
    border: 1px solid color-mix(in oklch, var(--cat-color) 22%, var(--fy-border));
    color: var(--cat-color);
    flex-shrink: 0;
    line-height: 1;
    position: relative;
    z-index: 1;
    box-shadow: 0 0 0 4px color-mix(in oklch, var(--cat-color) 6%, transparent);
    transition:
        background var(--fy-duration-normal) var(--fy-easing-standard),
        border-color var(--fy-duration-normal) var(--fy-easing-standard),
        box-shadow var(--fy-duration-normal) var(--fy-easing-standard),
        transform var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-algo-card:hover .ql-algo-icon {
    background: color-mix(in oklch, var(--cat-color) 20%, var(--fy-surface-alt));
    border-color: var(--cat-color);
    box-shadow: 0 0 0 6px color-mix(in oklch, var(--cat-color) 10%, transparent);
    transform: scale(1.06);
}

.ql-algo-icon svg {
    display: block;
    width: 26px;
    height: 26px;
}

.ql-algo-header {
    display: flex;
    flex-direction: column;
    gap: 6px;
    position: relative;
    z-index: 1;
}

.ql-algo-name {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    letter-spacing: var(--fy-letter-spacing-tight);
}

/* Category label — a plain coloured eyebrow above the name (via flex
   `order`, no markup change) rather than a pill/badge sticker: reads as
   crisp typographic hierarchy instead of a decorative chip. */
.ql-algo-category {
    --cat-color: var(--fy-brand-primary);
    order: -1;
    display: inline-flex;
    align-items: center;
    height: auto;
    min-width: auto;
    font-size: 11px;
    font-weight: var(--fy-font-weight-bold);
    letter-spacing: var(--fy-letter-spacing-wider);
    text-transform: uppercase;
    background: none;
    color: var(--cat-color);
    border: none;
    padding: 0;
    width: fit-content;
}

/* Per-category hue definitions — Lapis brand family (see .ql-algo-card above) */
.ql-algo-cat-state-prep     { --cat-color: oklch(48% 0.15 265); }
.ql-algo-cat-transform      { --cat-color: oklch(52% 0.15 269); }
.ql-algo-cat-algorithm      { --cat-color: oklch(45% 0.16 272); }
.ql-algo-cat-optimisation   { --cat-color: oklch(50% 0.14 275); }
.ql-algo-cat-ansatz         { --cat-color: oklch(42% 0.16 277); }
.ql-algo-cat-encoding       { --cat-color: oklch(54% 0.13 280); }
.ql-algo-cat-arithmetic     { --cat-color: oklch(47% 0.15 282); }
.ql-algo-cat-simulation     { --cat-color: oklch(51% 0.14 285); }
.ql-algo-cat-benchmark      { --cat-color: oklch(44% 0.16 287); }
.ql-algo-cat-tensor-network { --cat-color: oklch(49% 0.15 290); }

.ql-algo-desc {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    margin: 0;
    line-height: 1.6;
    flex: 1;
    position: relative;
    z-index: 1;
}

/* Footer row: qubit count — a thin divider separates it from the
   description, then a plain mono stat rather than a pill/button, so the
   card ends on a quiet, crisp data point instead of another sticker. */
.ql-algo-footer {
    display: flex;
    align-items: center;
    margin-top: auto;
    padding-top: var(--fy-spacing-padding-sm);
    border-top: 1px solid var(--fy-border);
    position: relative;
    z-index: 1;
}

.ql-algo-qubits {
    display: inline-flex;
    align-items: center;
    height: auto;
    min-width: auto;
    gap: 5px;
    font-family: var(--fy-font-mono);
    font-size: var(--fy-font-size-xs);
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-tertiary);
    padding: 0;
    background: none;
    border: none;
}

/* Pagination dots — pill active state */
.ql-algo-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 6px;
    padding-top: var(--fy-spacing-gap-sm);
}

.ql-algo-dot {
    width: 6px;
    height: 6px;
    border-radius: var(--fy-radius-full);
    background: var(--fy-border);
    border: none;
    cursor: pointer;
    padding: 0;
    transition:
        background var(--fy-duration-fast) var(--fy-easing-standard),
        transform var(--fy-duration-fast) var(--fy-easing-sharp),
        width var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-algo-dot:hover {
    background: var(--fy-text-tertiary);
}

.ql-algo-dot-active {
    background: var(--fy-brand-primary);
    transform: scale(1.2);
    width: 18px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   12. prefers-reduced-motion overrides
   ═══════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
    /* Bento cards */
    .ql-bento-card,
    .ql-bento-card:hover,
    .ql-bento-ampligrid,
    .ql-bento-ampligrid:hover {
        transition: none;
        transform: none;
    }

    .ql-bento-card::before,
    .ql-bento-card::after {
        transition: none;
    }

    /* Disable scroll-reveal entrance animation */
    .ql-bento-card[data-reveal] {
        transition: none;
        opacity: 1;
        transform: none;
    }



    /* Preset cards */
    .ql-preset-card {
        transition: none;
    }

    .ql-preset-card:hover {
        transform: none;
    }



    /* Tool rows: disable ambient glow easing + scroll-reveal entrance */
    .ql-tool-row,
    .ql-tool-row:hover {
        transition: none;
    }


    .ql-tool-row[data-reveal] {
        transition: none;
        opacity: 1;
        transform: none;
    }

    /* Algo card */
    .ql-algo-card,
    .ql-algo-card:hover {
        transition: none;
        transform: none;
    }

    /* Algo nav */
    .ql-algo-nav {
        transition: none;
        transform: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }

    /* Algo dot */
    .ql-algo-dot {
        transition: none;
        width: auto;
    }

    .ql-algo-dot-active {
        transform: none;
        width: 18px;
    }

    /* Nav */
    .ql-nav {
        transition: none;
    }

    .ql-nav-inner,
    .ql-nav-link,
    .ql-nav-link svg,
    .ql-nav-dropdown,
    .ql-nav-dropdown-item,
    .ql-nav-dropdown-icon,
    .ql-nav-dropdown-link,
    .ql-nav-icon-btn,
    .ql-nav-hamburger {
        transition: none;
        filter: none;
    }

    .ql-nav-dropdown {
        filter: none;
        transform: translateX(-50%) translateY(0) scale(1);
    }

    /* Back to top */
    .ql-back-to-top {
        transition: none;
    }

    .ql-back-to-top:hover {
        transform: none;
    }

    /* CTA dark pattern — remove animation */
    .ql-cta-dark::before {
        opacity: 0.3;
    }

}

/* ═══════════════════════════════════════════════════════════════════════════
   13. Content pages — blog, legal, changelog, static pages
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Shared page hero — gradient-lit header for every content page ────── */

.ql-page-hero {
    position: relative;
    overflow: hidden;
    padding: 140px 0 80px;
    background: var(--fy-surface-background);
}

@media (max-width: 640px) {
    .ql-page-hero {
        padding: 100px 0 48px;
    }
}

.ql-page-hero-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(ellipse 70% 60% at 50% 50%, transparent 0%, var(--fy-surface-background) 70%),
        radial-gradient(ellipse 50% 50% at 50% 50%, oklch(55% 0.16 275 / 0.08) 0%, transparent 60%),
        radial-gradient(ellipse 40% 40% at 50% 50%, oklch(55% 0.20 240 / 0.05) 0%, transparent 60%);
}

.ql-page-hero .fyn-container {
    position: relative;
    z-index: 1;
}

.ql-page-hero-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--fy-spacing-gap-sm);
    width: 100%;
}

/* Override container padding to lg on content pages */
.ql-page-hero .fyn-container-padded,
.ql-content-section .fyn-container-padded {
    padding-left: var(--fy-spacing-padding-lg);
    padding-right: var(--fy-spacing-padding-lg);
}

/* Faded separator between hero and content */
.ql-page-hero::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    height: 1px;
    width: min(var(--fy-container-width-page), calc(100% - 48px));
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--fy-border) 20%,
        var(--fy-border) 80%,
        transparent 100%
    );
    pointer-events: none;
}

/* ── Research project cards ──────────────────────────── */

.ql-research-grid {
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-stack-lg);
}

.ql-research-card {
    position: relative;
    z-index: 1;
    padding: var(--fy-spacing-padding-xl);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-color: var(--fy-surface);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    overflow: hidden;
    min-height: 384px;
}

.ql-research-card-inner {
    padding-top: 200px;
    position: relative;
    z-index: 1;
}

.ql-research-card::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to top,
        var(--fy-surface) 0%,
        var(--fy-surface) 65%,
        transparent 100%
    );
    pointer-events: none;
    z-index: 0;
    border-radius: inherit;
}

#card-nucleation {
    background-image: url('/assets/Q-Nucleation.webp');
}

#card-data-fusion {
    background-image: url('/assets/Multi-Source_Data_Fusion.webp');
}

#card-benchmarks {
    background-image: url('/assets/Multi-GPU_Distributed_Statevector_Benchmarks.webp');
}

.ql-research-title {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-xl);
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-primary);
    margin: 0 0 var(--fy-spacing-stack-sm);
    line-height: 1.25;
    text-wrap: balance;
}

.ql-research-label {
    font-size: var(--fy-font-size-xs);
    font-weight: var(--fy-font-weight-semibold);
    letter-spacing: var(--fy-letter-spacing-wider);
    text-transform: uppercase;
    color: var(--fy-text-secondary);
    margin: 0 0 var(--fy-spacing-stack-xs);
}

.ql-research-brief {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    line-height: 1.5;
    margin: 0 0 var(--fy-spacing-stack-sm);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ql-research-card-sep {
    height: 1px;
    background: var(--fy-border);
    margin-bottom: var(--fy-spacing-stack-sm);
}

.ql-research-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--fy-spacing-gap-md);
    font-size: var(--fy-font-size-xs);
    color: var(--fy-text-tertiary);
    margin-bottom: var(--fy-spacing-stack-md);
}

.ql-research-meta-item {
    white-space: nowrap;
}

.ql-research-expand-wrap {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.35s ease;
}

.ql-research-expanded .ql-research-expand-wrap {
    grid-template-rows: 1fr;
}

.ql-research-expand-wrap > * {
    overflow: hidden;
    min-height: 0;
}

.ql-research-details {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-primary);
    line-height: 1.6;
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-stack-md);
}

.ql-research-summary-block .ql-research-summary-text {
    margin: 0;
    color: var(--fy-text-primary);
    line-height: 1.6;
}

.ql-research-outputs {
    padding: var(--fy-spacing-padding-md);
    background: color-mix(in oklch, var(--fy-surface-alt) 60%, transparent);
    border-radius: var(--fy-radius-md);
}

.ql-research-outputs .ql-research-label {
    margin-bottom: var(--fy-spacing-stack-xs);
}

.ql-research-outputs-text {
    margin: 0;
    color: var(--fy-text-secondary);
}

.ql-research-expand {
    display: inline-block;
    font-size: var(--fy-font-size-sm);
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-brand-primary);
    cursor: pointer;
    text-decoration: none;
}

.ql-research-expand:hover {
    text-decoration: underline;
}

/* ── Shared content section — padding wrapper ─────────────────────────── */

.ql-content-section {
    padding: var(--fy-spacing-stack-2xl) 0 var(--fy-spacing-stack-3xl);
}

@media (max-width: 640px) {
    .ql-content-section {
        padding: var(--fy-spacing-stack-xl) 0 var(--fy-spacing-stack-2xl);
    }
}

/* ── Shared content body — SSOT typography for Markdown-generated HTML ── */
/* Uses Fyrn design tokens throughout to stay consistent with the design system. */

.ql-content-body {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-primary);
    line-height: 1.6;
}

.ql-content-body h2 {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-xl);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: var(--fy-spacing-stack-xl) 0 var(--fy-spacing-gap-sm);
    letter-spacing: var(--fy-letter-spacing-tight);
    line-height: 1.3;
}

.ql-content-body h3 {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: var(--fy-spacing-stack-lg) 0 var(--fy-spacing-gap-xs);
}

.ql-content-body p {
    margin: 0 0 var(--fy-spacing-gap-md);
}

.ql-content-body ul,
.ql-content-body ol {
    margin: 0 0 var(--fy-spacing-gap-md);
    padding-left: 1.5em;
}

.ql-content-body li {
    margin-bottom: var(--fy-spacing-gap-xs);
}

.ql-content-body a {
    color: var(--fy-brand-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.ql-content-body a:hover {
    opacity: 0.8;
}

/* Blockquote — mirrors .fyn-text-blockquote token values */
.ql-content-body blockquote {
    margin: 0 0 var(--fy-spacing-stack-lg);
    padding: var(--fy-spacing-padding-sm) var(--fy-spacing-padding-md);
    border-left: var(--fy-size-4px) solid var(--fy-brand-primary);
    background: var(--fy-surface-alt);
    border-radius: var(--fy-radius-sm);
    color: var(--fy-text-secondary);
    font-style: italic;
}

/* Inline code — mirrors .fyn-text-code exactly */
.ql-content-body code {
    font-family: var(--fy-font-mono);
    font-size: 0.875em;
    background: var(--fy-surface-alt);
    padding: var(--fy-size-2px) var(--fy-size-6px);
    border-radius: var(--fy-radius-sm);
    border: 1px solid var(--fy-border);
    color: var(--fy-brand-primary);
}

.ql-content-body pre {
    background: var(--fy-surface-alt);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-lg);
    padding: var(--fy-spacing-padding-lg);
    overflow-x: auto;
    margin: 0 0 var(--fy-spacing-stack-lg);
    font-size: 0.875rem;
    line-height: 1.7;
}

.ql-content-body pre code {
    background: none;
    border: none;
    padding: 0;
    color: inherit;
}

/* Table — mirrors .fyn-table-bordered token values */
.ql-content-body table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 var(--fy-spacing-stack-lg);
    font-size: var(--fy-font-size-sm);
    border-radius: var(--fy-radius-lg);
    overflow: hidden;
}

.ql-content-body th,
.ql-content-body td {
    padding: var(--fy-spacing-padding-sm) var(--fy-spacing-padding-md);
    border: 1px solid var(--fy-border);
    text-align: left;
}

.ql-content-body th {
    background: var(--fy-surface-alt);
    font-weight: var(--fy-font-weight-semibold);
    font-size: var(--fy-font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--fy-letter-spacing-wide);
    color: var(--fy-text-secondary);
}

.ql-content-body img {
    max-width: 100%;
    border-radius: var(--fy-radius-lg);
    border: 1px solid var(--fy-border);
    margin: var(--fy-spacing-stack-lg) 0;
}

.ql-content-body hr {
    border: none;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--fy-border), transparent);
    margin: var(--fy-spacing-stack-xl) 0;
}

/* ── Blog grid — card layout ─────────────────────────────────────────── */

.ql-blog-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: var(--fy-spacing-gap-lg);
}

@media (max-width: 480px) {
    .ql-blog-grid {
        grid-template-columns: 1fr;
    }
}

.ql-blog-card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 4px;
}

.ql-blog-card {
    position: relative;
    display: block;
    padding: var(--fy-spacing-padding-xl);
    text-decoration: none;
    color: inherit;
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    background: var(--fy-surface);
    overflow: hidden;
    transition:
        transform var(--fy-duration-normal) var(--fy-easing-decelerate),
        box-shadow var(--fy-duration-normal) var(--fy-easing-standard),
        border-color var(--fy-duration-normal) var(--fy-easing-standard);
}

.ql-blog-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 20%;
    right: 20%;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--fy-brand-primary), transparent);
    pointer-events: none;
    z-index: 1;
    opacity: 0;
    transition: opacity var(--fy-duration-slow) var(--fy-easing-decelerate);
}

.ql-blog-card:hover {
    transform: translateY(-5px);
    border-color: var(--fy-border-accent);
    box-shadow: var(--fy-shadow-lg);
}

.ql-blog-card:hover::before {
    opacity: 1;
}

.ql-blog-card-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: auto;
    padding-top: var(--fy-spacing-gap-sm);
}

.ql-blog-card-arrow {
    font-size: var(--fy-font-size-lg);
    color: var(--fy-text-tertiary);
    transition:
        transform var(--fy-duration-fast) var(--fy-easing-standard),
        color var(--fy-duration-fast) var(--fy-easing-standard);
}

.ql-blog-card:hover .ql-blog-card-arrow {
    transform: translateX(4px);
    color: var(--fy-brand-primary);
}

.ql-blog-empty {
    text-align: center;
    padding: var(--fy-spacing-stack-3xl) 0;
    color: var(--fy-text-tertiary);
}

/* ── Changelog — entry chrome only (typography via .ql-content-body) ──── */

.ql-changelog-entry {
    position: relative;
    border-color: var(--fy-border-accent);
    box-shadow: var(--fy-shadow-sm);
}

.ql-changelog-entry::before {
    content: "";
    position: absolute;
    top: 0;
    left: 24%;
    right: 24%;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--fy-brand-primary), transparent);
    pointer-events: none;
    z-index: 1;
}

.ql-changelog-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--fy-spacing-gap-md);
    padding: var(--fy-spacing-padding-lg);
    background: var(--fy-surface-alt);
    border-bottom: 1px solid var(--fy-border);
}

.ql-changelog-version-group {
    display: flex;
    align-items: center;
    gap: var(--fy-spacing-gap-md);
}

/* ── Content page responsive ─────────────────────────────────────────── */

@media (max-width: 640px) {
    .ql-changelog-header {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--fy-spacing-gap-xs);
    }


}

@media (prefers-reduced-motion: reduce) {
    .ql-blog-card,
    .ql-blog-card:hover,
    .ql-changelog-entry,
    .ql-changelog-entry:hover {
        transition: none;
        transform: none;
    }

    .ql-blog-card::before,
    .ql-changelog-entry::before {
        opacity: 1;
    }
}

/* ════════════════════════════════════════════════════════════════════
   14. Early access form page (textarea styling, success state)
   ════════════════════════════════════════════════════════════════════
   The form lives on a dedicated /early-access page (not in a dialog).
   Textarea and success state are the only QL-specific overrides;
   everything else (inputs, select, alerts, buttons) is handled by
   fyrn-css directly. */

/* ── Early access form field spacing ──────────────────────── */
.ql-ea-form .fyn-form {
    gap: var(--fy-spacing-stack-sm);
}

/* Match select trigger styling to inputs */
.ql-ea-form .fyn-select-wrapper.fyn-select-md {
    padding: 0;
}
.ql-ea-form .fyn-select-wrapper.fyn-select-md .fyn-select-trigger {
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-control-radius);
}
.ql-ea-form .fyn-select-trigger.fyn-select-outlined:hover {
    border-color: var(--fy-border);
}

/* Hide redundant required indicators (all fields are required) */
.ql-ea-form .fyn-input-required,
.ql-ea-form .fyn-select-required,
.ql-ea-form .fyn-label-required {
    display: none;
}

/* Tighter label styling — matches standalone Label component */
.ql-ea-form .fyn-label,
.ql-ea-form .fyn-input-label,
.ql-ea-form .fyn-select-label {
    margin-bottom: 2px;
    font-size: var(--fy-font-size-xs);
    font-weight: var(--fy-font-weight-medium);
    color: var(--fy-text-secondary);
}

.ql-ea-success {
    padding-top: var(--fy-spacing-stack-xl);
}

.ql-ea-success.fyn-alert-variant-success {
    margin-top: var(--fy-spacing-stack-lg);
}



/* ════════════════════════════════════════════════════════════════════
   15. Early-access page redesign (2026)
   Two-column cohort layout, elevated form card, superposition-collapse
   success motif, scarcity line.
   ════════════════════════════════════════════════════════════════════ */

:root {
    --ql-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ── Early access page: two-column layout ──────────────────────────── */

.ql-ea-layout {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: var(--fy-spacing-stack-2xl);
    align-items: start;
    padding-top: var(--fy-spacing-stack-2xl);
    padding-bottom: var(--fy-spacing-stack-3xl);
}

@media (max-width: 900px) {
    .ql-ea-layout {
        grid-template-columns: 1fr;
    }
}

.ql-ea-aside {
    display: flex;
    flex-direction: column;
    gap: var(--fy-spacing-stack-lg);
    padding-top: var(--fy-spacing-stack-sm);
}

.ql-ea-aside-eyebrow {
    color: var(--fy-text-secondary);
    letter-spacing: var(--fy-letter-spacing-wider);
    margin: 0;
}

.ql-ea-aside-item {
    display: flex;
    gap: var(--fy-spacing-gap-md);
    align-items: flex-start;
}

.ql-ea-aside-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--fy-radius-md);
    border: 1px solid var(--fy-border-accent);
    color: var(--fy-brand-primary);
    background: oklch(55% 0.16 275 / 0.06);
}

.ql-ea-aside-title {
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-primary);
    margin: 0 0 2px;
}

.ql-ea-aside-desc {
    margin: 0;
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    line-height: 1.55;
}

.ql-ea-form-card {
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-xl);
    background: var(--fy-surface);
    padding: var(--fy-spacing-padding-xl);
    box-shadow: var(--fy-shadow-md);
}

/* Success state: superposition-collapse motif. */
.ql-ea-success-orb {
    width: 56px;
    height: 56px;
    margin: 0 auto var(--fy-spacing-stack-md);
    border-radius: 50%;
    border: 2px solid oklch(60% 0.16 155);
    display: flex;
    align-items: center;
    justify-content: center;
    color: oklch(55% 0.16 155);
    animation: ql-ea-collapse 0.9s var(--fy-easing-decelerate) both;
}

@keyframes ql-ea-collapse {
    0% {
        transform: scale(1.6);
        opacity: 0;
        box-shadow: 0 0 0 24px oklch(60% 0.16 155 / 0.25);
    }
    60% {
        transform: scale(0.94);
        opacity: 1;
        box-shadow: 0 0 0 6px oklch(60% 0.16 155 / 0.12);
    }
    100% {
        transform: scale(1);
        opacity: 1;
        box-shadow: 0 0 0 0 oklch(60% 0.16 155 / 0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .ql-ea-success-orb {
        animation: none;
    }
}

/* Cohort scarcity line under the form card. */
.ql-ea-scarcity {
    margin-top: var(--fy-spacing-stack-md);
    font-family: var(--ql-font-mono);
    font-size: var(--fy-font-size-xs);
    color: var(--fy-text-secondary);
    text-align: center;
}


/* ═══════════════════════════════════════════════════════════════════════════
   16. Benchmark paper — academic publication styling
   ═══════════════════════════════════════════════════════════════════════════ */

.ql-paper {
    max-width: 42rem;
    margin: 0 auto;
}

.ql-paper-abstract {
    background: var(--fy-surface-alt);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-lg);
    padding: var(--fy-spacing-padding-xl);
    margin-bottom: var(--fy-spacing-stack-2xl);
}

.ql-paper-abstract .ql-paper-section-title {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: 0 0 var(--fy-spacing-gap-sm);
}

.ql-paper-abstract-content {
    font-size: var(--fy-font-size-sm);
    color: var(--fy-text-secondary);
    line-height: 1.65;
}

.ql-paper-abstract-content p {
    margin: 0 0 var(--fy-spacing-gap-sm);
}

.ql-paper-abstract-content p:last-child {
    margin-bottom: 0;
}

.ql-paper-body h2 {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-xl);
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
    margin: var(--fy-spacing-stack-2xl) 0 var(--fy-spacing-gap-md);
    padding-bottom: var(--fy-spacing-gap-xs);
    border-bottom: 1px solid var(--fy-border);
    letter-spacing: var(--fy-letter-spacing-tight);
}

.ql-paper-body h3 {
    font-family: var(--fy-font-heading);
    font-size: var(--fy-font-size-lg);
    font-weight: var(--fy-font-weight-semibold);
    color: var(--fy-text-primary);
    margin: var(--fy-spacing-stack-xl) 0 var(--fy-spacing-gap-sm);
}

.ql-paper-body p {
    font-size: var(--fy-font-size-sm);
    line-height: 1.7;
    color: var(--fy-text-primary);
    margin: 0 0 var(--fy-spacing-gap-md);
    text-align: justify;
    hyphens: auto;
}

.ql-paper-body strong {
    font-weight: var(--fy-font-weight-bold);
    color: var(--fy-text-primary);
}

.ql-paper-body em {
    font-style: italic;
}

.ql-paper-body code {
    font-family: var(--fy-font-mono);
    font-size: 0.875em;
    background: var(--fy-surface-alt);
    padding: 1px 6px;
    border-radius: var(--fy-radius-sm);
    border: 1px solid var(--fy-border);
    color: var(--fy-brand-primary);
}

.ql-paper-body pre {
    background: var(--fy-surface-alt);
    border: 1px solid var(--fy-border);
    border-radius: var(--fy-radius-lg);
    padding: var(--fy-spacing-padding-lg);
    overflow-x: auto;
    margin: 0 0 var(--fy-spacing-stack-lg);
    font-size: 0.8rem;
    line-height: 1.6;
}

.ql-paper-body pre code {
    background: none;
    border: none;
    padding: 0;
    color: inherit;
}

.ql-paper-body blockquote {
    margin: 0 0 var(--fy-spacing-stack-lg);
    padding: var(--fy-spacing-padding-sm) var(--fy-spacing-padding-md);
    border-left: 3px solid var(--fy-brand-primary);
    background: var(--fy-surface-alt);
    border-radius: 0 var(--fy-radius-sm) var(--fy-radius-sm) 0;
    color: var(--fy-text-secondary);
    font-style: italic;
}

.ql-paper-body blockquote p {
    margin: 0;
}

.ql-paper-body ul, .ql-paper-body ol {
    margin: 0 0 var(--fy-spacing-gap-md);
    padding-left: 1.5em;
    font-size: var(--fy-font-size-sm);
    line-height: 1.7;
}

.ql-paper-body li {
    margin-bottom: var(--fy-spacing-gap-xs);
}

.ql-paper-body table {
    width: 100%;
    border-collapse: collapse;
    margin: var(--fy-spacing-stack-lg) 0;
    font-size: var(--fy-font-size-xs);
    border: 1px solid var(--fy-border);
}

.ql-paper-body th, .ql-paper-body td {
    padding: var(--fy-spacing-padding-sm) var(--fy-spacing-padding-md);
    border: 1px solid var(--fy-border);
    text-align: left;
}

.ql-paper-body th {
    background: var(--fy-surface-alt);
    font-weight: var(--fy-font-weight-semibold);
    font-size: var(--fy-font-size-xs);
    text-transform: uppercase;
    letter-spacing: var(--fy-letter-spacing-wide);
    color: var(--fy-text-secondary);
}

.ql-paper-body td {
    font-family: var(--fy-font-mono);
    font-variant-numeric: tabular-nums;
}

.ql-paper-body td:first-child {
    font-weight: var(--fy-font-weight-medium);
}

.ql-paper-body hr {
    border: none;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--fy-border), transparent);
    margin: var(--fy-spacing-stack-xl) 0;
}

.ql-paper-body a {
    color: var(--fy-brand-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.ql-paper-body a:hover {
    opacity: 0.8;
}

.ql-paper-body img {
    max-width: 100%;
    border-radius: var(--fy-radius-lg);
    border: 1px solid var(--fy-border);
    margin: var(--fy-spacing-stack-lg) 0;
}

@media (max-width: 640px) {
    .ql-paper-body p {
        text-align: left;
        hyphens: none;
    }

    .ql-paper {
        padding: 0;
    }
}


/* ── Button icons (fyrn Button::icon_html) ─────────────────────────── */
/* Inline-SVG icons sit inline with the label; the gap comes from the
   button's own flex gap in fyrn-css, so only vertical alignment is
   needed here. */

.fyn-btn-icon {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
}

.fyn-btn-icon:first-child {
    margin-left: 0;
    margin-right: 6px;
}

.fyn-btn-icon svg {
    display: block;
}
