@layer commonpub {
/* ===========================================
   CommonPub Token Contract — base.css
   Design: unified-v2 aesthetic + hack.build readability
   Sharp corners, 2px borders, offset shadows,
   JetBrains Mono labels, blue accent.
   =========================================== */

:root {
  /* Theme native UI (date/time pickers, scrollbars, form controls) to the light
     palette; dark.css overrides to `dark`. Without this, native popups (e.g. the
     datetime-local calendar) render in the OS default scheme and clash. */
  color-scheme: light;

  /* === SURFACES === */
  --bg: #fafaf9;
  --surface: #ffffff;
  --surface2: #f4f4f2;
  --surface3: #eaeae7;

  /* Aliases for backwards compat */
  --color-surface: var(--surface);
  --color-surface-alt: var(--surface2);
  --color-surface-raised: var(--surface);
  --color-surface-overlay: rgba(0, 0, 0, 0.5);
  --color-surface-overlay-light: rgba(0, 0, 0, 0.4);
  --color-surface-scrim: rgba(250, 250, 249, 0.75);
  --color-surface-hover: var(--surface2);
  --color-bg-subtle: var(--bg);

  /* === TEXT === */
  --text: #1a1a1a;
  --text-dim: #6b6b66;
  --text-faint: #a3a39e;

  --color-text: var(--text);
  --color-text-secondary: var(--text-dim);
  --color-text-muted: var(--text-faint);
  --color-text-inverse: #ffffff;

  /* === BORDERS === */
  --border: #1a1a1a;
  --border2: #d4d4d0;

  --color-border: var(--border2);
  --color-border-strong: var(--border);
  --color-border-focus: var(--accent);

  /* === ACCENT (blue) === */
  --accent: #5b9cf6;
  --accent-bg: rgba(91, 156, 246, 0.08);
  --accent-bg-strong: rgba(91, 156, 246, 0.2);
  --accent-bg-heavy: rgba(91, 156, 246, 0.4);
  --accent-bg-solid: rgba(91, 156, 246, 0.6);
  --accent-border: rgba(91, 156, 246, 0.25);
  --accent-focus-ring: 0 0 0 3px rgba(91, 156, 246, 0.12);

  --color-primary: var(--accent);
  --color-primary-hover: #4a8be5;
  /* Label colour ON a filled accent surface. Near-black, not white: white on
     --accent #5b9cf6 is 2.79:1, below even the 3:1 large-text floor, and it
     shipped that way until session 253. #1a1a1a is 6.24:1. The accent hue is
     fixed by the design system, so the label moves, not the fill.
     Locked by packages/theme-studio/src/__tests__/theme-contrast.test.ts. */
  --color-primary-text: #1a1a1a;
  --color-on-primary: #1a1a1a;
  --color-accent: var(--accent);
  --color-accent-hover: #4a8be5;
  --color-accent-text: #1a1a1a;
  --color-on-accent: #1a1a1a;
  --color-on-red: #1a1a1a;  /* 4.62:1 on this theme's --red */
  --color-on-green: #1a1a1a;  /* 7.64:1 on this theme's --green */
  --color-on-yellow: #1a1a1a;  /* 8.10:1 on this theme's --yellow */
  --color-accent-bg: var(--accent-bg);
  --color-accent-border: var(--accent-border);

  /* === SECONDARY ACCENT (violet) === */
  --secondary: #8b5cf6;
  --secondary-hover: #7c3aed;
  --secondary-bg: rgba(139, 92, 246, 0.08);
  --secondary-border: rgba(139, 92, 246, 0.25);
  --color-on-secondary: #ffffff;

  /* Film-grain overlay opacity (0 = off; app.vue mounts the overlay) */
  --grain: 0;

  /* === SEMANTIC COLORS === */
  --green: #22c55e;
  --green-bg: rgba(34, 197, 94, 0.08);
  --green-border: rgba(34, 197, 94, 0.25);

  --yellow: #f59e0b;
  --yellow-bg: rgba(245, 158, 11, 0.08);
  --yellow-border: rgba(245, 158, 11, 0.25);

  --red: #ef4444;
  --red-bg: rgba(239, 68, 68, 0.08);
  --red-border: rgba(239, 68, 68, 0.25);

  --purple: #8b5cf6;
  --purple-bg: rgba(139, 92, 246, 0.08);
  --purple-border: rgba(139, 92, 246, 0.25);

  --teal: #14b8a6;
  --teal-bg: rgba(20, 184, 166, 0.08);
  --teal-border: rgba(20, 184, 166, 0.25);

  --pink: #ec4899;
  --pink-bg: rgba(236, 72, 153, 0.08);
  --pink-border: rgba(236, 72, 153, 0.25);

  /* Rank colors (contests) */
  --gold: #fbbf24;
  --silver: #94a3b8;
  --bronze: #a0724a;

  --color-text-inverse: #ffffff;

  /* Inline-code text. The raw --teal fails WCAG AA as small text on the light
     --surface2 chip (≈2.4:1 on base, worse on vivid themes). --code-inline is the
     theme's teal mixed toward --text so it stays branded yet readable; it adapts
     per theme (deveco's green, dark mode's light text) via the inner var()
     resolution. The @supports block (after :root) upgrades it to color-mix; this is
     the readable fallback. */
  --code-inline: var(--text);

  /* === READABLE SEMANTIC TEXT COLORS ===
     The raw vivid semantics (--green/--yellow/--red/--teal/--purple/--pink/--accent)
     fail WCAG AA as small TEXT on light surfaces (≈2-4:1 — e.g. --yellow ≈2.2:1,
     --green ≈2.3:1 on white). These -text variants mix the vivid toward --text so
     they read ≥4.5:1 on light AND dark (the mix targets the theme's own --text, so
     a single definition adapts per theme — deveco's green, dark mode's light text).
     Use these for any vivid color applied as TEXT; keep the raw --vivid for fills,
     borders, and icons over the dark badge overlay. The @supports block (after
     :root) upgrades them to color-mix; the raw vivid is the no-color-mix fallback
     (<5% of browsers) = today's behavior, so there is never a regression.
     Per-color mix % is tuned to clear 4.5:1 on the lightest surface (white). */
  --green-text: var(--green);
  --yellow-text: var(--yellow);
  --red-text: var(--red);
  --teal-text: var(--teal);
  --purple-text: var(--purple);
  --pink-text: var(--pink);
  /* Distinct from --color-accent-text (= white, for text ON an accent fill).
     --accent-text is the accent usable AS text on a light surface. */
  --accent-text: var(--accent);

  /* Code block tokens (GitHub Dark defaults — overridable by themes) */
  --code-bg: #0d1117;
  --code-text: #e6edf3;
  --code-header-bg: #161b22;
  --code-border: #30363d;
  --code-muted: #8b949e;
  --code-green: #7ee787;
  --hljs-comment: #8b949e;
  --hljs-keyword: #ff7b72;
  --hljs-literal: #79c0ff;
  --hljs-string: #a5d6ff;
  --hljs-deletion: #ffa198;
  --hljs-meta: #d2a8ff;
  --hljs-name: #7ee787;
  --hljs-variable: #ffa657;

  --color-success: var(--green);
  --color-warning: var(--yellow);
  --color-error: var(--red);
  --color-info: var(--accent);
  --color-success-bg: var(--green-bg);
  --color-warning-bg: var(--yellow-bg);
  --color-error-bg: var(--red-bg);
  --color-info-bg: var(--accent-bg);

  /* === OVERLAYS === */
  --color-badge-overlay: rgba(0, 0, 0, 0.75);

  /* === INTERACTIVE === */
  --color-link: var(--accent);
  --color-link-hover: #4a8be5;

  /* === TYPOGRAPHY === */
  --font-sans: system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, monospace;

  --font-heading: var(--font-sans);
  --font-body: var(--font-sans);

  /* Font Sizes — bumped +2px from unified-v2 mockup for readability */
  --text-xs: 0.75rem;     /* 12px (was 10px) */
  --text-sm: 0.875rem;    /* 14px (was 12px) */
  --text-base: 1rem;      /* 16px (was 14px) */
  --text-md: 1.125rem;    /* 18px */
  --text-lg: 1.25rem;     /* 20px */
  --text-xl: 1.375rem;    /* 22px */
  --text-2xl: 1.75rem;    /* 28px */
  --text-3xl: 2.25rem;    /* 36px */
  --text-4xl: 3rem;       /* 48px */
  --text-5xl: 3.75rem;    /* 60px */
  --text-6xl: 4.5rem;     /* 72px */
  --text-label: 0.6875rem; /* 11px — monospace UI labels */

  /* Font Weights */
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  /* Line Heights — increased for readability */
  --leading-tight: 1.2;
  --leading-snug: 1.4;
  --leading-normal: 1.7;  /* was 1.5, bumped for hack.build readability */
  --leading-relaxed: 1.9;

  /* Letter Spacing */
  --tracking-tight: -0.02em;
  --tracking-normal: 0;
  --tracking-wide: 0.04em;
  --tracking-wider: 0.08em;
  --tracking-widest: 0.12em;  /* for uppercase mono labels */

  /* === SPACING (4px base) === */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;     /* 24px — card body padding (increased from 20px) */
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;       /* 48px section padding */
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;       /* 72px section spacing */

  /* === SHAPE === */
  --radius: 0px;           /* sharp corners — the commonpub signature */
  --radius-none: 0;
  --radius-sm: 2px;
  --radius-md: 0;          /* override: sharp corners */
  --radius-lg: 0;
  --radius-xl: 0;
  --radius-2xl: 0;
  --radius-full: 50%;      /* avatars only */

  --border-width-thin: 1px;
  --border-width-default: 2px;  /* strong 2px borders — the commonpub signature */
  --border-width-thick: 3px;

  /* === SHADOWS (offset, no blur — the commonpub signature) === */
  --shadow-sm: 2px 2px 0 var(--border);
  --shadow-md: 4px 4px 0 var(--border);
  --shadow-lg: 6px 6px 0 var(--border);
  --shadow-xl: 8px 8px 0 var(--border);
  --shadow-accent: 4px 4px 0 var(--accent);
  /* Component surface shadow. Built-in themes deliberately do NOT override these
   * (only --shadow-* above), so buttons/cards keep the offset-block signature.
   * Theme Studio emits them per the recipe's shadowStyle so a custom theme's
   * buttons/cards reflect its archetype (neumorphic relief, soft blur, etc.). */
  --shadow-block: 4px 4px 0 var(--border);
  --shadow-block-sm: 2px 2px 0 var(--border);

  /* === TREATMENTS ===
     Surface effects. Defaults are TRUE no-ops: `none`, never `blur(0)` — any
     non-none backdrop-filter creates a stacking context and becomes the
     containing block for fixed/absolute descendants, which would move
     dropdowns/modals on every existing theme. Built-in themes don't set
     these; Theme Studio emits them for glass recipes. */
  --surface-backdrop: none;  /* backdrop-filter for cards/panels (glass) */
  --bg-image: none;          /* page background gradient (gradients only) */

  /* === TRANSITIONS === */
  --transition-fast: 0.1s ease;
  --transition-default: 0.15s ease;
  --transition-slow: 0.3s ease;

  /* === Z-INDEX SCALE === */
  --z-dropdown: 100;
  --z-sticky: 200;
  --z-fixed: 500;
  --z-modal-backdrop: 900;
  --z-modal: 1000;
  --z-toast: 1050;
  --z-tooltip: 1100;

  /* === LAYOUT === */
  --nav-height: 3rem;       /* 48px topbar */
  --subnav-height: 2.75rem;
  --sidebar-width: 12.5rem; /* 200px fixed sidebar */
  --sidebar-width-collapsed: 3.5rem; /* 56px icons-only — admin chrome collapsed state */
  --content-max-width: 60rem; /* 960px */
  --content-wide-max-width: 75rem;

  /* === CONTENT-CARD GRID ===
     Every grid that lays out <ContentCard> draws its column min-width + gap
     from these tokens so cards are a single, consistent size everywhere they
     appear (home feed, listing pages, search, explore, profiles, hubs…).
     Default values match deveco.io's responsive card grid. Instances retune
     by overriding these tokens in their theme CSS — no per-view edits. */
  --cpub-card-min: 260px;  /* min column width before wrapping (auto-fill) */
  --cpub-card-gap: 20px;   /* gutter between cards */

  /* === CHROME (topbar / nav / footer / banner) ===
     The global layout chrome is fully token-driven so an instance theme can change
     its SHAPE — not just colors — without forking the layout (the deveco use case).
     Every default below EXACTLY reproduces the current base look, so existing
     instances + built-in themes are unaffected unless they opt in by overriding a
     token. A theme that wants e.g. deveco's elevated rounded bar sets these in its
     own [data-theme="…"] / :root block. See layers/base/layouts/default.vue. */

  /* Top bar */
  --cpub-topbar-height: 48px;              /* MUST match the content top-offset + mobile-menu top */
  --cpub-topbar-bg: var(--surface);
  --cpub-topbar-border: var(--border-width-default) solid var(--border); /* shorthand: full bottom border */
  --cpub-topbar-radius: 0;                 /* deveco: 12px rounded bottom */
  --cpub-topbar-shadow: none;              /* deveco: 0 2px 8px rgba(0,0,0,.08) */
  --cpub-topbar-position: fixed;           /* deveco: sticky */
  --cpub-topbar-padding-x: 20px;
  --cpub-topbar-blur: none;                /* deveco: blur(8px) backdrop */
  /* Top offset reserved for the fixed bar. A theme that makes the bar `sticky`
     (which reserves its own space) should set this to 0. Default = the bar height. */
  --cpub-content-top-offset: var(--cpub-topbar-height, 48px);

  /* Nav links (rendered by NavRenderer → .cpub-nav-link) */
  --cpub-nav-link-size: 12px;              /* deveco: 14px */
  --cpub-nav-link-weight: 400;             /* deveco: 500 */
  --cpub-nav-link-padding: 5px 12px;       /* deveco: 8px 14px */
  --cpub-nav-link-radius: var(--radius);   /* deveco: 6px (pill) */
  --cpub-nav-link-color: var(--text-dim);
  --cpub-nav-link-active-color: var(--text);          /* deveco: var(--deveco-dark-green) */
  --cpub-nav-link-active-bg: var(--surface2);          /* deveco: var(--accent-bg) */
  --cpub-nav-link-active-weight: 400;                  /* deveco: 600 */
  --cpub-nav-link-active-border: var(--border);        /* color of the active link border */

  /* Footer */
  --cpub-footer-bg: var(--surface);        /* deveco: var(--deveco-dark-green) */
  --cpub-footer-text: var(--text-dim);     /* body/link text; deveco: rgba(255,255,255,.7) */
  --cpub-footer-muted: var(--text-faint);  /* col titles / bottom bar; deveco: rgba(255,255,255,.4) */
  --cpub-footer-border: var(--border);     /* deveco: rgba(255,255,255,.1) */
  --cpub-footer-link-hover: var(--text);   /* link hover color; deveco: var(--accent) */
  --cpub-footer-heading: var(--text);      /* brand logo text; deveco uses its dark-bg logo */

  /* === FOCUS === */
  --focus-ring: var(--shadow-accent);
}

/* Branded-but-readable inline code: mix the theme's --teal ~50% toward --text so it
   reads at ~6:1 on light themes and adapts on dark (mixes toward the light --text).
   One definition adapts to every theme because the inner var()s resolve at the
   inline-code element. ~95% browser support; older browsers keep the readable
   --text fallback declared in :root above. */
@supports (color: color-mix(in srgb, red, white)) {
  :root {
    --code-inline: color-mix(in srgb, var(--teal), var(--text) 50%);
    /* Mix % tuned per color so each clears ≥4.5:1 on white/--surface2/own *-bg
       (verified empirically). Mixing toward --text only lightens vivids on dark
       themes, so the same values pass there too (6.9-10.8:1). */
    --green-text: color-mix(in srgb, var(--green), var(--text) 50%);
    --yellow-text: color-mix(in srgb, var(--yellow), var(--text) 50%);
    --red-text: color-mix(in srgb, var(--red), var(--text) 25%);
    --teal-text: color-mix(in srgb, var(--teal), var(--text) 45%);
    --purple-text: color-mix(in srgb, var(--purple), var(--text) 20%);
    --pink-text: color-mix(in srgb, var(--pink), var(--text) 30%);
    --accent-text: color-mix(in srgb, var(--accent), var(--text) 40%);
  }
}

/* === BASE STYLES === */
body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text);
  background-color: var(--bg);
  background-image: var(--bg-image, none);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

