/* =============================================================================
   AbuseScore design tokens
   =============================================================================

   The surface ramp, the radius scale, the elevation scale and the motion
   vocabulary. Loaded before theme.css so every component can lean on it.

   The ramp follows the way MagicUI builds depth on dark backgrounds, tinted
   into the brand palette. Dark surfaces never use a drop shadow to sit above
   the page. They get lighter by a fixed step and take a hairline of white at
   low alpha, which is what makes a card read as a physical layer instead of a
   rectangle of a slightly different colour.

   There is a layer BELOW the page as well. Code wells and inputs are recessed,
   not raised, and a design with only "page" and "card" always looks flat
   because nothing is ever cut into the surface.
   ========================================================================== */

:root {
    /* -- Which way the light falls ---------------------------------------- */
    /*
     * Two primitives, and everything that used to be a hardcoded
     * rgba(255,255,255,…) or rgba(0,0,0,…) goes through one of them.
     *
     * `--gloss` is the colour of light landing on a surface from above: every
     * hairline, every inner highlight, every faint wash. On a dark ground that
     * is white at low alpha; on a light one it has to be black, because a
     * white hairline on a white card is not an edge, it is nothing. The alpha
     * stays where each rule put it and only the colour flips, so the whole
     * elevation system inverts by changing one line.
     *
     * `--shade` is the colour of a drop shadow, and `--shadow-k` is how much
     * of it survives. A shadow tuned for a dark ground is far too heavy on a
     * light one: the same 0.8 alpha that reads as depth on #0b0f14 reads as
     * soot on #f6f8fa. Each shadow keeps its own relative weight and the whole
     * set is scaled by that one number.
     *
     * Specular highlights on saturated fills, the white lip along the top of
     * the green button, are NOT gloss. They are a reflection off a coloured
     * object and stay white in both themes, so they are still written as
     * literal white.
     */
    --gloss: 255 255 255;
    --shade: 0 0 0;
    --shadow-k: 1;

    /* -- Brand ------------------------------------------------------------ */
    --void:   #0b0f14;
    --panel:  #1c2530;
    --paper:  #e8ecef;
    --signal: #3ddc84;

    /*
     * The same green, as TEXT.
     *
     * #3ddc84 is a fill colour. It is 11:1 on the dark page and 1.9:1 on a
     * near-white one, so in the light palette every green link, every green
     * heading and every green figure on this site would be a rumour. Splitting
     * the two uses is what lets the brand fill stay exactly the brand fill
     * while the readable version moves: a green button is a green rectangle
     * with dark text on it and does not change, and `color: var(--signal-ink)`
     * darkens to #0f7a44, which is 4.94:1 and recognisably the same green.
     *
     * Rule of thumb: if it paints a shape, `--signal`. If somebody reads it,
     * `--signal-ink`.
     */
    --signal-ink: #3ddc84;

    /* Companions to the Signal Green, for gradients and beams. */
    --cyan:   #43d0ff;
    --violet: #a97cf8;
    --pink:   #fe8bbb;
    --amber:  #ffbe7b;

    /*
     * The same four, as TEXT, for the same reason `--signal-ink` exists.
     *
     * Every one of them is a bright colour chosen to glow on #0b0f14, and on a
     * near-white page they measure between 2.0:1 and 2.9:1. The aurora
     * headline is the worst case: it is the first sentence on the site and it
     * would be four pastel washes on white.
     */
    --cyan-ink:   #43d0ff;
    --violet-ink: #a97cf8;
    --pink-ink:   #fe8bbb;
    --amber-ink:  #ffbe7b;

    /* -- Surface ramp ----------------------------------------------------- */
    /* Each step is roughly +6 lightness. Below the page, then above it. */
    --surface-sunken: #06090d;   /* cut into the page: code wells, inputs   */
    --surface-page:   #0b0f14;   /* the page itself                         */
    --surface-1:      #111821;   /* cards, panels                           */
    --surface-2:      #182231;   /* raised: hovered rows, secondary buttons */
    --surface-3:      #1f2b3b;   /* the top of the stack: menus, popovers   */

    /* -- Hairlines -------------------------------------------------------- */
    /* White at low alpha, not a grey. A grey border goes muddy the moment a
       gradient passes under it; white alpha rides on top of whatever is
       beneath and always reads as an edge catching light. */
    --line:        rgb(var(--gloss) / .07);
    --line-strong: rgb(var(--gloss) / .12);
    --line-accent: rgba(61, 220, 132, .35);

    /* A third hairline, for edges that carry meaning rather than decoration.
       WCAG wants 3:1 on the boundary of a control, against both the face
       behind it and the fill inside it. --line-strong measures 1.18:1, which
       is right for a card edge and leaves a text input with no visible
       boundary at all until you focus it. */
    --line-control: rgba(255, 255, 255, .34);

    /* -- Text ------------------------------------------------------------- */
    --text:        #e8ecef;
    --text-muted:  #94a6b8;
    --text-dim:    #8496a8;   /* was #65788c, which measured 3.52:1 on surface-2 */

    /* -- Status ----------------------------------------------------------- */
    --danger: #ff6b6b;
    --warn:   #ffc86b;
    --info:   #6bb8ff;

    /* The fill and edge a destructive control sits on. Tokens rather than a
       literal tint, because the tint that reads as "careful" on a dark card
       reads as nothing at all on a white one. */
    --surface-danger:        rgba(255, 107, 107, .15);
    --surface-danger-strong: rgba(255, 107, 107, .26);
    --line-danger:           rgba(255, 107, 107, .4);

    /* -- Surfaces that are not on the ramp --------------------------------
       The last few places that paint a colour rather than a step. Each was a
       hex literal, which is fine until the page underneath it changes: a
       header painted #0b0f14 over a white page is a black bar with invisible
       links in it, and that is exactly what the light palette produced before
       these became tokens. */

    /* The sticky header, translucent so the page shows through the blur. */
    --surface-veil:      rgba(11, 15, 20, .72);
    /* The foot of the sidebar, where the panel darkens into the page. */
    --surface-sink:      #0e141c;
    /* The mobile menu panel: opaque, because it covers the page. */
    --surface-menu-top:  #151d27;
    --surface-menu-foot: #0d1219;
    /* A focused input, cut one step deeper than its resting state. */
    --surface-focus:     #080c11;
    /* The face of the accent pill, behind its gradient border. */
    --surface-pill:      #0e1f19;
    /* Scrollbar chrome and the meter track, which need a visible extent
       against the surface they sit on rather than a hairline. */
    --chrome:            #2b3847;
    --chrome-hover:      #3a4a5c;
    --track-edge:        #54636f;

    /* -- Radius ----------------------------------------------------------- */
    --radius:      12px;
    --radius-sm:   8px;
    --radius-md:   10px;
    --radius-lg:   14px;
    --radius-xl:   18px;
    --radius-full: 9999px;

    /* -- Elevation -------------------------------------------------------- */
    /* On a dark ground, elevation is an inner glow plus a hairline, never a
       drop shadow. The drop shadows here only deepen the ground beneath a
       floating element, they do not create the sense of lift by themselves. */
    --elev-1:
        inset 0 1px 0 rgb(var(--gloss) / .05),
        0 1px 2px rgb(var(--shade) / calc(.4 * var(--shadow-k)));

    --elev-2:
        inset 0 1px 0 rgb(var(--gloss) / .06),
        inset 0 -24px 60px -24px rgb(var(--gloss) / .07),
        0 2px 4px rgb(var(--shade) / calc(.45 * var(--shadow-k))),
        0 12px 28px -8px rgb(var(--shade) / calc(.55 * var(--shadow-k)));

    --elev-3:
        inset 0 1px 0 rgb(var(--gloss) / .08),
        0 4px 8px rgb(var(--shade) / calc(.5 * var(--shadow-k))),
        0 24px 48px -12px rgb(var(--shade) / calc(.7 * var(--shadow-k)));

    /* The single most useful line in the whole system. An inner bottom-lit
       lip turns a flat pill into an object with a top and a bottom. */
    --lip:        inset 0 -8px 10px -6px rgb(var(--gloss) / .14);
    --lip-hover:  inset 0 -6px 10px -4px rgba(255, 255, 255, .26);
    --lip-active: inset 0 -10px 10px -6px rgba(255, 255, 255, .26);

    /* Accent glow, for anything that should look energised. */
    --glow-signal: 0 0 0 1px rgba(61, 220, 132, .28), 0 14px 40px -16px rgba(61, 220, 132, .45);

    /* -- Type ------------------------------------------------------------- */
    /* The Fallback faces are metric-matched to the real ones and must stay
       second, ahead of the generic keywords: those resolve 14% wider and turn
       the font swap into a several-hundred-pixel reflow. See fonts.css. */
    --sans: 'Outfit', 'Outfit Fallback', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --mono: 'DM Mono', 'DM Mono Fallback', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

    /* A 1.2 modular scale, clamped so it holds on a phone. */
    --text-xs:   .78rem;
    --text-sm:   .875rem;
    --text-base: 1rem;
    --text-lg:   1.125rem;
    --text-xl:   clamp(1.2rem, 1.6vw, 1.35rem);
    --text-2xl:  clamp(1.45rem, 2.4vw, 1.75rem);
    --text-3xl:  clamp(1.75rem, 3.4vw, 2.3rem);
    --text-4xl:  clamp(2.2rem, 5vw, 3.4rem);
    --text-5xl:  clamp(2.6rem, 6.4vw, 4.2rem);

    /* A fixed length, not 66ch, and that matters more than it looks.
       `ch` is the advance width of "0" in the RESOLVED font, so the column
       itself changes width when the family does: 726px in Outfit, 594px in
       the fallback. The whole prose page then reflows during the font swap,
       by 477px on /legal/terms at desk width. 45.5rem is the width Outfit
       was already producing, so nothing moves and nothing looks different. */
    --measure: 45.5rem;

    /* -- Rhythm ----------------------------------------------------------- */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
    --space-8: 64px;
    --space-9: 96px;

    --shell-max: 1180px;
    --nav-height: 64px;
    --sidebar-width: 268px;

    /* -- Motion ----------------------------------------------------------- */
    --ease-out:    cubic-bezier(.22, .68, .36, 1);
    --ease-expo:   cubic-bezier(.16, 1, .3, 1);
    --ease-spring: cubic-bezier(.34, 1.26, .64, 1);
    --t-fast:   150ms;
    --t-base:   250ms;
    --t-slow:   400ms;
}

