/* =========================================================================
   Elevation Layer — premium depth, glass, and spring motion
   -------------------------------------------------------------------------
   Loaded AFTER style.css, so it composes over the existing design system
   rather than replacing it. Nothing here introduces a new palette: every
   value derives from style.css's section-1 tokens, so the light/dark swap
   still holds and the ~40 feature component blocks keep working untouched.

   Contents:
     1. depth + glass tokens
     2. ambient canvas (the gradient mesh behind everything)
     3. surface elevation — cards read as objects, not outlines
     4. control polish — buttons, fields, nav
     5. motion primitives — reveal + tilt
   ========================================================================= */

/* =========================================================================
   1. DEPTH TOKENS
   ========================================================================= */
:root {
    /* Layered shadows. A single shadow reads flat; a tight contact shadow plus
       a wide diffuse one is what gives an element physical weight. */
    --d-1: 0 1px 2px rgba(0, 0, 0, .28), 0 1px 1px rgba(0, 0, 0, .16);
    --d-2: 0 2px 4px rgba(0, 0, 0, .26), 0 6px 16px -4px rgba(0, 0, 0, .42);
    --d-3: 0 4px 8px rgba(0, 0, 0, .3), 0 16px 40px -10px rgba(0, 0, 0, .55);
    --d-4: 0 8px 16px rgba(0, 0, 0, .32), 0 32px 72px -16px rgba(0, 0, 0, .68);

    /* Top-edge highlight. Light falls from above, so a 1px inset white line on
       the top edge is what separates a raised surface from a printed one. */
    --edge-top: inset 0 1px 0 rgba(255, 255, 255, .07);
    --edge-top-strong: inset 0 1px 0 rgba(255, 255, 255, .12);

    /* Glass */
    --glass-bg: rgba(22, 25, 34, .62);
    --glass-border: rgba(255, 255, 255, .09);
    --glass-blur: blur(20px) saturate(160%);

    /* Accent glow — focus rings, primary CTAs, hero orbs. */
    --glow-accent: 0 8px 28px -6px rgba(139, 92, 246, .5);
    --glow-accent-lg: 0 16px 56px -10px rgba(139, 92, 246, .55);

    /* Gradient mesh stops for the ambient canvas. */
    --mesh-1: rgba(139, 92, 246, .16);
    --mesh-2: rgba(56, 189, 248, .1);
    --mesh-3: rgba(217, 70, 239, .08);

    /* Display type. Marketing headlines need a larger, tighter ramp than the
       console's --fs-* scale, which tops out at 1.875rem. Fluid so a hero
       headline never needs a breakpoint of its own. */
    --fs-d1: clamp(2.75rem, 6.5vw, 4.75rem);
    --fs-d2: clamp(2rem, 4.2vw, 3rem);
    --fs-d3: clamp(1.5rem, 2.6vw, 2rem);
    --fs-lead: clamp(1rem, 1.4vw, 1.1875rem);

    /* Springs. style.css's --ease is right for state changes; these are for
       movement, where a little overshoot reads as physical. */
    --spring: cubic-bezier(.34, 1.56, .64, 1);
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --dur-slow: .45s;

    --shell-max: 1240px;
}

[data-theme="light"] {
    --d-1: 0 1px 2px rgba(15, 23, 42, .06), 0 1px 1px rgba(15, 23, 42, .04);
    --d-2: 0 2px 4px rgba(15, 23, 42, .05), 0 6px 16px -4px rgba(15, 23, 42, .1);
    --d-3: 0 4px 8px rgba(15, 23, 42, .06), 0 16px 40px -10px rgba(15, 23, 42, .14);
    --d-4: 0 8px 16px rgba(15, 23, 42, .07), 0 32px 72px -16px rgba(15, 23, 42, .18);

    --edge-top: inset 0 1px 0 rgba(255, 255, 255, .9);
    --edge-top-strong: inset 0 1px 0 rgba(255, 255, 255, 1);

    --glass-bg: rgba(255, 255, 255, .72);
    --glass-border: rgba(15, 23, 42, .08);

    --glow-accent: 0 8px 28px -6px rgba(124, 58, 237, .28);
    --glow-accent-lg: 0 16px 56px -10px rgba(124, 58, 237, .32);

    --mesh-1: rgba(124, 58, 237, .1);
    --mesh-2: rgba(14, 165, 233, .08);
    --mesh-3: rgba(217, 70, 239, .05);
}

