/* ============================================================================
   Orbit Axis — Design Tokens
   ----------------------------------------------------------------------------
   The single source of truth for every visual value in the app. Nothing below
   this layer hardcodes a colour, size, radius, or duration.

   THE DESIGN LANGUAGE. Orbit Axis is built on Apple's marketing-surface system:
   a near-invisible interface wrapped around one thing worth looking at. Its
   rules, and why each one is here:

     · ONE accent. Every "you can act on this" signal is Orbit Violet and nothing
       else. There is no second brand colour, no zodiac palette, no sign colours.
       Meaning comes from words; colour only says "this is interactive".
     · Elevation is a surface change, not a shadow. Sections separate because the
       canvas under them changes tone. The system has exactly ONE drop shadow and
       it is reserved for the chart wheel and the moon — the two things that are
       photographic objects rather than interface.
     · Type carries the hierarchy. Display sizes are weight 600 with negative
       tracking; body is 17px, not 16px, because the extra pixel is the
       difference between reading and scanning.
     · The weight ladder is 300 / 400 / 600 / 700. Weight 500 is deliberately
       absent — mid-emphasis is 600, and having both makes every decision a
       coin-flip that drifts.
     · Radius is a grammar, not a taste. Pill = action. 18px = card. 8px = compact
       utility. Nothing in between.

   A NIGHT-SKY PRODUCT. Apple's own surfaces are light-dominant; Orbit Axis
   defaults to dark, because it is an app about the night sky and most people
   open it in the evening. That changes the palette, not the system: the same
   single accent (in its on-dark variant), the same tile alternation, the same
   type ladder, the same one shadow. Both themes are complete and neither is a
   filter over the other.

   Sections:
     1. Palette primitives
     2. Type ladder
     3. Radius, spacing, layout
     4. Elevation, blur, motion
     5. Semantic colours — dark (default)
     6. Semantic colours — light
     7. Contrast, density, and text-size modes
   ========================================================================== */