:root {
    color-scheme: dark;
}

/* =============================================================================
   Light
   =============================================================================

   The design is dark by intent and dark is the default. This is the palette
   for somebody who asked for the other one, which is a real request on a bright
   screen in an office, and refusing it is not a design decision, it is a
   shrug.

   Only tokens are redefined. Not one component rule is duplicated here, and
   that is the whole reason the sweep above was worth doing: with `--gloss` and
   `--shade` doing the work, inverting the elevation system is six lines rather
   than six hundred.

   ## The ramp is not the dark one inverted

   Flipping #06090d to #f9f6f2 would put the SUNKEN layer above the page, and a
   recessed input would read as a raised one. The order is kept and the whole
   ramp is rebuilt going the other way: sunken is the darkest, the page sits
   above it, and cards are lighter still. Pure white is never used for a
   surface. It is the brightest thing a monitor can do, it leaves nothing above
   it for a card to be, and against black text at that size it is the contrast
   people describe as glare.

   ## The green does not survive unchanged

   #3ddc84 measures 1.63:1 on a near-white ground, so the colour that carries
   every action on this site would be unreadable as text. The surface uses stay
   as they are, because a green button is a green fill with dark text on it,
   but anywhere the green IS the text it is darkened to #0f7a44, which measures
   4.94:1. It is recognisably the same green and it can be read.
   ========================================================================== */

