Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions site/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ export default defineConfig({
markdown: {
remarkPlugins: [rewriteMdLinks],
shikiConfig: {
// github-dark-high-contrast passes WCAG AA for all token colors
// (#6A737D comment color in github-dark fails 3.05:1 on its #24292e bg)
theme: 'github-dark-high-contrast',
// css-variables theme so syntax colors come from the CorvidLabs brand
// --code-* tokens (mapped to --astro-code-token-* in globals.css). This
// follows light/dark automatically and keeps code on-brand (no purple/blue).
theme: 'css-variables',
},
},
})
1 change: 1 addition & 0 deletions site/public/brand/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.1.0 (317e2c4)
13 changes: 13 additions & 0 deletions site/public/brand/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions site/public/brand/logo-mark-reversed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions site/public/brand/logo-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions site/public/brand/mascot.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions site/public/brand/theme-toggle.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!-- ============================================================
CorvidLabs theme toggle — the standard sun/moon button.
Never ship a "THEME" text button. Copy the three blocks below.
============================================================ -->

<!-- 1. PRE-PAINT (inline in <head>, before any CSS) — sets the theme
before first paint so a stored choice never flashes. -->
<script>
(() => {
try {
const q = new URLSearchParams(location.search).get("theme");
const t = q || localStorage.getItem("corvid-theme");
if (t === "light" || t === "dark") document.documentElement.dataset.theme = t;
} catch (_) {}
})();
</script>

<!-- 2. THE BUTTON — drop in your header. The icon shown reflects the
current mode (sun in light, moon in dark); the swap is CSS, so
it's correct on first paint. theme.js keeps the aria-label fresh. -->
<button type="button" class="corvid-theme-toggle"
data-corvid-theme-toggle aria-pressed="false"
aria-label="Switch to dark theme" title="Switch theme">
<svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="12" cy="12" r="4.2" />
<path d="M12 2.6v2.4M12 19v2.4M4.2 4.2l1.7 1.7M18.1 18.1l1.7 1.7M2.6 12h2.4M19 12h2.4M4.2 19.8l1.7-1.7M18.1 5.9l1.7-1.7" />
</svg>
<svg class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21 12.8A8.6 8.6 0 1 1 11.2 3a6.7 6.7 0 0 0 9.8 9.8z" />
</svg>
</button>

<!-- 3. THE STYLES — uses tokens.css variables; the icon swap mirrors
the token cascade so it never disagrees with the page. -->
<style>
.corvid-theme-toggle {
display: inline-flex; align-items: center; justify-content: center;
width: 34px; height: 34px; padding: 0;
background: none; border: 1px solid var(--ink-12); color: var(--ink-70);
cursor: pointer; transition: border-color 0.2s, color 0.2s;
}
.corvid-theme-toggle:hover { border-color: var(--sheen); color: var(--sheen); }
.corvid-theme-toggle:focus-visible { outline: 2px solid var(--sheen); outline-offset: 2px; }
.corvid-theme-toggle svg { width: 17px; height: 17px; }

/* Show the current mode's icon. */
.corvid-theme-toggle .moon { display: none; }
:root[data-theme="dark"] .corvid-theme-toggle .sun { display: none; }
:root[data-theme="dark"] .corvid-theme-toggle .moon { display: inline; }
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) .corvid-theme-toggle .sun { display: none; }
:root:not([data-theme="light"]) .corvid-theme-toggle .moon { display: inline; }
}
/* A forced-light page while the OS is dark must show the sun again. */
:root[data-theme="light"] .corvid-theme-toggle .sun { display: inline; }
:root[data-theme="light"] .corvid-theme-toggle .moon { display: none; }
</style>
71 changes: 71 additions & 0 deletions site/public/brand/theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* ============================================================
CorvidLabs theme controller — the standard light/dark behavior.

Drop this on any page that imports tokens.css. It:
- defaults to the OS preference (prefers-color-scheme)
- lets ?theme=light|dark force a mode (handy for QA screenshots)
- persists an explicit choice in localStorage
- wires every [data-corvid-theme-toggle] button: click to flip,
with aria-pressed + a descriptive aria-label kept in sync.

The sun/moon icon swap itself is pure CSS (see theme-toggle.html),
so the correct icon shows on first paint with no flash. This script
only manages state + accessibility.