/* Surface radius. Real UI surfaces (buttons, cards, inputs, tags, panels)
 * inherit the theme's --radius. Structural, media, and decorative elements are
 * reset to 0 below so a rounded theme (e.g. Stoa, --radius:12px) does NOT put
 * radii on line breaks, dividers, rules, icons, images, table cells, or
 * pseudo-element decorations — the "line breaks carry rounded corners" bug.
 * (Elements that genuinely want rounding set it explicitly, e.g. avatars use
 * --radius-full; an explicit class-level border-radius outranks these resets.) */
* {
  border-radius: var(--radius);
}

hr,
svg,
img,
picture,
video,
canvas,
iframe,
table, thead, tbody, tfoot, tr, td, th, caption, col, colgroup,
::before,
::after,
::marker,
::placeholder,
.cpub-divider {
  border-radius: 0;
}

/* === ACCESSIBILITY === */

/* Skip-to-content link */
.cpub-skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: var(--z-tooltip);
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: var(--color-on-accent);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  text-decoration: none;
  border: var(--border-width-default) solid var(--border);
}

.cpub-skip-link:focus {
  top: var(--space-2);
}

/* Focus-visible ring for all interactive elements */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

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

/* Screen reader only utility */
.cpub-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* === CONTENT TYPE BADGE COLORS === */
[data-content-type="article"] { --badge-color: var(--accent); --badge-bg: var(--accent-bg); }
[data-content-type="blog"] { --badge-color: var(--green); --badge-bg: var(--green-bg); }
[data-content-type="project"] { --badge-color: var(--purple); --badge-bg: var(--purple-bg); }
[data-content-type="explainer"] { --badge-color: var(--teal); --badge-bg: var(--teal-bg); }
[data-content-type="video"] { --badge-color: var(--red); --badge-bg: var(--red-bg); }
[data-content-type="tutorial"] { --badge-color: var(--yellow); --badge-bg: var(--yellow-bg); }
}