:root {
  /* ── 1. Palette primitives ─────────────────────────────────────────────────
     Raw values. Components reference the semantic names in §5/§6, never these. */

  /* Orbit Axis brand constants. The 62deg angle belongs to the identity, not
     to an individual drawing; every brand asset uses this same observer axis. */
  --brand-deep-space: #080a12;
  --brand-surface: #101321;
  --brand-orbit-purple: #4a28b8;
  --brand-active-violet: #7657e8;
  --brand-celestial-highlight: #b9a7ff;
  --brand-star-white: #f4f2fa;
  --brand-muted-starlight: #8e93a8;
  --brand-axis-angle: 62deg;
  --brand-wordmark-tracking: 0.18em;

  /* Orbit Violet — the one interactive colour, in its surface variants.
     ONE HUE (254°), two lightnesses, because a single hex cannot serve both
     themes: #4a28b8 scores 9.2:1 on white and 2.3:1 on black, so on the dark
     canvas it would be a link nobody can read. The dark sibling is the same
     hue lightened to 7.3:1 on black.

     The trade comes at the other end: a light violet FILL cannot carry white
     text (2.9:1), so on dark the filled button takes near-black ink instead.
     That is the same move as a pale button with dark text on iOS — the fill is
     the loud part, the label just has to be legible on it. */
  --violet-action: var(--brand-orbit-purple);
  --violet-focus: var(--brand-active-violet);
  --violet-sky: var(--brand-celestial-highlight);
  --violet-sky-focus: var(--brand-celestial-highlight);
  --violet-ink: var(--brand-deep-space);

  /* Ink — light-surface text, from Apple's near-black through its mutes. */
  --ink: #1d1d1f;                /* headlines and body: near-black, not black,
                                    so the page reads photographic not printed */
  --ink-80: #333333;
  --ink-60: #56565a;
  --ink-48: #7a7a7a;

  /* Paper — light surfaces. */
  --paper-white: #ffffff;
  --paper-parchment: #f5f5f7;    /* the signature Apple off-white              */
  --paper-pearl: #fafafc;        /* ghost-button fill, lighter than parchment  */
  --paper-hairline: #e0e0e0;
  --paper-divider: #f0f0f0;

  /* Void — dark surfaces. The three tiles are micro-steps apart on purpose:
     that half-tone difference is what separates two dark sections without a
     border. */
  --void-black: var(--brand-deep-space);
  --void-canvas: #0b0e19;
  --void-tile-1: var(--brand-surface);
  --void-tile-2: #171b2d;
  --void-tile-3: #0d101c;
  --void-sunken: #0b0d18;

  /* On-dark text. */
  --moon-white: var(--brand-star-white);
  --moon-muted: #c9c5d6;
  /* 14px metadata sat at 4.34:1 on a tile — measured, just under AA's 4.5 for
     normal text. This step reads 5.1:1 on the brightest tile and 4.7:1 even on
     the hover surface, a margin rather than a graze, while staying two visual
     steps away from --moon-muted above it and from the #6a6a6e disabled tone
     below it — quieter than copy, but never a squint. */
  --moon-faint: var(--brand-muted-starlight);

  /* Signal colours. Informational only — they never become a second accent,
     and nothing is clickable *because* it is green. */
  --signal-green: #30d158;
  --signal-green-dim: #248a3d;
  --signal-amber: #ffd60a;
  --signal-amber-dim: #a1730a;
  --signal-red: #ff453a;
  --signal-red-dim: #c9251c;

  /* ── 2. Type ladder ───────────────────────────────────────────────────────
     Inter is the brand target; the existing platform stack remains the local,
     zero-request fallback. IBM Plex Mono leads technical and coordinate data. */
  --font-display: "Inter", "SF Pro Display", -apple-system, BlinkMacSystemFont,
    system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-text: "Inter", "SF Pro Text", -apple-system, BlinkMacSystemFont,
    system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", "SF Mono", ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace;

  /* Astrological glyphs — ♈ ☉ ☿ △ and the rest.
     These are ordinary Unicode, and several of them ALSO have emoji
     presentations that Apple platforms prefer: left to the body font, "♈"
     rendered as a purple-gradient tile from Apple Color Emoji, which in an
     interface with exactly one accent colour was the loudest thing on the page.
     A symbol-first stack resolves them before any emoji font is reached.
     `font-variant-emoji: text` and a U+FE0E in the string are the other two
     halves of the fix (see symbol-atlas.css and textGlyph() in app.js) — all
     three are needed, because each is ignored by some browser. */
  --font-glyph: "Apple Symbols", "Segoe UI Symbol", "Noto Sans Symbols 2",
    "STIXGeneral", var(--font-text);

  /* Sizes. Each display step pairs with its own tracking below — the tracking is
     not optional, it is what produces the tight headline cadence. */
  --type-hero: 3.5rem;        /* 56 — hero headline                            */
  --type-display: 2.5rem;     /* 40 — tile headline                            */
  --type-section: 2.125rem;   /* 34 — section head                             */
  --type-lead: 1.75rem;       /* 28 — tile subcopy                             */
  --type-lead-airy: 1.5rem;   /* 24 — airy lead paragraph (weight 300)         */
  --type-tagline: 1.3125rem;  /* 21 — sub-tile tagline, sub-nav category       */
  --type-body: 1.0625rem;     /* 17 — DEFAULT paragraph. Not 16.               */
  --type-caption: 0.875rem;   /* 14 — captions, button labels                  */
  --type-fine: 0.75rem;       /* 12 — fine print, nav links                    */
  --type-micro: 0.625rem;     /* 10 — legal micro-copy                         */

  --weight-light: 300;        /* rare, and deliberate — large airy reads only  */
  --weight-regular: 400;
  --weight-semibold: 600;     /* every headline, every strong inline           */
  --weight-bold: 700;         /* the tagline, when it needs more assertion     */

  --lead-hero: 1.07;
  --lead-display: 1.1;
  --lead-tight: 1.19;
  --lead-snug: 1.29;
  --lead-body: 1.47;          /* never tighten body below this                 */
  --lead-airy: 1.5;
  --lead-dense-link: 2.41;    /* footer / utility link columns — not a typo    */

  --track-hero: -0.028em;
  --track-display: -0.022em;
  --track-body: -0.022em;     /* -0.374px at 17px                              */
  --track-caption: -0.016em;
  --track-fine: -0.01em;
  --track-none: 0;
  --track-caps: 0.06em;

  /* ── 3. Radius, spacing, layout ──────────────────────────────────────────
     Four radii and a pill. Mixing grammars is what makes an interface look
     assembled rather than designed, so there is deliberately nothing between
     these steps. */
  --radius-none: 0;
  --radius-xs: 5px;    /* inline chips                                        */
  --radius-sm: 8px;    /* compact utility buttons, inline imagery             */
  --radius-md: 11px;   /* pearl capsules, inputs                              */
  --radius-lg: 18px;   /* THE card radius                                     */
  --radius-xl: 26px;   /* the one step above a card: sheets and hero tiles    */
  --radius-pill: 9999px;
  --radius-full: 9999px;

  /* 8px base. The odd 17px step is Apple's own and matches the body size, which
     is what keeps text-adjacent padding optically aligned with the text. */
  --space-xxs: 4px;
  --space-xs: 8px;
  --space-sm: 12px;
  --space-md: 17px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-xxl: 48px;
  --space-section: 80px;

  --border-width: 1px;
  --container-max: 1100px;   /* text-heavy reading width, Apple's ~980 + gutter */
  --container-wide: 1440px;  /* card grids                                      */
  --rail-width: 260px;
  --rail-width-collapsed: 76px;
  --topbar-height: 52px;     /* the frosted sub-nav                             */
  --tabbar-height: 56px;
  --control-height: 44px;    /* the minimum touch target, everywhere            */

  /* ── 4. Elevation, blur, motion ───────────────────────────────────────────
     ONE shadow. It belongs to the chart wheel and the moon — objects that rest
     on a surface. Cards, buttons, and text never take it: they separate by
     surface tone and hairline instead. */
  --shadow-object: 3px 5px 30px 0 rgba(0, 0, 0, 0.22);
  --blur-frosted: saturate(180%) blur(20px);

  --duration-instant: 90ms;
  --duration-fast: 140ms;
  --duration-base: 200ms;
  --duration-slow: 320ms;
  --duration-brand-reveal: 420ms;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-decelerate: cubic-bezier(0.05, 0.7, 0.1, 1);
  --ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
  /* The system-wide press. Every button shrinks by this and nothing else. */
  --press-scale: 0.95;
  /* The same gesture on something the width of the screen. 5% of a pill is a
     few pixels; 5% of a full-width row is nearly twenty, and the row appears
     to jump away from the finger. Large surfaces press by a hair instead — the
     movement is felt rather than watched. */
  --press-scale-large: 0.99;

  /* Breakpoints, for reference — custom properties cannot drive @media:
       480  small phone      640  phone        834  tablet portrait
       1024 small desktop   1200 desktop      1440 content lock            */
}