:root[data-appearance='light'] {
    color-scheme: light;

    --gloss: 15 23 33;
    --shade: 20 34 48;
    /* Shadows carry the lift on a light ground, where there is no inner glow
       to do it, but at a fraction of the weight. */
    --shadow-k: .16;

    --void:  #f3f5f7;
    --paper: #10161d;

    /* Sunken stays BELOW the page and the page stays below a card. Same
       direction as the dark ramp, different absolute values. */
    --surface-sunken: #e7ebef;
    --surface-page:   #f3f5f7;
    --surface-1:      #ffffff;
    --surface-2:      #f7f9fb;
    --surface-3:      #ffffff;

    --line:        rgb(var(--gloss) / .1);
    --line-strong: rgb(var(--gloss) / .16);
    --line-accent: rgba(15, 122, 68, .4);
    --line-control: rgb(var(--gloss) / .34);

    --text:       #10161d;
    --text-muted: #46566a;
    --text-dim:   #54626f;   /* 4.72:1 on the code bar, which is the darkest ground it lands on */

    /* The signal green as TEXT. 4.94:1 on #f3f5f7 against 1.63:1 for the
       original, which is the difference between a link and a rumour. */
    --signal-ink: #0f7a44;
    --cyan-ink:   #0b6fa8;
    --violet-ink: #6a3fc0;
    --pink-ink:   #b8286e;
    --amber-ink:  #8a5a00;
    --danger: #c02626;
    --warn:   #8a5a00;
    --info:   #0b5fa8;

    --surface-danger:        rgba(192, 38, 38, .08);
    --surface-danger-strong: rgba(192, 38, 38, .15);
    --line-danger:           rgba(192, 38, 38, .35);
    --surface-veil:      rgba(247, 249, 251, .78);
    --surface-sink:      #eceff3;
    --surface-menu-top:  #ffffff;
    --surface-menu-foot: #f4f6f9;
    --surface-focus:     #ffffff;
    --surface-pill:      #e9f6ee;
    --chrome:            #b9c4cf;
    --chrome-hover:      #9aa8b6;
    --track-edge:        #aab6c2;

    /* An inner lip is light catching the bottom edge of a raised object. On a
       light ground there is no light to catch, so it is a shadow instead, and
       a much quieter one: at dark-theme strength it looks like dirt. */
    --lip:        inset 0 -8px 10px -6px rgb(var(--gloss) / .05);
    --lip-hover:  inset 0 -6px 10px -4px rgb(var(--gloss) / .08);
    --lip-active: inset 0 -10px 10px -6px rgb(var(--gloss) / .08);

    --glow-signal:
        0 0 0 1px rgba(15, 122, 68, .3),
        0 10px 26px -14px rgba(15, 122, 68, .45);
}

