/* ============================================================================
   base.css — design tokens, reset, and base element styling
   Covert Channel Studio — a Crypto-Lab exhibit
   Dark technical aesthetic. No external fonts or assets (strict CSP friendly).
   ========================================================================== */

/* ---- Design tokens -------------------------------------------------------- */
:root {
  /* Surfaces (layered dark) */
  --bg:            #0a0e14;
  --surface-0:     #0e131b;
  --surface-1:     #131a24;
  --surface-2:     #1a2330;
  --surface-3:     #24303f;
  --surface-inset: #0b0f16;

  /* Borders / lines.
     --border / --border-strong / --border-faint are DECORATIVE dividers: card
     edges, table rules, hairlines. They are deliberately quiet and none of them
     reaches 3:1 against the surfaces they sit on (--border-strong is 1.79:1 on
     --surface-1), which is fine for decoration.

     --border-control is the boundary of an INTERACTIVE component, which WCAG
     1.4.11 Non-text Contrast holds to 3:1 against adjacent colour. Measured
     (WCAG 2.1 relative luminance): 3.55:1 on --surface-1, 3.21:1 on --surface-2,
     3.78:1 on --surface-0, 3.92:1 on --bg, 3.89:1 on --surface-inset — i.e. it
     clears 3:1 against every surface a control is drawn on or filled with.
     Use it ONLY on things the user can operate; decorative edges stay quiet. */
  --border:        #263243;
  --border-strong: #35455a;
  --border-faint:  #1a2331;
  --border-control:#5e728c;

  /* Text */
  --text:          #e7eef6;
  --text-dim:      #a8b8c8;
  /* Lightened from #728398, which measured 4.08:1 on --surface-2 and 4.51:1 on
     --surface-1 — under, and barely over, the 4.5:1 body-text minimum. It is used in
     roughly twenty places, so this is a token-level defect rather than a set of rule
     ones; test/contrast.test.js measures it. #7c8da2 clears 4.66:1 on the darkest
     panel surface while staying clearly quieter than --text-dim (7.80:1). */
  --text-faint:    #7c8da2;
  --text-invert:   #0a0e14;

  /* Brand accents */
  --accent:        #2dd4bf;   /* teal — primary signal */
  --accent-deep:   #14b8a6;
  --accent-2:      #60a5fa;   /* blue — secondary / receiver */
  --accent-2-deep: #3b82f6;

  /* Semantic */
  --covert:        #fbbf24;   /* amber — the *hidden* information */
  --covert-deep:   #f59e0b;
  --danger:        #f87171;   /* high anomaly / errors */
  --warn:          #fbbf24;   /* moderate anomaly */
  --ok:            #34d399;   /* low anomaly / clean */
  --info:          #818cf8;

  /* Bit palette (do not rely on colour alone — always pair with a glyph) */
  --bit-0:         #38bdf8;   /* cyan  */
  --bit-1:         #f472b6;   /* pink  */
  --bit-err:       #f87171;

  /* Anomaly scale */
  --anom-low:      #34d399;
  --anom-mod:      #fbbf24;
  --anom-high:     #f87171;

  /* Typography */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
               Arial, "Helvetica Neue", sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, "Menlo", "Consolas",
               "Liberation Mono", "Courier New", monospace;

  --fs-xs:  0.72rem;
  --fs-sm:  0.82rem;
  --fs-base:0.94rem;
  --fs-md:  1.06rem;
  --fs-lg:  1.28rem;
  --fs-xl:  1.7rem;
  --fs-2xl: 2.4rem;
  --fs-3xl: 3.2rem;

  --lh-tight: 1.2;
  --lh-base:  1.6;

  /* Spacing scale */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;

  /* Radii */
  --r-sm: 5px;
  --r-md: 9px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-pill: 999px;

  /* Elevation */
  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 4px 16px rgba(0,0,0,.35);
  --shadow-3: 0 12px 40px rgba(0,0,0,.45);
  --glow-accent: 0 0 0 1px rgba(45,212,191,.35), 0 0 22px -6px rgba(45,212,191,.5);
  --glow-covert: 0 0 0 1px rgba(251,191,36,.4), 0 0 22px -6px rgba(251,191,36,.55);

  /* Motion */
  --ease: cubic-bezier(.2, .7, .2, 1);
  --dur-fast: 120ms;
  --dur:      220ms;
  --dur-slow: 420ms;

  /* Layout */
  --nav-w: 248px;
  --maxw: 1500px;

  /* Height of the sticky .app-header. Everything that has to clear the header —
     the sidebar, the sticky workbench panels, and scroll-padding-top — keys off
     this instead of repeating a magic pixel constant.

     It is in REM on purpose. The header is built entirely from rem-sized type
     and spacing, so a reader who raises the browser's default font size (rather
     than using page zoom) makes the real header taller; a px constant would not
     follow it and the header would start covering the top of the sidebar. That
     is WCAG 1.4.4 Resize Text, which page zoom satisfies but text-only zoom does
     not. Derivation of the one-row desktop header, at any root size:
       padding      --sp-3 x2                                = 1.500rem
       .msg-field   label (--fs-sm x --lh-base)              = 1.312rem
                  + --sp-2 gap                               = 0.500rem
                  + input (--sp-2 x2 + --fs-base x --lh-base
                           + 2px border)                     = 2.629rem
                                                        total ~ 5.941rem
     Rounded up to 6.25rem so the value is never short. Over-estimating only
     leaves a little air under the header; under-estimating hides content. */
  --header-h: 6.25rem;
}