/* ── 5. Semantic colours — DARK (default) ──────────────────────────────────
   Deep Space canvas with blue-black instrument surfaces. The tone step is the
   elevation story on this theme; no interface shadow is involved. */
:root,
:root[data-theme="dark"] {
  color-scheme: dark;

  --color-bg: var(--void-black);
  --color-canvas: var(--void-canvas);
  --color-surface: var(--void-tile-1);
  --color-surface-elevated: var(--void-tile-2);
  --color-surface-sunken: var(--void-sunken);
  --color-surface-hover: #1c2136;
  --color-surface-ghost: rgba(255, 255, 255, 0.06);

  --color-border: rgba(185, 167, 255, 0.14);
  --color-border-strong: rgba(185, 167, 255, 0.28);
  --color-border-focus: var(--brand-active-violet);

  --color-primary: var(--moon-white);     /* headlines and body                */
  --color-secondary: var(--moon-muted);   /* secondary copy                    */
  --color-muted: var(--moon-faint);       /* metadata                          */
  --color-faint: #70758b;                 /* disabled, placeholder             */

  --color-accent: var(--violet-sky);
  --color-accent-hover: var(--brand-star-white);
  --color-accent-soft: rgba(118, 87, 232, 0.18);
  --color-accent-border: rgba(185, 167, 255, 0.42);
  /* Near-black, not white: see the note on --violet-ink above. */
  --color-on-accent: var(--violet-ink);

  --color-success: var(--signal-green);
  --color-success-soft: rgba(48, 209, 88, 0.16);
  --color-warning: var(--signal-amber);
  --color-warning-soft: rgba(255, 214, 10, 0.16);
  --color-error: var(--signal-red);
  --color-error-soft: rgba(255, 69, 58, 0.16);

  /* Frosted chrome — the sub-nav and the floating action bar. Functional, not
     decorative: it is how a bar stays legible over scrolling content. */
  --glass-bg: rgba(16, 19, 33, 0.78);
  --glass-border: rgba(185, 167, 255, 0.12);
  /* Translucent chip over imagery — Apple's circular control. */
  --chip-translucent: rgba(36, 40, 65, 0.72);

  --focus-ring: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-border-focus);
}

