/* ==========================================================================
   Artisan Hosting — base.css
   Design tokens, self-hosted fonts, reset, type scale, utilities.

   Load order (do not reorder, no @import — it serializes requests):
     base.css -> layout.css -> components.css  [-> crt.css on /for-developers/]

   Every page must carry this in <head> BEFORE the stylesheets, so the theme
   and effects state resolve before first paint (no flash, no CRT replay):

   <script>(function(){var d=document.documentElement;try{
     var t=localStorage.getItem('artisan-theme');
     if(t!=='dark'&&t!=='light')t=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';
     d.setAttribute('data-theme',t);
     var e=localStorage.getItem('artisan-effects');
     if(e!=='full'&&e!=='reduced')e=matchMedia('(prefers-reduced-motion: reduce)').matches?'reduced':'full';
     d.setAttribute('data-effects',e);
   }catch(x){d.setAttribute('data-theme','light');d.setAttribute('data-effects','reduced')}})()</script>

   Because that script always writes data-theme, the dark palette lives in ONE
   block below rather than being duplicated into a prefers-color-scheme query.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts — self-hosted woff2. The previous stylesheet declared these with
   `src: local(...)` and no url(), so none of them had ever actually rendered.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/source-sans-3-400-700-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: 'Source Sans 3';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/source-sans-3-400-700-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-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/fraunces-400-700-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: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/fraunces-400-700-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-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-400-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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-400-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-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-500-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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-500-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-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   Tokens — light (default)
   -------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  /* Type stacks */
  --font-sans: 'Source Sans 3', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-serif: 'Fraunces', ui-serif, Georgia, 'Times New Roman', Times, serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;

  /* Brand primitives — the six colors. Everything else derives from these. */
  --sky: #a7c7e7;
  --navy: #0b132b;
  --charcoal: #1f2430;
  --paper: #f6f7fb;
  --wine: #912f40;
  --warm: #e7e7a7;

  /* Surfaces */
  --bg: var(--paper);
  --surface-1: #ffffff;
  --surface-2: #eef2f7;
  --surface-sunken: #e7edf5;
  --border: #d8dee9;
  --border-strong: rgba(11, 19, 43, 0.18);
  --glass: rgba(11, 19, 43, 0.08);

  /* Text ramp — four steps, and that is deliberately all of them.
     The old sheet carried eight, five of which sat within 0.10 alpha
     of each other. That is not a scale, it is noise. */
  --text-1: var(--charcoal);          /* body copy, h3+                */
  --text-2: rgba(31, 36, 48, 0.72);   /* leads, card body, idle nav    */
  --text-3: rgba(31, 36, 48, 0.55);   /* eyebrows, captions, meta      */
  --text-strong: #101a33;             /* h1 / h2 only                  */
  --text-on-brand: var(--paper);

  --link: var(--navy);
  --link-hover: var(--wine);

  /* Buttons */
  --btn-primary-bg: var(--navy);
  --btn-primary-hover: #0f1a3d;
  --btn-primary-text: var(--paper);
  --btn-secondary-bg: var(--sky);
  --btn-secondary-hover: #93b9e0;
  --btn-secondary-text: var(--navy);
  --btn-secondary-border: transparent;
  --btn-ghost-text: var(--navy);
  --btn-ghost-hover: rgba(167, 199, 231, 0.25);
  --focus-ring: rgba(11, 19, 43, 0.25);

  /* Accents */
  --accent: var(--wine);
  --accent-soft: rgba(145, 47, 64, 0.12);
  --info-soft: rgba(167, 199, 231, 0.35);

  /* Ambient washes — tokenized so they invert with the theme instead of
     being baked as raw rgba the way the old hero gradient was. */
  --wash-sky: rgba(167, 199, 231, 0.22);
  --wash-warm: rgba(231, 231, 167, 0.18);
  --wash-hero-a: rgba(167, 199, 231, 0.32);
  --wash-hero-b: rgba(145, 47, 64, 0.18);

  /* Status */
  --ok: #0f7a52;
  --warn: #a86a00;
  --bad: #b3261e;
  --ok-soft: rgba(15, 122, 82, 0.12);
  --warn-soft: rgba(168, 106, 0, 0.12);
  --bad-soft: rgba(179, 38, 30, 0.12);

  /* CRT — shared by the tier-2 accents and the tier-3 full treatment */
  --crt-phosphor: #33ff33;
  --crt-phosphor-bright: #66ff66;
  --crt-bg: #04120a;
  --crt-border: #1b5e1b;

  /* Shadows — a --shadow-* token is always a complete box-shadow value.
     The raw color always carries the -color suffix. */
  --shadow-color: rgba(11, 19, 43, 0.12);
  --shadow-soft: 0 16px 40px -28px rgba(11, 19, 43, 0.28);
  --shadow: 0 20px 58px var(--shadow-color);
  --shadow-medium: 0 22px 62px var(--shadow-color);

  /* Geometry */
  --radius: 18px;
  --radius-sm: 12px;
  --radius-pill: 999px;
  --maxw: 1080px;
  --header-h: 72px;

  /* Spacing scale */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 72px;
  --section-space: clamp(24px, 5vw, 56px);
  --grid-gap: clamp(16px, 4vw, 28px);
  --wrap-pad: clamp(18px, 5vw, 36px);

  /* Motion */
  --ease: cubic-bezier(.2, .8, .2, 1);
  --dur-fast: 120ms;
  --dur: 240ms;

  /* Stacking */
  --z-scrim: 900;
  --z-header: 1000;
  --z-drawer: 1100;

  /* Convenience aliases kept because they read better at the call site.
     These are permanent, not a migration shim. */
  --card: var(--surface-1);
  --muted: var(--text-2);
  --brand: var(--sky);
  --code-bg: #eaf0fa;
  --code-text: var(--charcoal);
}