/* =========================================================================
   2. AMBIENT CANVAS
   -------------------------------------------------------------------------
   A fixed, non-interactive gradient mesh. Fixed rather than scrolled so the
   light sources stay put while content moves past them — that parallax between
   content and lighting is what makes the page feel like it has depth.
   ========================================================================= */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -2;
    pointer-events: none;
    background:
        radial-gradient(60rem 40rem at 15% -5%, var(--mesh-1), transparent 60%),
        radial-gradient(50rem 36rem at 95% 5%, var(--mesh-2), transparent 62%),
        radial-gradient(46rem 34rem at 60% 100%, var(--mesh-3), transparent 60%);
}

/* Fine grain over the mesh. Wide, low-contrast gradients band badly on 8-bit
   panels; a low-opacity noise tile breaks up the stepping. */
body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: .022;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* =========================================================================
   3. SURFACE ELEVATION
   ========================================================================= */
.card,
.stat-card,
.panel-section,
.manage-section,
.website-section,
.support-section,
.api-section,
.datasets-section {
    box-shadow: var(--d-2), var(--edge-top);
    transition:
        transform var(--dur) var(--ease-out),
        box-shadow var(--dur) var(--ease-out),
        border-color var(--dur) var(--ease);
}

/* Lift on hover. translate3d promotes the element to its own compositor layer
   so the shadow transition is composited rather than repainted each frame. */
.stat-card:hover,
.card:hover {
    transform: translate3d(0, -3px, 0);
    box-shadow: var(--d-3), var(--edge-top-strong);
    border-color: var(--border-strong);
}

/* Stat tiles get a hairline accent on the top edge that ignites on hover — a
   cheap, quiet signal that the tile is a live object. */
.stat-card {
    position: relative;
    overflow: hidden;
}

.stat-card::after {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    opacity: 0;
    transition: opacity var(--dur) var(--ease);
}

.stat-card:hover::after {
    opacity: .9;
}

.stat-ic {
    box-shadow: var(--d-1), var(--edge-top);
}

/* --- Glass utility ------------------------------------------------------ */
.glass {
    background: var(--glass-bg);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border: 1px solid var(--glass-border);
    box-shadow: var(--d-3), var(--edge-top);
}

/* =========================================================================
   4. CONTROL POLISH
   ========================================================================= */

/* Primary buttons read as lit objects: gradient body, top highlight, and a
   coloured glow that intensifies on hover. */
.btn-primary {
    background: linear-gradient(180deg, var(--brand-500), var(--brand-600));
    box-shadow: var(--d-1), var(--edge-top-strong);
    transition:
        transform var(--dur-fast) var(--ease-out),
        box-shadow var(--dur) var(--ease-out),
        filter var(--dur) var(--ease);
}

.btn-primary:hover {
    transform: translate3d(0, -1px, 0);
    box-shadow: var(--glow-accent), var(--edge-top-strong);
    filter: brightness(1.06);
}

/* The press travels further than the hover lift, so the click reads as a click. */
.btn-primary:active,
.btn-secondary:active,
.btn-ghost:active {
    transform: translate3d(0, 1px, 0);
    transition-duration: .06s;
}

.btn-secondary {
    box-shadow: var(--d-1), var(--edge-top);
    transition:
        transform var(--dur-fast) var(--ease-out),
        box-shadow var(--dur) var(--ease-out),
        border-color var(--dur) var(--ease);
}

.btn-secondary:hover {
    transform: translate3d(0, -1px, 0);
    box-shadow: var(--d-2), var(--edge-top-strong);
}