/* ── 6. Semantic colours — LIGHT ───────────────────────────────────────────
   Apple's own daylight palette, unchanged: white canvas, parchment for the
   alternating band, near-black ink, one blue. */
:root[data-theme="light"] {
  color-scheme: light;

  --color-bg: var(--paper-parchment);
  --color-canvas: var(--paper-white);
  --color-surface: var(--paper-white);
  --color-surface-elevated: var(--paper-white);
  --color-surface-sunken: var(--paper-parchment);
  --color-surface-hover: var(--paper-pearl);
  --color-surface-ghost: rgba(0, 0, 0, 0.04);

  --color-border: var(--paper-hairline);
  --color-border-strong: #c7c7cc;
  --color-border-focus: var(--violet-focus);

  --color-primary: var(--ink);
  --color-secondary: var(--ink-80);
  --color-muted: var(--ink-60);
  --color-faint: var(--ink-48);

  --color-accent: var(--violet-action);
  --color-accent-hover: var(--violet-focus);
  --color-accent-soft: rgba(74, 40, 184, 0.09);
  --color-accent-border: rgba(74, 40, 184, 0.35);
  /* A dark fill takes white — 9.2:1. */
  --color-on-accent: var(--paper-white);

  --color-success: var(--signal-green-dim);
  --color-success-soft: rgba(36, 138, 61, 0.12);
  --color-warning: var(--signal-amber-dim);
  --color-warning-soft: rgba(161, 115, 10, 0.12);
  --color-error: var(--signal-red-dim);
  --color-error-soft: rgba(201, 37, 28, 0.1);

  --glass-bg: rgba(245, 245, 247, 0.8);
  --glass-border: rgba(0, 0, 0, 0.07);
  --chip-translucent: rgba(210, 210, 215, 0.64);

  --focus-ring: 0 0 0 2px var(--color-canvas), 0 0 0 4px var(--color-border-focus);
}

/* ── 7. Modes ──────────────────────────────────────────────────────────────
   Contrast, density, and text size are user choices that remap tokens rather
   than adding rules, so every component inherits them without knowing they
   exist. */

/* Contrast. Hairlines are the first thing to disappear for a reader who needs
   more separation, so they are the first thing these modes strengthen. */