For zero flash of the wrong THEME, also inline the pre-paint snippet
from theme-toggle.html in <head>; this file can load with defer.
============================================================ */
(() => {
"use strict";

const root = document.documentElement;
const STORE_KEY = "corvid-theme";

const systemDark = () => window.matchMedia("(prefers-color-scheme: dark)").matches;
const isDark = () =>
root.dataset.theme === "dark" || (!root.dataset.theme && systemDark());

// Apply a stored or URL-forced choice (the pre-paint snippet may
// have already done this; re-applying is idempotent).
const urlTheme = new URLSearchParams(location.search).get("theme");
let saved = urlTheme;
if (!saved) {
// localStorage access can throw in sandboxed iframes / disabled-storage
// private modes — guard it so the toggle still initializes.
try {
saved = localStorage.getItem(STORE_KEY);
} catch (_) {
/* no stored preference available */
}
}
if (saved === "dark" || saved === "light") {
root.dataset.theme = saved;
}

const buttons = document.querySelectorAll("[data-corvid-theme-toggle]");

const reflect = () => {
const dark = isDark();
buttons.forEach((btn) => {
btn.setAttribute("aria-pressed", String(dark));
btn.setAttribute(
"aria-label",
dark ? "Switch to light theme" : "Switch to dark theme"
);
});
};

buttons.forEach((btn) => {
btn.addEventListener("click", () => {
root.dataset.theme = isDark() ? "light" : "dark";
try {
localStorage.setItem(STORE_KEY, root.dataset.theme);
} catch (_) {
/* storage may be unavailable; the in-page choice still applies */
}
reflect();
});
});

reflect();
})();
139 changes: 139 additions & 0 deletions site/public/brand/tokens.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* ============================================================
CorvidLabs Brand Tokens
The single source of truth. Import this file, don't re-derive it.

Light is the default. Dark follows the OS via prefers-color-scheme,
and either can be forced with data-theme="light|dark" on <html>
(the sun/moon toggle in theme.js writes it). Every token is defined
in both modes, so anything built on these tokens themes for free.
============================================================ */