/* Fields are sunken — the inverse of a button, so the two are never confused
   at a glance. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="url"],
input[type="search"],
input[type="tel"],
select,
textarea {
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, .18);
    transition:
        border-color var(--dur) var(--ease),
        box-shadow var(--dur) var(--ease),
        background var(--dur) var(--ease);
}

input:focus,
select:focus,
textarea:focus {
    box-shadow: var(--ring), inset 0 1px 2px rgba(0, 0, 0, .1);
}

[data-theme="light"] input[type="text"],
[data-theme="light"] input[type="email"],
[data-theme="light"] input[type="password"],
[data-theme="light"] input[type="number"],
[data-theme="light"] input[type="url"],
[data-theme="light"] input[type="search"],
[data-theme="light"] input[type="tel"],
[data-theme="light"] select,
[data-theme="light"] textarea {
    box-shadow: inset 0 1px 2px rgba(15, 23, 42, .05);
}

/* App topbar sits on the glass tokens so it matches the marketing header. */
.navbar {
    background: var(--glass-bg);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    box-shadow: 0 1px 0 var(--border), 0 8px 24px -16px rgba(0, 0, 0, .8);
}

.brand-mark {
    box-shadow: var(--glow-accent), var(--edge-top-strong);
}

/* Sidebar items slide a touch on hover; the active one carries a glowing bar. */
.panel-nav a,
.nav-item {
    position: relative;
    transition:
        background var(--dur) var(--ease),
        color var(--dur) var(--ease),
        transform var(--dur) var(--ease-out);
}

.panel-nav a:hover,
.nav-item:hover {
    transform: translate3d(2px, 0, 0);
}

.panel-nav a.is-active::before,
.nav-item.is-active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 3px;
    height: 18px;
    transform: translateY(-50%);
    border-radius: 0 var(--r-full) var(--r-full) 0;
    background: var(--accent);
    box-shadow: 0 0 12px var(--accent);
}

/* =========================================================================
   5. MOTION PRIMITIVES
   -------------------------------------------------------------------------
   [data-reveal] elements start displaced and are released by the
   IntersectionObserver in base.html adding .is-in. The .no-js rule is the
   fallback: if the script never runs, content must still be visible.
   ========================================================================= */
[data-reveal] {
    opacity: 0;
    transform: translate3d(0, 22px, 0);
    transition:
        opacity var(--dur-slow) var(--ease-out),
        transform var(--dur-slow) var(--ease-out);
    transition-delay: var(--reveal-delay, 0s);
}

[data-reveal].is-in {
    opacity: 1;
    transform: none;
}

.no-js [data-reveal] {
    opacity: 1;
    transform: none;
}

/* Tilt: a 3D hover for feature cards. The perspective lives on the parent so
   the children share one vanishing point instead of each having its own. */
.tilt-scope {
    perspective: 1200px;
}

.tilt {
    transform-style: preserve-3d;
    transition:
        transform var(--dur-slow) var(--ease-out),
        box-shadow var(--dur-slow) var(--ease-out);
}

.tilt:hover {
    box-shadow: var(--d-4), var(--edge-top-strong);
}

@media (prefers-reduced-motion: reduce) {
    [data-reveal] {
        opacity: 1;
        transform: none;
    }

    .stat-card:hover,
    .card:hover,
    .btn-primary:hover,
    .btn-secondary:hover,
    .panel-nav a:hover,
    .nav-item:hover,
    .tilt:hover {
        transform: none;
    }
}

/* =========================================================================
   6. CONSOLE DEPTH
   -------------------------------------------------------------------------
   The dashboard and admin panel are working surfaces, so the treatment here is
   deliberately quieter than the marketing pages: depth and material, but no
   orbs, no gradient text and no large-scale movement. Someone reads these
   screens every day — the chrome has to stay out of the way.
   ========================================================================= */

/* --- Stat tiles ----------------------------------------------------------
   Overrides the flatter --e-1/--e-2 pair from style.css so the tiles sit in
   the same light as everything else in this layer. */
.stat-card {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, .028), transparent 42%),
        var(--surface);
    box-shadow: var(--d-2), var(--edge-top);
}

.stat-card:hover {
    box-shadow: var(--d-3), var(--edge-top-strong);
}

/* The icon chip is the tile's brightest point, so it carries a real glow
   rather than the flat accent-soft fill. */