/* ---- Reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

/* scroll-padding-top keeps the sticky header from landing on top of whatever the
   browser has just scrolled into view — a focused control reached with Shift+Tab,
   the skip link's target, a hash change. Without it the browser aligns the target
   with the viewport's top edge, which is underneath the header, and the focus ring
   is invisible behind 88%-opaque backdrop-blurred glass (WCAG 2.2 SC 2.4.11 Focus
   Not Obscured (Minimum)). --header-h drops to 0 below 960px, where the header is
   no longer sticky. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--sp-2));
}

body {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

/* Subtle grid backdrop — decorative only */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(1200px 700px at 78% -8%, rgba(45,212,191,.08), transparent 60%),
    radial-gradient(1000px 620px at 6% 4%, rgba(96,165,250,.07), transparent 55%),
    linear-gradient(transparent 0 0);
  pointer-events: none;
}

img, svg, canvas { display: block; max-width: 100%; }
canvas { image-rendering: pixelated; }

button, input, select, textarea { font: inherit; color: inherit; }

a { color: var(--accent-2); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3, h4 { line-height: var(--lh-tight); font-weight: 650; letter-spacing: -0.01em; }
h1 { font-size: var(--fs-2xl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }

p { color: var(--text-dim); }
strong { color: var(--text); font-weight: 650; }

code, kbd, samp, pre { font-family: var(--font-mono); }
code {
  font-size: 0.88em;
  background: var(--surface-inset);
  border: 1px solid var(--border-faint);
  border-radius: var(--r-sm);
  padding: 0.08em 0.4em;
  color: var(--accent);
}

ul, ol { padding-left: 1.3em; color: var(--text-dim); }
li { margin: 0.25em 0; }

hr { border: none; border-top: 1px solid var(--border); margin: var(--sp-5) 0; }

/* ---- Focus & accessibility ----------------------------------------------- */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
:focus:not(:focus-visible) { outline: none; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

.skip-link {
  position: fixed;
  top: 0; left: 50%;
  transform: translate(-50%, -120%);
  z-index: 100;
  background: var(--accent);
  color: var(--text-invert);
  padding: var(--sp-2) var(--sp-4);
  border-radius: 0 0 var(--r-md) var(--r-md);
  font-weight: 650;
  transition: transform var(--dur) var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); text-decoration: none; }

.noscript-note { padding: 2rem; max-width: 60ch; margin: 0 auto; color: var(--text); }
.noscript-note h2 { margin-bottom: var(--sp-3); }

/* Scrollbars */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--r-pill);
  border: 2px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-track { background: transparent; }

/* Selection */
::selection { background: rgba(45,212,191,.3); color: #fff; }

/* ---- Reduced motion ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