/* --------------------------------------------------------------------------
   Tokens — dark. One block. The head script always writes data-theme, so
   there is no prefers-color-scheme duplicate to keep in sync.
   -------------------------------------------------------------------------- */

:root[data-theme='dark'] {
  color-scheme: dark;

  --bg: var(--navy);
  --surface-1: #121b33;
  --surface-2: #1a2440;
  --surface-sunken: #0e1628;
  --border: rgba(246, 247, 251, 0.12);
  --border-strong: rgba(246, 247, 251, 0.2);
  --glass: rgba(246, 247, 251, 0.09);

  --text-1: var(--paper);
  --text-2: rgba(246, 247, 251, 0.78);
  --text-3: rgba(246, 247, 251, 0.58);
  --text-strong: #ffffff;
  --text-on-brand: var(--navy);

  --link: var(--sky);
  --link-hover: var(--warm);

  --btn-primary-bg: var(--sky);
  --btn-primary-hover: #93b9e0;
  --btn-primary-text: var(--navy);
  --btn-secondary-bg: #1a2440;
  --btn-secondary-hover: #243055;
  --btn-secondary-text: var(--paper);
  --btn-secondary-border: rgba(246, 247, 251, 0.18);
  --btn-ghost-text: var(--sky);
  --btn-ghost-hover: rgba(167, 199, 231, 0.14);
  --focus-ring: rgba(167, 199, 231, 0.55);

  --accent: var(--warm);
  --accent-soft: rgba(231, 231, 167, 0.14);
  --info-soft: rgba(167, 199, 231, 0.16);

  --wash-sky: rgba(167, 199, 231, 0.10);
  --wash-warm: rgba(231, 231, 167, 0.07);
  --wash-hero-a: rgba(167, 199, 231, 0.16);
  --wash-hero-b: rgba(145, 47, 64, 0.22);

  --ok: #4ade80;
  --warn: #fbbf24;
  --bad: #f87171;
  --ok-soft: rgba(74, 222, 128, 0.14);
  --warn-soft: rgba(251, 191, 36, 0.14);
  --bad-soft: rgba(248, 113, 113, 0.14);

  --shadow-color: rgba(0, 0, 0, 0.35);
  --shadow-soft: 0 18px 44px -30px rgba(0, 0, 0, 0.42);
  --shadow: 0 22px 60px var(--shadow-color);
  --shadow-medium: 0 26px 66px var(--shadow-color);

  --code-bg: #16213b;
  --code-text: var(--paper);
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--text-1);
  background:
    radial-gradient(1200px 640px at 20% 0%, var(--wash-sky), transparent 56%),
    radial-gradient(900px 520px at 85% 10%, var(--wash-warm), transparent 62%),
    var(--bg);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg,