/* The system setting, for somebody who has not chosen. `data-appearance` is
   stamped only when they have, so an explicit dark choice wins here and an
   explicit light choice is matched by the rule above.

   The attribute selector is repeated rather than nesting the light block,
   because `@media` and `[data-appearance]` carry the same specificity and the
   later rule would otherwise beat the explicit choice on a light system. */
@media (prefers-color-scheme: light) {
    :root[data-appearance='system'] {
        color-scheme: light;

        --gloss: 15 23 33;
        --shade: 20 34 48;
        --shadow-k: .16;

        --void:  #f3f5f7;
        --paper: #10161d;

        --surface-sunken: #e7ebef;
        --surface-page:   #f3f5f7;
        --surface-1:      #ffffff;
        --surface-2:      #f7f9fb;
        --surface-3:      #ffffff;

        --line:        rgb(var(--gloss) / .1);
        --line-strong: rgb(var(--gloss) / .16);
        --line-accent: rgba(15, 122, 68, .4);
        --line-control: rgb(var(--gloss) / .34);

        --text:       #10161d;
        --text-muted: #46566a;
        --text-dim:   #54626f;   /* 4.72:1 on the code bar, which is the darkest ground it lands on */

        --signal-ink: #0f7a44;
        --cyan-ink:   #0b6fa8;
        --violet-ink: #6a3fc0;
        --pink-ink:   #b8286e;
        --amber-ink:  #8a5a00;
        --danger: #c02626;
        --warn:   #8a5a00;
        --info:   #0b5fa8;

        --surface-danger:        rgba(192, 38, 38, .08);
        --surface-danger-strong: rgba(192, 38, 38, .15);
        --line-danger:           rgba(192, 38, 38, .35);
        --surface-veil:      rgba(247, 249, 251, .78);
        --surface-sink:      #eceff3;
        --surface-menu-top:  #ffffff;
        --surface-menu-foot: #f4f6f9;
        --surface-focus:     #ffffff;
        --surface-pill:      #e9f6ee;
        --chrome:            #b9c4cf;
        --chrome-hover:      #9aa8b6;
        --track-edge:        #aab6c2;

        --lip:        inset 0 -8px 10px -6px rgb(var(--gloss) / .05);
        --lip-hover:  inset 0 -6px 10px -4px rgb(var(--gloss) / .08);
        --lip-active: inset 0 -10px 10px -6px rgb(var(--gloss) / .08);

        --glow-signal:
            0 0 0 1px rgba(15, 122, 68, .3),
            0 10px 26px -14px rgba(15, 122, 68, .45);
    }
}
