SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%

# Patterns — Design Tokens & Theming

# Contents

  • Starter token sheet (primitives)
  • Semantic tokens, light + dark
  • Component tier example
  • Theme toggle (no-flash)
  • Contrast quick-check
  • Gotchas

# Starter token sheet (primitives)

css
:root {
  /* Neutral ramp (5 steps is enough to start) */
  --gray-50:  #f8fafc;
  --gray-200: #e2e8f0;
  --gray-500: #64748b;
  --gray-800: #1e293b;
  --gray-950: #0b1220;

  /* Accent ramp */
  --blue-400: #60a5fa;
  --blue-600: #2563eb;
  --blue-700: #1d4ed8;

  /* Status */
  --green-600: #16a34a;
  --amber-600: #d97706;
  --red-600:   #dc2626;

  /* Spacing — base-4 scale */
  --space-1: 0.25rem;  --space-2: 0.5rem;  --space-3: 0.75rem;
  --space-4: 1rem;     --space-6: 1.5rem;  --space-8: 2rem;
  --space-12: 3rem;    --space-16: 4rem;

  /* Radius & shadows — 3 levels each */
  --radius-sm: 0.25rem; --radius-md: 0.5rem; --radius-full: 9999px;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.06);
  --shadow-2: 0 4px 8px rgb(0 0 0 / 0.10);
  --shadow-3: 0 12px 24px rgb(0 0 0 / 0.14);

  color-scheme: light dark;
}

# Semantic tokens, light + dark

css
/* Light (default) */
:root, [data-theme="light"] {
  --color-bg-page:     var(--gray-50);
  --color-bg-surface:  #ffffff;
  --color-text:        var(--gray-800);   /* on bg-page: 12.6:1 ✓ */
  --color-text-muted:  var(--gray-500);   /* on surface: 4.8:1 ✓  */
  --color-border:      var(--gray-200);
  --color-accent:      var(--blue-600);   /* as text on surface: 5.2:1 ✓ */
  --color-accent-hover: var(--blue-700);
  --color-danger:      var(--red-600);
}

/* Dark via system preference (only when no explicit choice) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --color-bg-page:     var(--gray-950);
    --color-bg-surface:  var(--gray-800);
    --color-text:        var(--gray-50);
    --color-text-muted:  #94a3b8;         /* on gray-800: 5.9:1 ✓ */
    --color-border:      #334155;
    --color-accent:      var(--blue-400); /* lighter accent for dark bg: 6.6:1 ✓ */
    --color-accent-hover: #93c5fd;
  }
}

/* Dark via explicit user choice — identical block, attribute-scoped */
[data-theme="dark"] {
  --color-bg-page:     var(--gray-950);
  --color-bg-surface:  var(--gray-800);
  --color-text:        var(--gray-50);
  --color-text-muted:  #94a3b8;
  --color-border:      #334155;
  --color-accent:      var(--blue-400);
  --color-accent-hover: #93c5fd;
}

# Component tier example

css
.button-primary {
  background: var(--color-accent);
  color: var(--color-bg-surface);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-1);
}
.button-primary:hover { background: var(--color-accent-hover); }

.card {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-6);
}

# Theme toggle (no-flash)

html
<!-- In <head>, BEFORE any stylesheet, so first paint is themed -->
<script>
  const t = localStorage.getItem("theme");           // "light" | "dark" | null
  if (t) document.documentElement.dataset.theme = t; // absent = follow system
</script>
js
function setTheme(next) {           // next: "light" | "dark" | "system"
  if (next === "system") {
    delete document.documentElement.dataset.theme;
    localStorage.removeItem("theme");
  } else {
    document.documentElement.dataset.theme = next;
    localStorage.setItem("theme", next);
  }
}

# Contrast quick-check

Compute ratio = (L1 + 0.05) / (L2 + 0.05) with relative luminance, or verify in devtools (element → color picker shows the ratio). Thresholds to enforce in the token sheet:

Pair Minimum
Body/label text on its background 4.5:1 (AA)
Large text ≥24px (or 18.7px bold) 3:1
UI component borders, icons, focus rings 3:1

# Gotchas

  • prefers-color-scheme block must exclude explicit choices — scope it with :root:not([data-theme]) or a user who picked "light" gets system-dark anyway.
  • Forgetting color-scheme: light dark leaves scrollbars, form controls, and default UA styles stuck in light mode.
  • Muted text is the #1 AA failure — grays around #999 fail on white (2.8:1). Nothing lighter than #767676 for body-size text on white.
  • Same accent in both themes usually fails one of them — accents need a per-theme value (darker for light bg, lighter for dark bg).
  • rgb(0 0 0 / 0.5)-style translucent text has no fixed contrast ratio (depends on what's behind) — use opaque token colors for text.
  • Tokens in shadows: define whole shadows as tokens, not just colors — dark themes often need different alpha, not different hue.