@media (prefers-contrast: more) {
  :root { --color-border: rgba(255, 255, 255, 0.3); --color-border-strong: rgba(255, 255, 255, 0.55); --color-muted: #d6d6d8; }
  :root[data-theme="light"] { --color-border: #a1a1a6; --color-border-strong: #6e6e73; --color-muted: var(--ink-80); }
}
:root[data-contrast="high"] {
  --color-border: rgba(255, 255, 255, 0.34);
  --color-border-strong: rgba(255, 255, 255, 0.6);
  --color-muted: #dcdcde;
}
:root[data-theme="light"][data-contrast="high"] {
  --color-border: #8e8e93;
  --color-border-strong: #48484a;
  --color-muted: var(--ink-80);
}

/* Density. Components read --density-* for their internal rhythm, so the whole
   app tightens from one place. */
:root {
  --density-card-pad: var(--space-lg);
  --density-tile-pad: var(--space-lg);
  --density-row-pad: var(--space-sm);
  --density-gap: var(--space-lg);
  --density-stack: var(--space-md);
  --density-section: var(--space-xxl);
}

/* Large text scales the rem base; every size above is rem-based, so the whole
   ladder grows in proportion and nothing has to be respecified. */
:root[data-text="large"] { font-size: 117.5%; }

/* ── Compatibility aliases ─────────────────────────────────────────────────
   The names the pre-redesign stylesheets were written against, mapped onto the
   system above. They exist so a single token file re-skins the entire app
   rather than requiring ten stylesheets to change in lockstep — and so that a
   rule nobody has revisited yet still renders in the new language instead of
   falling back to an unset value.

   These are a migration surface, not an API. New rules use the names above. */
:root {
  /* Type — old scale names onto the new ladder. */
  --text-display: var(--type-section);
  --text-title: var(--type-lead);
  --text-heading: var(--type-tagline);
  --text-card-title: var(--type-body);
  --text-body: var(--type-body);
  --text-caption: var(--type-caption);
  --text-meta: var(--type-fine);
  --font-sans: var(--font-text);

  /* Weight 500 does not exist in this system; requests for it resolve to 600. */
  --weight-medium: var(--weight-semibold);

  --leading-tight: var(--lead-display);
  --leading-snug: var(--lead-snug);
  --leading-normal: var(--lead-body);
  --tracking-tight: var(--track-body);
  --tracking-normal: var(--track-none);
  --tracking-wide: var(--track-none);
  --tracking-caps: var(--track-caps);

  /* Spacing — the old 4px-grid step names onto the 8px scale. */
  --space-0: 0;
  --space-1: var(--space-xxs);
  --space-2: var(--space-xs);
  --space-3: var(--space-sm);
  --space-4: var(--space-md);
  --space-5: var(--space-lg);
  --space-6: var(--space-lg);
  --space-8: var(--space-xl);
  --space-10: var(--space-xxl);
  --space-12: var(--space-xxl);
  --space-16: var(--space-section);

  /* Elevation. The old three-step shadow ramp is gone: this system separates by
     surface, so e1 and e2 resolve to nothing at all and e3 — used only by
     dialogs, which genuinely float above a scrim — takes the object shadow. */
  --shadow-e1: none;
  --shadow-e2: none;
  --shadow-e3: var(--shadow-object);
  --glass-blur: 20px;

  /* The retired decorative palette. Every one of these was a second, third, and
     fourth accent — lavender, indigo, periwinkle, pink — used for glows and
     gradient washes. The system allows exactly one accent, so they all resolve
     to it or to plain ink, which collapses the gradients they fed into flat
     surfaces without needing to hunt down each rule. */
  --axis-lavender: var(--color-accent);
  --axis-periwinkle: var(--color-accent);
  --axis-blue: var(--color-accent);
  --axis-indigo: var(--color-accent);
  --axis-pink: var(--color-accent);
  --axis-moon: var(--color-primary);
  --axis-glow: 0 0 0;
  --axis-glow-soft: 0 0 0;
  --axis-radius-lg: var(--radius-lg);
  --axis-radius-md: var(--radius-md);

  /* Short names some stylesheets were written against, always as
     `var(--accent, #7c9cff)` with a hardcoded fallback. Those fallbacks are the
     OLD palette, so leaving these undefined would silently keep half the app on
     the retired colours no matter what this file says. Defined here, the
     fallbacks become unreachable and every one of those rules joins the system. */
  --accent: var(--color-accent);
  --accent-strong: var(--color-accent-hover);
  --border: var(--color-border);
  --surface-2: var(--color-surface);
  --text: var(--color-primary);
  --text-muted: var(--color-muted);
  --text-soft: var(--color-secondary);
  --muted: var(--color-muted);
  --dim: var(--color-faint);
  --primary: var(--color-primary);
  --error: var(--color-error);
  --danger: var(--color-error);
  --danger-border: var(--color-error);
  --danger-surface: var(--color-error-soft);
  --danger-text: var(--color-error);
  --warn-border: var(--color-warning);
  /* Gold was the pre-redesign second accent on sign glyphs and headings. */
  --gold: var(--color-accent);
  /* The moon scene's sky gradient. Kept as a gradient because it depicts a
     photographic subject — a night sky — rather than decorating an interface. */
  --moon-sky-top: #0b1020;
  --moon-sky-bottom: #05070f;

  /* Old primitive ramps, for the handful of rules that reach past the semantic
     layer. */
  --blue-300: var(--violet-sky);
  --blue-400: var(--violet-sky);
  --blue-500: var(--color-accent);
  --blue-600: var(--violet-action);
  --ink-000: var(--moon-white);
  --ink-050: #f5f5f7;
  --ink-100: #e5e5ea;
  --ink-200: var(--moon-muted);
  --ink-300: #aeaeb2;
  --ink-400: var(--moon-faint);
  --ink-500: #6a6a6e;
  --ink-600: #48484a;
  --ink-700: #3a3a3c;
  --ink-750: #303032;
  --ink-800: var(--void-tile-2);
  --ink-850: var(--void-tile-1);
  --ink-900: var(--void-sunken);
  --ink-950: var(--void-black);
  --green-400: var(--signal-green);
  --green-500: var(--signal-green-dim);
  --amber-400: var(--signal-amber);
  --amber-500: var(--signal-amber-dim);
  --red-400: var(--signal-red);
  --red-500: var(--signal-red-dim);
}