.stat-ic {
    background: linear-gradient(160deg, var(--accent-soft), transparent 70%), var(--accent-soft);
    border: 1px solid var(--accent-line);
    box-shadow: var(--d-1), var(--edge-top-strong);
}

.stat-card:hover .stat-ic {
    box-shadow: var(--glow-accent), var(--edge-top-strong);
}

/* Tilt for the console: half the marketing travel. A working surface should
   acknowledge the pointer, not perform for it. */
.tilt-scope .stat-card.tilt {
    transition:
        transform var(--dur) var(--ease-out),
        box-shadow var(--dur) var(--ease-out),
        border-color var(--dur) var(--ease);
}

.tilt-scope .stat-card.tilt:hover {
    transform: translate3d(0, -3px, 0) rotateX(2.5deg) rotateY(-2deg);
}

/* --- Content panels ------------------------------------------------------ */
.website-section,
.support-section,
.api-section,
.datasets-section,
.panel-section,
.manage-section {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, .022), transparent 38%),
        var(--surface);
    box-shadow: var(--d-2), var(--edge-top);
}

/* Panels are containers, not controls: they gain light on hover but never
   move. Only things that can be clicked should travel. */
.website-section:hover,
.support-section:hover,
.api-section:hover,
.datasets-section:hover,
.panel-section:hover,
.manage-section:hover {
    box-shadow: var(--d-3), var(--edge-top-strong);
    border-color: var(--border-strong);
}

/* --- Sidebar -------------------------------------------------------------
   Deliberately NOT backdrop-filter: the rail is its own scroll container
   (overflow-y: auto in style.css), so a backdrop filter would blur its own
   scrolled contents rather than the page behind it. A vertical gradient plus a
   cast shadow gives the same sense of a separate plane without that artifact. */
.client-sidebar,
.panel-sidebar {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, .025), transparent 30%),
        var(--surface-sunken);
    box-shadow: 1px 0 0 var(--border), 8px 0 24px -20px rgba(0, 0, 0, .9);
}

/* The account card at the sidebar's base reads as a raised object so the
   footer does not dissolve into the rail. */
.sidebar-user {
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--surface-raised);
    box-shadow: var(--d-1), var(--edge-top);
}

/* --- Meters --------------------------------------------------------------
   A groove with an inset shadow and a lit fill: the two together are what make
   the bar read as carved rather than drawn. */
.meter-track {
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, .35);
}

[data-theme="light"] .meter-track {
    box-shadow: inset 0 1px 2px rgba(15, 23, 42, .12);
}

.meter-fill {
    box-shadow:
        0 0 12px -2px var(--accent),
        inset 0 1px 0 rgba(255, 255, 255, .3);
}

.meter-fill.is-full {
    box-shadow:
        0 0 12px -2px var(--red-500),
        inset 0 1px 0 rgba(255, 255, 255, .3);
}

/* --- Tables --------------------------------------------------------------
   An opaque header, so rows passing under a sticky header are hidden rather
   than showing through. Scoped to .data-table to match style.css. */
.data-table thead th {
    background: var(--surface-sunken);
    box-shadow: inset 0 -1px 0 var(--border);
}

.data-table tbody tr {
    transition: background var(--dur-fast) var(--ease);
}

.data-table tbody tr:hover {
    background: var(--surface-hover);
}

/* --- Empty states -------------------------------------------------------- */
.empty-state {
    border: 1px dashed var(--border-strong);
    border-radius: var(--r-lg);
    background: var(--surface-sunken);
}

.empty-state svg {
    opacity: .55;
}

/* --- Page header ---------------------------------------------------------
   style.css already draws a flat border-bottom here. Replacing it with a
   gradient hairline that fades out to the right separates the header from the
   body without a hard rule running the full width of the column. */
.panel-header,
.dashboard-header {
    position: relative;
    border-bottom-color: transparent;
}

.panel-header::after,
.dashboard-header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 1px;
    background: linear-gradient(90deg, var(--border-strong), transparent 70%);
}

@media (prefers-reduced-motion: reduce) {
    .tilt-scope .stat-card.tilt:hover {
        transform: none;
    }
}
