/*
   Self-hosted fonts (audit L-2, owner ruling 2026-10-10).

   Replaces `@import url("https://fonts.googleapis.com/...")`. That import had three problems and
   only the first is the obvious one: it fetched the CSS and the font files from a third party,
   leaking every visitor's IP and Referer to Google; it could not carry an SRI hash, so the bytes
   were trusted on transport alone; and — the one that mattered for CSP — a remote `@import` means
   the page's `style-src` and `font-src` must name an external origin, which is exactly the
   allowance `script-src 'self'` work wants to remove.

   Four files, not sixteen: Outfit and JetBrains Mono both ship as VARIABLE fonts, so all five
   Outfit weights and all three JetBrains weights resolve to one file per subset. Serving the
   per-weight copies Google's API returns would have been five identical downloads.

   Only `latin` and `latin-ext` are kept. The upstream CSS also declares cyrillic, greek and
   vietnamese subsets — none of which this market's UI can produce text in, and each of which would
   have been another 20-60 KB of font data per page load for glyphs no user will see.

   `font-display: swap` and the `unicode-range` declarations are copied from the upstream CSS
   unchanged. The ranges are load-bearing rather than descriptive: they are what tells the browser
   a `latin-ext` file need not be fetched for a page of plain ASCII.
*/
@font-face {
    font-family: "Outfit";
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url("../vendor/fonts/outfit-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Outfit";
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url("../vendor/fonts/outfit-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../vendor/fonts/jetbrains-mono-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "JetBrains Mono";
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../vendor/fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    --bg-dark: #0a0a0a;
    --bg-card: rgba(20, 20, 20, 0.95);
    --bg-card-solid: #141414;
    --border-dark: rgba(255, 255, 255, 0.12);
    --border-glow: rgba(0, 240, 255, 0.3);

    /* 赛博朋克未来风：霓虹青与洋红 */
    --cyan: #00f0ff;
    --cyan-bright: #5cffff;
    --cyan-glow: rgba(0, 240, 255, 0.4);
    --magenta: #ff007f;
    --magenta-glow: rgba(255, 0, 127, 0.15);

    /* The position chart's curve, and the only gold in the product.
       It is a token rather than a literal in `chart.js` for the reason every other colour here is
       one, but it is also a NEW token rather than a reuse, and that part was a decision: `--amber`
       is the nearest existing colour and it is already the warning colour. A price line drawn in
       the warning colour reads as a warning about the price, on a chart whose whole job is to
       show a price behaving normally. */
    --gold: #f2c14e;
    --gold-glow: rgba(242, 193, 78, 0.55);

    /* 状态与语义色 */
    --green: #10b981;
    --green-glow: rgba(16, 185, 129, 0.4);
    --red: #ef4444;
    --amber: #f59e0b;

    --text-primary: #f8fafc;
    /* The two greys, both lifted 50% in HSL lightness (task 2026-09-15: "所有的灰色字体颜色都太暗了，
       把灰色全部调亮 50%"). L 34% → 51% and L 66% → 99%, hue and saturation untouched, so both stay
       the same greys on the same background — only further from it. `--text-secondary` lands on a
       colour a hair off #ffffff; it still reads as a secondary grey against `--bg-dark` because the
       figure that matters is the ratio to the ground, not to white.

       These two variables are the whole of it: every grey in the product is one of them (the
       disabled button's own `#475569` literal below is the one exception, and it moved with them).
       Nothing else was touched — the borders and the background washes are not type, and brightening
       them would lighten the panels rather than the text. */
    --text-secondary: #ced7e2;
    --text-muted: #809cc4;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Outfit", sans-serif;
}
body {
    background: var(--bg-dark);
    color: var(--text-primary);
    min-height: 100vh;
    overflow-x: hidden;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}

/* 霓虹渐变网格与光晕背景 */
.grid-bg {
    position: fixed;
    inset: 0;
    z-index: -2;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
    background-size: 60px 60px;
}
.glow-bg {
    position: fixed;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(
            ellipse at 20% 0%,
            rgba(0, 240, 255, 0.08) 0%,
            transparent 50%
        ),
        radial-gradient(
            ellipse at 80% 100%,
            rgba(255, 0, 127, 0.05) 0%,
            transparent 50%
        );
}

.header {
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 100;
    padding: 16px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: rgba(10, 10, 10, 0.85);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border-dark);
}
.menu-btn {
    width: 44px;
    height: 44px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 6px;
    background: var(--bg-card);
    border: 1px solid var(--border-dark);
    border-radius: 12px;
    cursor: pointer;
    transition:
        border-color 0.3s,
        box-shadow 0.3s;
}
.menu-btn:hover {
    border-color: var(--cyan);
    box-shadow: 0 0 15px var(--cyan-glow);
}
.menu-btn span {
    width: 18px;
    height: 2px;
    background: var(--cyan);
    border-radius: 1px;
}

.brand-logo {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    /* Relative to THIS file: the sheet lives in css/ and the asset in assets/, so a bare
       "assets/logo.png" resolved to /css/assets/logo.png and 404'd on all four pages, leaving
       every header logo an empty box (round one M-1). */
    background-image: url("../assets/logo.png");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    box-shadow: 0 0 10px rgba(0, 240, 255, 0.2);
    /* No `:hover` glow, and so no transition to animate one: the mark stopped being a link
       (task 2026-09-21), and a highlight that follows the cursor is the page still advertising a
       tap target that is gone. Dropping the anchor also drops the pointer cursor, which is the
       other half of the same promise. */
}

.wallet-info {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    background: var(--bg-card);
    border: 1px solid var(--border-dark);
    border-radius: 12px;
    font-family: "JetBrains Mono", monospace;
    font-size: 13px;
    transition: border-color 0.3s;
}
.wallet-info:hover {
    border-color: rgba(0, 240, 255, 0.4);
}
.wallet-dot {
    width: 8px;
    height: 8px;
    background: var(--cyan);
    border-radius: 50%;
    box-shadow: 0 0 10px var(--cyan-glow);
}

/* The wallet is connected but not on this deployment's chain (task 2026-09-15).
   Amber, not red: nothing is broken and nothing is lost — the user is one tap away from the state
   the header wants, and the box's own label already says which tap that is. Red is reserved for
   the failures this product reports as errors (`toast.*.level: error`), and dressing a switch
   prompt as a failure would teach users to read the header's colour as a verdict on their wallet.
   `.wallet-info` is a `div` built by `shell.js`, so the state class is toggled from there. */
.wallet-info.off-chain {
    border-color: rgba(245, 158, 11, 0.4);
}
.wallet-info.off-chain .wallet-dot {
    background: var(--amber);
    box-shadow: 0 0 10px rgba(245, 158, 11, 0.4);
}
.wallet-info.off-chain #shell-account {
    color: var(--amber);
}