:root {
color-scheme: light;

/* Core surfaces */
--ink: #15181B; /* near-black, slightly cool — primary text/marks */
--paper: #FAF9F6; /* warm off-white — page ground */
--surface: #FFFFFF; /* cards, raised panels */
--surface-strong: #DCDAD2; /* inputs, wells, lifted surfaces */

/* Accent — corvid feather sheen. Never purple. */
--sheen: #0E6F66; /* the accent — 5.9:1 on paper (AA) */
--sheen-strong: #0B5750; /* deepened — 8:1 on paper, for small accent text (AAA) */
--sheen-bright: #45D0BC; /* glint — for use ON ink only */
--steel: #1E6FA8; /* gradient end only, never text */

/* Ink alpha steps (text + hairlines over light surfaces) */
--ink-70: rgba(21, 24, 27, 0.72);
--ink-60: rgba(21, 24, 27, 0.62);
--ink-45: rgba(21, 24, 27, 0.45);
--ink-12: rgba(21, 24, 27, 0.12);
--ink-06: rgba(21, 24, 27, 0.06);
--hairline: var(--ink-12);
--header-bg: rgba(250, 249, 246, 0.92);

/* Semantic state colors (defined so sites stop improvising) */
--danger: #84241E; /* errors, destructive, recording */
--warning: #8A5A00; /* in-progress, caution */
--success: #2F6B3A; /* shipped, healthy */
--info: var(--sheen);/* informational — reuses the accent by design */

/* Code syntax highlighting (docs, terminals) — never purple */
--code-keyword: #0B5750;
--code-string: #2F6B3A;
--code-number: #8A5A00;
--code-function: #1B5E8A; /* also types */
--code-comment: rgba(21, 24, 27, 0.50);

/* Categorical chart / data-viz palette — distinguishable, never purple */
--chart-1: #0E6F66; /* teal */
--chart-2: #1E6FA8; /* steel */
--chart-3: #B07A1E; /* amber */
--chart-4: #2F6B3A; /* green */
--chart-5: #A0492E; /* clay */

/* The one gradient we allow: a feather-sheen hairline. Decorative only. */
--iridescence: linear-gradient(90deg, #0E6F66 0%, #1799A3 55%, #1E6FA8 100%);

/* Type */
--font-display: "Schibsted Grotesk", "Helvetica Neue", sans-serif;
--font-mono: "Spline Sans Mono", "SF Mono", monospace;
--measure: 64ch;
}

/* Dark surfaces. Declared once, applied via the forced override below
and the system-preference media query. */
:root[data-theme="dark"] {
color-scheme: dark;

--ink: #F4F3EF;
--paper: #131619;
--surface: #1B1F23;
--surface-strong: #272C31;

--sheen: #45D0BC;
--sheen-strong: #45D0BC;
--sheen-bright: #45D0BC;

--ink-70: rgba(244, 243, 239, 0.78);
--ink-60: rgba(244, 243, 239, 0.68);
--ink-45: rgba(244, 243, 239, 0.55);
--ink-12: rgba(244, 243, 239, 0.15);
--ink-06: rgba(244, 243, 239, 0.08);
--header-bg: rgba(19, 22, 25, 0.92);

--danger: #F08A7D;
--warning: #E0B05A;
--success: #6FC98A;

--code-keyword: #45D0BC;
--code-string: #6FC98A;
--code-number: #E0B05A;
--code-function: #6BB6E0;
--code-comment: rgba(244, 243, 239, 0.50);

--chart-1: #45D0BC;
--chart-2: #6BB6E0;
--chart-3: #E0B05A;
--chart-4: #6FC98A;
--chart-5: #E0916F;
}

@media (prefers-color-scheme: dark) {
/* :not([data-theme="light"]) lets a forced-light override win. */
:root:not([data-theme="light"]) {
color-scheme: dark;

--ink: #F4F3EF;
--paper: #131619;
--surface: #1B1F23;
--surface-strong: #272C31;

--sheen: #45D0BC;
--sheen-strong: #45D0BC;
--sheen-bright: #45D0BC;

--ink-70: rgba(244, 243, 239, 0.78);
--ink-60: rgba(244, 243, 239, 0.68);
--ink-45: rgba(244, 243, 239, 0.55);
--ink-12: rgba(244, 243, 239, 0.15);
--ink-06: rgba(244, 243, 239, 0.08);
--header-bg: rgba(19, 22, 25, 0.92);

--danger: #F08A7D;
--warning: #E0B05A;
--success: #6FC98A;

--code-keyword: #45D0BC;
--code-string: #6FC98A;
--code-number: #E0B05A;
--code-function: #6BB6E0;
--code-comment: rgba(244, 243, 239, 0.50);

--chart-1: #45D0BC;
--chart-2: #6BB6E0;
--chart-3: #E0B05A;
--chart-4: #6FC98A;
--chart-5: #E0916F;
}
}
11 changes: 6 additions & 5 deletions site/src/components/Button.astro
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ const Tag = href ? 'a' : 'button'
<style is:global>
.btn {
display: inline-flex; align-items: center; gap: 8px;
padding: 12px 20px; border-radius: 8px;
padding: 12px 20px;
font-size: 0.9375rem; font-weight: 500; text-decoration: none;
border: 1px solid transparent; cursor: pointer;
min-height: 44px; font-family: inherit;
transition: all .15s ease;
transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.btn-primary { background: var(--accent); color: #1a0f08; font-weight: 600; }
.btn-primary:hover { background: var(--accent-bright); }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } }
.btn-primary { background: var(--ink); color: var(--paper); font-weight: 600; }
.btn-primary:hover { background: var(--sheen-strong); color: var(--paper); }
.btn-secondary { background: transparent; color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover { border-color: var(--accent); color: var(--accent-bright); background: var(--accent-muted); }
.btn-secondary:hover { border-color: var(--accent); color: var(--accent); background: var(--ink-06); }
.btn-ghost { background: transparent; color: var(--text-muted); padding: 12px 14px; }
.btn-ghost:hover { color: var(--text); }
</style>
18 changes: 9 additions & 9 deletions site/src/components/Callout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ const { type = 'note' } = Astro.props

<style is:global>
.callout { padding: 16px 18px; border-left: 3px solid var(--accent);
background: var(--accent-muted); border-radius: 0 8px 8px 0; margin: 20px 0; }
background: var(--ink-06); margin: 20px 0; }
.callout p:last-child { margin-bottom: 0; }
.callout strong { color: var(--accent-bright); }
.callout-warn { border-left-color: #f87171; background: rgba(248,113,113,0.08); }
.callout-warn strong { color: #fca5a5; }
.callout-tip { border-left-color: #34d399; background: rgba(52,211,153,0.08); }
.callout-tip strong { color: #6ee7b7; }
.callout-drift { border-left-color: var(--drift); background: var(--drift-muted);
.callout strong { color: var(--accent); }
.callout-warn { border-left-color: var(--warning); }
.callout-warn strong { color: var(--warning); }
.callout-tip { border-left-color: var(--success); }
.callout-tip strong { color: var(--success); }
.callout-drift { border-left-color: var(--warning); background: var(--ink-06);
display: flex; gap: 12px; align-items: flex-start; }
.callout-drift strong { color: var(--drift); }
.callout-drift-icon { font-size: 1.1rem; color: var(--drift); flex-shrink: 0; margin-top: 1px; }
.callout-drift strong { color: var(--warning); }
.callout-drift-icon { font-size: 1.1rem; color: var(--warning); flex-shrink: 0; margin-top: 1px; }
</style>
Loading
Loading