video,
canvas { display: block; max-width: 100%; height: auto; }

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

button { cursor: pointer; }

hr { border: 0; border-top: 1px solid var(--border); margin: var(--space-6) 0; }

:target { scroll-margin-top: calc(var(--header-h) + var(--space-5)); }

:focus-visible {
  outline: 2px solid transparent;
  box-shadow: 0 0 0 3px var(--focus-ring);
  border-radius: var(--radius-sm);
}

/* --------------------------------------------------------------------------
   Type scale
   -------------------------------------------------------------------------- */

h1, h2, h3, h4 {
  margin: 0 0 var(--space-3);
  line-height: 1.15;
  color: var(--text-strong);
  text-wrap: balance;
}

h1 {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  font-weight: 600;
  letter-spacing: -0.015em;
}

h2 {
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.125rem);
  font-weight: 600;
  letter-spacing: -0.01em;
}

h3 {
  font-size: clamp(1.125rem, 1.05rem + 0.4vw, 1.3rem);
  font-weight: 700;
  color: var(--text-1);
}

h4 {
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-1);
}

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

a { color: var(--link); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover, a:focus-visible { color: var(--link-hover); }

ul, ol { margin: 0 0 var(--space-4); padding-left: 1.25em; }
ul:last-child, ol:last-child { margin-bottom: 0; }
li + li { margin-top: var(--space-2); }

strong, b { font-weight: 700; color: var(--text-1); }

blockquote {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-4);
  border-left: 3px solid var(--accent);
  color: var(--text-2);
}

code, kbd, samp {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--code-bg);
  color: var(--code-text);
  padding: 0.15em 0.4em;
  border-radius: 6px;
}

pre {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  line-height: 1.55;
  background: var(--code-bg);
  color: var(--code-text);
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  overflow-x: auto;
}
pre code { background: none; padding: 0; font-size: inherit; }

/* --------------------------------------------------------------------------
   Text utilities
   -------------------------------------------------------------------------- */

.lead {
  font-size: clamp(1.05rem, 1rem + 0.35vw, 1.2rem);
  line-height: 1.55;
  color: var(--text-2);
  max-width: 62ch;
}

/* Was 1.2rem in the old sheet — larger than body text, on a class named
   "tiny". This is the corrected value. */
.tiny { font-size: 0.85rem; line-height: 1.5; color: var(--text-3); }

.small { font-size: 0.925rem; }
.muted-text { color: var(--text-2); }
.quiet { color: var(--text-3); }
.mono { font-family: var(--font-mono); }
.upper { text-transform: uppercase; letter-spacing: 0.08em; }
.center { text-align: center; }
.measure { max-width: 62ch; }
.nowrap { white-space: nowrap; }

.quote-line {
  font-family: var(--font-serif);
  font-size: clamp(1.25rem, 1.1rem + 0.8vw, 1.75rem);
  font-weight: 400;
  line-height: 1.35;
  color: var(--text-strong);
  text-wrap: balance;
}

.hide { display: none !important; }

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

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: calc(-1 * var(--space-8));
  z-index: calc(var(--z-drawer) + 1);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  text-decoration: none;
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: var(--space-4); }

/* --------------------------------------------------------------------------
   Reduced effects / reduced motion.

   The head script resolves an explicit choice over the OS setting and writes
   data-effects, so this is one gate rather than two parallel rule sets.
   The bare media query below is no-JS insurance only.
   -------------------------------------------------------------------------- */

:root[data-effects='reduced'] *,
:root[data-effects='reduced'] *::before,
:root[data-effects='reduced'] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

@media (prefers-reduced-motion: reduce) {
  html:not([data-effects='full']) *,
  html:not([data-effects='full']) *::before,
  html:not([data-effects='full']) *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