.nav-overlay {
    position: fixed;
    inset: 0;
    background: rgba(10, 10, 10, 0.8);
    z-index: 200;
    opacity: 0;
    visibility: hidden;
    transition:
        opacity 0.3s,
        visibility 0.3s;
    will-change: opacity;
}
.nav-overlay.active {
    opacity: 1;
    visibility: visible;
}
.side-nav {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    max-width: 320px;
    z-index: 201;
    background: var(--bg-card-solid);
    transform: translateX(-100%);
    transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
    padding: 40px 20px;
    border-right: 1px solid var(--border-glow);
    will-change: transform;
}
.side-nav.active {
    transform: translateX(0);
}

.nav-link {
    display: block;
    padding: 16px;
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 18px;
    border-radius: 12px;
    margin-bottom: 8px;
    transition:
        background-color 0.3s,
        color 0.3s,
        border-color 0.3s;
    border: 1px solid transparent;
}
.nav-link:hover,
.nav-link.active {
    background: rgba(0, 240, 255, 0.05);
    color: var(--cyan);
    border-color: var(--border-dark);
}

.main {
    padding: 90px 20px 40px;
    max-width: 600px;
    margin: 0 auto;
}
.card,
.panel {
    background: var(--bg-card);
    border: 1px solid var(--border-dark);
    border-radius: 20px;
    padding: 20px;
    margin-bottom: 20px;
}
.panel {
    display: none;
}
.panel.active {
    display: block;
    animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.card-title {
    font-size: 16px;
    font-weight: 600;
    color: var(--cyan);
    margin-bottom: 16px;
    border-bottom: 1px solid var(--border-dark);
    padding-bottom: 10px;
}

.input-group {
    background: rgba(0, 0, 0, 0.3);
    border: 1px solid var(--border-dark);
    border-radius: 16px;
    padding: 16px;
    margin-bottom: 16px;
    transition: border-color 0.3s;
}
.input-group:focus-within {
    border-color: var(--cyan);
}
.input-header {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    color: var(--text-muted);
    margin-bottom: 10px;
}
.input-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* 带有呼吸感光效的按钮 */
.btn-submit {
    width: 100%;
    padding: 16px;
    margin-top: 16px;
    background: var(--cyan);
    color: #000000;
    border: none;
    border-radius: 12px;
    font-weight: 700;
    font-size: 16px;
    cursor: pointer;
    text-transform: uppercase;
    box-shadow: 0 0 15px var(--cyan-glow);
    transition:
        transform 0.2s,
        box-shadow 0.2s,
        background 0.3s;
}
.btn-submit:hover {
    box-shadow: 0 0 25px var(--cyan-glow);
    background: var(--cyan-bright);
}
.btn-submit:active {
    transform: scale(0.98);
}
.btn-submit:disabled {
    background: #1e293b;
    color: #6a80a1;
    box-shadow: none;
    cursor: not-allowed;
}

/* ── Modals (shared across pages) ──
   `.custom-modal-overlay` lived here, copied from the previous project where it styles a
   template's *dismissable* overlays: `display: none; opacity: 0`, shown by a script adding
   `.show`. This project builds its modals in JS instead, and it built them with that class name
   plus inline geometry — inline `display: flex` beat the `display: none`, but nothing ever
   assigned `opacity`, so every modal was 0%-opaque and invisible. The rule is gone; the
   backdrop for every modal is now `.modal-layer` in css/app.css (see `Toast.overlay()`).
   `.custom-modal-close` below is kept — it is the close button's hit area, and every modal's
   close button wears it. */
.custom-modal-close {
    background: none;
    border: none;
    padding: 0;
    position: absolute;
    top: 12px;
    right: 16px;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.3s;
    width: 24px;
    height: 24px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 22px;
    line-height: 1;
    user-select: none;
}
.custom-modal-close:hover {
    color: var(--amber);
}
.custom-modal-close.cyan-hover:hover {
    color: var(--cyan);
}
.custom-modal-title {
    font-size: 18px;
    font-weight: 600;
    margin-bottom: 16px;
    padding-right: 24px;
}
