How to use the Color Matrix
- Browse palettes: Each column is a color family (Primary, Secondary, Neutral, etc.). Each card is a stop (ultra-light → ultra-dark).
- Copy an OKLCH value: Click the OKLCH value on a card to copy only the oklch(…) string to your clipboard. You’ll see a quick “Copied” toast confirmation.
- See transparency steps: Click the palette icon on a card to open a popover showing ready-to-use transparency steps for that token (using color-mix(in oklch, var(–token) …, transparent)).
- Close the popover: Press Esc, click the X, or click outside the popover to close it.
- Accessibility note: Text colors are automatically chosen (black/white) to meet the APCA minimum. The “Copied” toast always stays the same style for consistency.
- Just add the code to your snippet manager of choice (e.g., wpCodeBox) or your functions.php.
<?php
/**
* Shortcode: [acss_colors] v3.1
*
* Reads ACSS variables directly from:
* wp-content/uploads/automatic-css/automatic.css
*
* Usage:
* [acss_colors]
* [acss_colors prefixes="primary,secondary,tertiary,accent,base,neutral,danger,warning,info,success" mono="true" debug="false"]
*/
add_shortcode('acss_colors', function($atts = []) {
$atts = shortcode_atts([
'prefixes' => 'primary,secondary,tertiary,accent,base,neutral,danger,warning,info,success',
'mono' => 'false',
'debug' => 'false',
], $atts, 'acss_colors');
$prefixes = array_values(array_filter(array_map('trim', explode(',', strtolower($atts['prefixes'])))));
$include_mono = in_array(strtolower(trim($atts['mono'])), ['1','true','yes','on'], true);
$debug = in_array(strtolower(trim($atts['debug'])), ['1','true','yes','on'], true);
$uid = 'acss-matrix-' . wp_generate_uuid4();
// ---- 1) Locate ACSS file on disk (uploads/automatic-css/automatic.css)
$uploads = wp_upload_dir(null, false);
$acss_dir = trailingslashit($uploads['basedir']) . 'automatic-css/';
$acss_file = $acss_dir . 'automatic.css';
// Fallback: newest *.css in folder
if (!is_readable($acss_file)) {
$candidates = glob($acss_dir . '*.css') ?: [];
if ($candidates) {
usort($candidates, fn($a, $b) => filemtime($b) <=> filemtime($a));
$acss_file = $candidates[0];
}
}
if (!is_readable($acss_file)) {
return '<p><strong>ACSS Color Matrix:</strong> Could not read the ACSS stylesheet in uploads/automatic-css.</p>';
}
$css_text = file_get_contents($acss_file);
if (!is_string($css_text) || $css_text === '') {
return '<p><strong>ACSS Color Matrix:</strong> ACSS stylesheet was empty or unreadable.</p>';
}
// ---- 2) Parse custom properties: --foo: value;
$css_text = preg_replace('~/\*.*?\*/~s', '', $css_text);
$vars = [];
if (preg_match_all('/(--[a-zA-Z0-9_-]+)\s*:\s*([^;}{]+);/', $css_text, $m, PREG_SET_ORDER)) {
foreach ($m as $match) {
$name = trim($match[1]);
$val = trim($match[2]);
if ($val === '') continue;
$vars[$name] = $val; // last wins
}
}
// Label overrides (base -> core)
$label_map = [
'base' => 'core',
];
// ---- 3) Build matrix columns (family + stop order)
$stops = ['ultra-light','light','semi-light','base','hover','semi-dark','dark','ultra-dark'];
$columns = [];
foreach ($prefixes as $family) {
$rows = [];
foreach ($stops as $stop) {
$var_name = ($stop === 'base') ? '--' . $family : '--' . $family . '-' . $stop;
if (isset($vars[$var_name])) {
$rows[] = [$stop, $var_name, $vars[$var_name]];
}
}
if (!empty($rows)) {
$columns[ucfirst($family)] = $rows;
}
}
if ($include_mono) {
$mono = [];
foreach (['--white','--black'] as $vn) {
if (isset($vars[$vn])) $mono[] = [ltrim($vn, '-'), $vn, $vars[$vn]];
}
if (!empty($mono)) $columns['Mono'] = $mono;
}
if (empty($columns)) {
$count = count($vars);
$msg = '<p><strong>ACSS Color Matrix:</strong> Parsed the ACSS file but found no matching families.</p>';
if ($debug) {
$msg .= '<pre style="padding:12px;border:1px solid #ddd;overflow:auto;">'
. esc_html("File: {$acss_file}\nTotal vars parsed: {$count}\nTry debug=1 or adjust prefixes=")
. '</pre>';
}
return $msg;
}
// ---- 4) Render output
ob_start();
if ($debug) {
echo '<pre style="padding:12px;border:1px solid #ddd;overflow:auto;margin:0 0 12px;">';
echo esc_html("ACSS file: {$acss_file}\nTotal vars parsed: " . count($vars) . "\nColumns rendered: " . count($columns));
echo '</pre>';
}
?>
<div class="acss-matrix" id="<?php echo esc_attr($uid); ?>">
<div class="acss-matrix__grid" aria-label="ACSS color matrix">
<?php foreach ($columns as $title => $rows): ?>
<div class="acss-matrix__col" aria-label="<?php echo esc_attr($title); ?>">
<div class="acss-matrix__title"><?php echo esc_html($title); ?></div>
<?php foreach ($rows as $i => [$label, $var_name, $value]): ?>
<?php
$sw_id = $uid . '-' . sanitize_title($title) . '-' . intval($i) . '-' . wp_generate_password(6, false, false);
$anchor_name = '--acss-anchor-' . $sw_id;
$popover_id = 'acss-pop-' . $sw_id;
$pretty_label = $label_map[$label] ?? $label;
$theme_group_id = 'acss-theme-' . $sw_id;
?>
<div
class="acss-matrix__swatch"
style="background: <?php echo esc_attr($value); ?>"
data-value="<?php echo esc_attr($value); ?>"
data-var="<?php echo esc_attr($var_name); ?>"
data-popover="<?php echo esc_attr($popover_id); ?>"
data-anchor="<?php echo esc_attr($anchor_name); ?>"
>
<div class="acss-matrix__meta">
<div class="acss-matrix__label"><?php echo esc_html($pretty_label); ?></div>
<div class="acss-matrix__meta-right">
<div class="acss-matrix__badge" aria-hidden="true"></div>
<button
type="button"
class="acss-matrix__palette-btn"
aria-label="<?php echo esc_attr('Show transparency steps for ' . $var_name); ?>"
popovertarget="<?php echo esc_attr($popover_id); ?>"
popovertargetaction="toggle"
style="anchor-name: <?php echo esc_attr($anchor_name); ?>;"
>
<svg aria-hidden="true" viewBox="0 0 24 24" focusable="false">
<path fill="currentColor" d="M12 2a10 10 0 0 0-9.95 11A4.5 4.5 0 0 0 6.5 17.5H8c.6 0 1 .4 1 1v.5a3 3 0 0 0 3 3h.5a10 10 0 0 0-.5-20Zm-5 13a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3-4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm4 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3 4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Z"/>
</svg>
</button>
</div>
</div>
<!-- Click to copy: copies ONLY the oklch value (or raw value if not oklch) -->
<button type="button" class="acss-matrix__value" aria-label="<?php echo esc_attr('Copy value ' . $value); ?>">
<?php echo esc_html($var_name . ': ' . $value); ?>
</button>
<!-- Local feedback -->
<div class="acss-matrix__copied" role="status" aria-live="polite" aria-atomic="true">
Copied
</div>
<!-- Popover -->
<div
id="<?php echo esc_attr($popover_id); ?>"
class="acss-matrix__alpha-pop"
popover
aria-label="<?php echo esc_attr('Transparency steps for ' . $var_name); ?>"
data-owner="<?php echo esc_attr($sw_id); ?>"
data-theme="acss"
>
<div class="acss-matrix__alpha-head">
<div class="acss-matrix__alpha-title"><?php echo esc_html(str_replace('--', '-', $var_name)); ?></div>
<!-- Theme switcher (ACSS default) -->
<fieldset class="acss-matrix__theme" aria-label="Popup theme">
<legend class="acss-matrix__sr-only">Popup theme</legend>
<input class="acss-matrix__theme-input" type="radio"
name="<?php echo esc_attr($theme_group_id); ?>"
id="<?php echo esc_attr($theme_group_id . '-acss'); ?>"
value="acss" checked>
<label class="acss-matrix__theme-btn" for="<?php echo esc_attr($theme_group_id . '-acss'); ?>">ACSS</label>
<input class="acss-matrix__theme-input" type="radio"
name="<?php echo esc_attr($theme_group_id); ?>"
id="<?php echo esc_attr($theme_group_id . '-light'); ?>"
value="light">
<label class="acss-matrix__theme-btn" for="<?php echo esc_attr($theme_group_id . '-light'); ?>">Light</label>
<input class="acss-matrix__theme-input" type="radio"
name="<?php echo esc_attr($theme_group_id); ?>"
id="<?php echo esc_attr($theme_group_id . '-dark'); ?>"
value="dark">
<label class="acss-matrix__theme-btn" for="<?php echo esc_attr($theme_group_id . '-dark'); ?>">Dark</label>
</fieldset>
<button type="button" class="acss-matrix__alpha-close" aria-label="Close" popovertarget="<?php echo esc_attr($popover_id); ?>" popovertargetaction="hide">
<svg aria-hidden="true" viewBox="0 0 24 24" focusable="false">
<path fill="currentColor" d="M18.3 5.7a1 1 0 0 0-1.4 0L12 10.6 7.1 5.7a1 1 0 1 0-1.4 1.4l4.9 4.9-4.9 4.9a1 1 0 1 0 1.4 1.4l4.9-4.9 4.9 4.9a1 1 0 0 0 1.4-1.4L13.4 12l4.9-4.9a1 1 0 0 0 0-1.4Z"/>
</svg>
</button>
</div>
<div class="acss-matrix__alpha-body">
<div class="acss-matrix__alpha-row acss-matrix__alpha-row--base">
<div class="acss-matrix__alpha-chip" aria-hidden="true"></div>
<div class="acss-matrix__alpha-code"></div>
</div>
<div class="acss-matrix__alpha-list" role="list"></div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
</div>
</div>
<style>
#<?php echo esc_attr($uid); ?>{
--col-w: 18rem;
--swatch-h: 150px;
--gap: 16px;
--radius: var(--radius-l);
--border: rgb(0 0 0 / .08);
--shadow: 0 1px 2px rgb(0 0 0 / .10);
--font: var(--sans,apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, Adwaita Sans, Cantarell, Ubuntu, roboto, noto, helvetica, arial, sans-serif);
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono","Courier New", monospace;
--apca-min: 60;
--pop-w: clamp(18rem, 42vw, 34rem);
font-family: var(--font);
}
#<?php echo esc_attr($uid); ?>,
#<?php echo esc_attr($uid); ?> *{
box-sizing: border-box;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__grid{
display: grid;
grid-auto-flow: column;
grid-auto-columns: var(--col-w);
gap: var(--card-gap, var(--gap));
align-items: start;
overflow-x: auto;
padding: var(--space-m);
width: 100%;
max-width: 100%;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__col{
display: grid;
gap: var(--card-gap, 10px);
margin: 0;
padding: 0;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__title{
font-weight: 750;
font-size: 1rem;
letter-spacing: .2px;
padding: 6px 2px 2px;
margin: 0;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch{
height: var(--swatch-h);
border-radius: var(--radius);
position: relative;
overflow: visible;
isolation: isolate;
box-shadow: var(--shadow);
border: 1px solid var(--border);
corner-shape: squircle;
display: flex;
gap: var(--card-gap, 8px);
flex-direction: column;
padding: var(--space-s);
margin: 0;
color: #fff;
--swatch-scrim: transparent;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch.needs-scrim::before{
content: "";
position: absolute;
inset: 0;
background: var(--swatch-scrim);
pointer-events: none;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__meta,
#<?php echo esc_attr($uid); ?> .acss-matrix__value,
#<?php echo esc_attr($uid); ?> .acss-matrix__copied{
position: relative;
z-index: 1;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__meta{
display: flex;
align-items: center;
gap: 10px;
margin: 0;
min-width: 0;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__label{
font-weight: 800;
font-size: 1rem;
text-transform: uppercase;
letter-spacing: .06em;
margin: 0;
min-width: 0;
flex: 1 1 auto;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__meta-right{
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 8px;
flex: 0 0 auto;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__badge{
font-size: calc(var(--text-xs) - 3px);
padding: 4px 8px;
border-radius: 999px;
border: 1px solid rgb(255 255 255 / .35);
background: rgb(0 0 0 / .18);
line-height: 1;
white-space: nowrap;
margin: 0;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__palette-btn{
inline-size: 30px;
block-size: 30px;
border-radius: 999px;
border: 1px solid rgb(255 255 255 / .35);
background: rgb(0 0 0 / .18);
color: currentColor;
display: inline-grid;
place-items: center;
padding: 0;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__palette-btn svg{
inline-size: 18px;
block-size: 18px;
display: block;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__palette-btn:focus-visible{
outline: 2px solid currentColor;
outline-offset: 2px;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__value{
font-family: var(--font);
font-size: calc(var(--text-m) - 2px);
line-height: 1.15;
opacity: .98;
word-break: break-word;
margin: 0;
text-align: left;
border: 0;
background: transparent;
color: inherit;
padding: 0;
cursor: pointer;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__value:focus-visible{
outline: 2px solid currentColor;
outline-offset: 2px;
border-radius: 6px;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__copied{
position: absolute;
inset-inline: auto var(--space-s);
inset-block: auto var(--space-s);
padding: 6px 10px;
border-radius: 999px;
font-weight: 750;
font-size: 12px;
letter-spacing: .02em;
/* lock toast colors (no inheritance from swatch) */
color: #fff;
background: rgb(0 0 0 / .55);
border: 1px solid rgb(255 255 255 / .25);
backdrop-filter: blur(8px);
opacity: 0;
transform: translateY(6px);
pointer-events: none;
transition: opacity .18s ease, transform .18s ease;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch.is-copied .acss-matrix__copied{
opacity: 1;
transform: translateY(0);
}
/* is-light means dark text */
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch.is-light{
color: rgb(10 10 10);
}
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch.is-light .acss-matrix__badge,
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch.is-light .acss-matrix__palette-btn{
border-color: rgb(0 0 0 / .18);
background: rgb(255 255 255 / .60);
}
#<?php echo esc_attr($uid); ?> .acss-matrix__swatch.is-light .acss-matrix__value{
opacity: .9;
}
/* ----------------------------
Popover + theme switching
---------------------------- */
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-pop{
inline-size: var(--pop-w);
max-inline-size: min(34rem, calc(100vw - 2rem));
border-radius: calc(var(--radius) + 2px);
box-shadow: 0 12px 30px rgb(0 0 0 / .35);
backdrop-filter: blur(16px);
padding: 14px;
/* defaults = ACSS theme */
background: var(--body-bg-color, rgb(15 15 18 / .92));
color: var(--text-color, #fff);
border: 1px solid rgb(0 0 0 / .12);
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-pop::backdrop{
background: transparent;
}
/* Light theme */
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-pop[data-theme="light"]{
background: rgb(255 255 255 / .92);
color: rgb(10 10 10);
border: 1px solid rgb(0 0 0 / .14);
}
/* Dark theme */
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-pop[data-theme="dark"]{
background: rgb(10 10 10 / .92);
color: #fff;
border: 1px solid rgb(255 255 255 / .18);
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-head{
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
flex-wrap: wrap;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-title{
font-family: var(--mono);
font-size: 22px;
letter-spacing: .2px;
font-weight: 750;
margin: 0;
flex: 1 1 auto;
min-width: 12ch;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-close{
margin-left: auto;
inline-size: 42px;
block-size: 42px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
background: color-mix(in srgb, currentColor 8%, transparent);
color: inherit;
display: inline-grid;
place-items: center;
cursor: pointer;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-close svg{
inline-size: 18px;
block-size: 18px;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-body{
display: grid;
gap: 10px;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-row{
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 14px;
border: 1px solid color-mix(in srgb, currentColor 14%, transparent);
background: color-mix(in srgb, currentColor 7%, transparent);
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-chip{
inline-size: 26px;
block-size: 26px;
border-radius: 8px;
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
background: transparent;
flex: 0 0 auto;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-code{
font-family: var(--mono);
font-size: 15px;
line-height: 1.2;
opacity: .95;
word-break: break-word;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-list{
display: grid;
gap: 10px;
}
/* Theme switcher (segmented control) */
#<?php echo esc_attr($uid); ?> .acss-matrix__sr-only{
position: absolute;
inline-size: 1px;
block-size: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__theme{
display: inline-flex;
align-items: center;
gap: 0;
border-radius: 999px;
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
background: color-mix(in srgb, currentColor 6%, transparent);
padding: 2px;
margin: 0;
flex: 0 0 auto;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__theme-input{
position: absolute;
opacity: 0;
pointer-events: none;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__theme-btn{
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px 10px;
border-radius: 999px;
font-weight: 750;
font-size: 12px;
letter-spacing: .02em;
cursor: pointer;
user-select: none;
color: inherit;
opacity: .85;
margin-bottom:0;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__theme-input:checked + .acss-matrix__theme-btn{
background: color-mix(in srgb, currentColor 14%, transparent);
opacity: 1;
}
#<?php echo esc_attr($uid); ?> .acss-matrix__theme-btn:focus-visible{
outline: 2px solid currentColor;
outline-offset: 2px;
}
/* Anchor positioning */
@supports (anchor-name: --a) and (position-anchor: --a){
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-pop{
position-anchor: var(--acss-anchor);
inset: auto;
inset-area: bottom;
translate: 0 10px;
position-try-fallbacks: flip-block, flip-inline;
}
}
@supports not ((anchor-name: --a) and (position-anchor: --a)){
#<?php echo esc_attr($uid); ?> .acss-matrix__alpha-pop{
position: fixed;
left: 50%;
top: 18vh;
transform: translateX(-50%);
}
}
@media (max-width: 1100px){
#<?php echo esc_attr($uid); ?> .acss-matrix__grid{
grid-auto-flow: row;
grid-auto-columns: unset;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
overflow-x: visible;
}
}
</style>
<script>
(() => {
const host = document.getElementById(<?php echo wp_json_encode($uid); ?>);
if (!host) return;
/* ---------- APCA-ish helpers ---------- */
const clamp01 = (v) => Math.min(1, Math.max(0, v));
const srgb8ToLin = (c8) => {
const c = c8 / 255;
return (c <= 0.04045) ? (c / 12.92) : Math.pow((c + 0.055) / 1.055, 2.4);
};
const yFromRGB = (r8, g8, b8) => {
const r = srgb8ToLin(r8), g = srgb8ToLin(g8), b = srgb8ToLin(b8);
return (0.2126 * r) + (0.7152 * g) + (0.0722 * b);
};
const apcaLc = (textRGB, bgRGB) => {
const Ytxt = yFromRGB(textRGB[0], textRGB[1], textRGB[2]);
const Ybg = yFromRGB(bgRGB[0], bgRGB[1], bgRGB[2]);
const txt = clamp01(Ytxt);
const bg = clamp01(Ybg);
const isDarkText = txt < bg;
const normBG = Math.pow(bg, 0.56);
const normTXT = Math.pow(txt, 0.57);
let lc = (normBG - normTXT) * 1.14 * 100;
if (!isDarkText) lc = -lc;
return lc;
};
const parseRgb = (cssColor) => {
const m = /rgba?\(\s*([0-9.]+)[,\s]+([0-9.]+)[,\s]+([0-9.]+)/i.exec(cssColor || '');
if (!m) return null;
const r = Math.round(parseFloat(m[1]));
const g = Math.round(parseFloat(m[2]));
const b = Math.round(parseFloat(m[3]));
if (![r,g,b].every(Number.isFinite)) return null;
return [r,g,b];
};
const parseL = (v) => {
const m = /oklch\(\s*([0-9.]+)/i.exec(v || '');
if (!m) return null;
const L = parseFloat(m[1]);
return Number.isFinite(L) ? L : null;
};
const getApcaMin = () => {
const raw = getComputedStyle(host).getPropertyValue('--apca-min').trim();
const n = parseFloat(raw);
return Number.isFinite(n) ? Math.abs(n) : 60;
};
const WHITE = [255,255,255];
const BLACK = [10,10,10];
const minLc = getApcaMin();
/* ---------- Clipboard helpers ---------- */
const copyText = async (text) => {
const t = String(text || '').trim();
if (!t) return false;
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(t);
return true;
}
} catch (e) {}
try {
const ta = document.createElement('textarea');
ta.value = t;
ta.setAttribute('readonly', '');
ta.style.position = 'fixed';
ta.style.left = '-9999px';
ta.style.top = '0';
document.body.appendChild(ta);
ta.select();
const ok = document.execCommand('copy');
document.body.removeChild(ta);
return !!ok;
} catch (e) {}
return false;
};
const pulseCopied = (sw) => {
if (!sw) return;
sw.classList.add('is-copied');
window.clearTimeout(sw.__acssCopiedTO);
sw.__acssCopiedTO = window.setTimeout(() => {
sw.classList.remove('is-copied');
}, 1200);
};
/* ---------- Popover theme switching ---------- */
const THEME_STORE_KEY = 'acss_matrix_pop_theme';
const validTheme = (t) => (t === 'acss' || t === 'light' || t === 'dark') ? t : 'acss';
const getStoredTheme = () => {
try { return validTheme(localStorage.getItem(THEME_STORE_KEY) || 'acss'); }
catch (e) { return 'acss'; }
};
const setStoredTheme = (t) => {
try { localStorage.setItem(THEME_STORE_KEY, t); } catch (e) {}
};
const setPopoverTheme = (pop, theme) => {
if (!pop) return;
const t = validTheme(theme);
pop.dataset.theme = t;
};
const syncPopoverRadios = (pop) => {
if (!pop) return;
const t = validTheme(pop.dataset.theme || 'acss');
const input = pop.querySelector(`.acss-matrix__theme-input[value="${CSS.escape(t)}"]`);
if (input) input.checked = true;
};
/* ---------- Popover content ---------- */
const buildTransparency = (sw) => {
const popId = sw.getAttribute('data-popover');
const pop = popId ? document.getElementById(popId) : null;
if (!pop) return;
const varName = (sw.getAttribute('data-var') || '').trim(); // e.g. --neutral
const cssVarRef = `var(${varName})`;
const baseRow = pop.querySelector('.acss-matrix__alpha-row--base');
const baseChip = baseRow?.querySelector('.acss-matrix__alpha-chip');
const baseCode = baseRow?.querySelector('.acss-matrix__alpha-code');
if (baseChip) baseChip.style.background = cssVarRef;
if (baseCode) baseCode.textContent = cssVarRef;
const list = pop.querySelector('.acss-matrix__alpha-list');
if (!list) return;
list.innerHTML = '';
const steps = [10,20,30,40,50,60,70,80,90];
steps.forEach(pct => {
const expr = `color-mix(in oklch, ${cssVarRef} ${pct}%, transparent)`;
const row = document.createElement('div');
row.className = 'acss-matrix__alpha-row';
row.setAttribute('role', 'listitem');
const chip = document.createElement('div');
chip.className = 'acss-matrix__alpha-chip';
chip.style.background = expr;
const code = document.createElement('div');
code.className = 'acss-matrix__alpha-code';
code.textContent = expr;
row.appendChild(chip);
row.appendChild(code);
list.appendChild(row);
});
const anchor = sw.getAttribute('data-anchor');
if (anchor) pop.style.setProperty('--acss-anchor', anchor);
};
/* ---------- Enhance swatches (badge + APCA) ---------- */
host.querySelectorAll('.acss-matrix__swatch').forEach(sw => {
const v = sw.getAttribute('data-value') || '';
const badge = sw.querySelector('.acss-matrix__badge');
const L = parseL(v);
if (L !== null) {
if (badge) badge.textContent = 'L ' + (Math.round(L * 1000) / 10).toFixed(1);
} else {
const vv = v.trim().toLowerCase();
if (vv === '#fff' || vv === '#ffffff' || vv === 'white') {
if (badge) badge.textContent = 'white';
} else if (vv === '#000' || vv === '#000000' || vv === 'black') {
if (badge) badge.textContent = 'black';
}
}
const bgCss = getComputedStyle(sw).backgroundColor;
const bgRGB = parseRgb(bgCss);
if (!bgRGB) {
if (L !== null && L >= 0.72) sw.classList.add('is-light');
buildTransparency(sw);
return;
}
const lcBlack = apcaLc(BLACK, bgRGB);
const lcWhite = apcaLc(WHITE, bgRGB);
const absBlack = Math.abs(lcBlack);
const absWhite = Math.abs(lcWhite);
const useBlack = absBlack >= absWhite;
const bestLc = useBlack ? lcBlack : lcWhite;
const bestAbs = Math.abs(bestLc);
sw.classList.toggle('is-light', useBlack);
if (bestAbs < minLc) {
sw.classList.add('needs-scrim');
const deficit = (minLc - bestAbs) / minLc;
const alpha = Math.max(0.10, Math.min(0.38, 0.12 + deficit * 0.30));
if (useBlack) sw.style.setProperty('--swatch-scrim', `rgba(255,255,255,${alpha})`);
else sw.style.setProperty('--swatch-scrim', `rgba(0,0,0,${alpha})`);
} else {
sw.classList.remove('needs-scrim');
sw.style.removeProperty('--swatch-scrim');
}
buildTransparency(sw);
});
/* ---------- Copy (delegated) ---------- */
host.addEventListener('click', async (e) => {
const valueBtn = e.target.closest('.acss-matrix__value');
if (!valueBtn || !host.contains(valueBtn)) return;
const sw = valueBtn.closest('.acss-matrix__swatch');
if (!sw) return;
const raw = (sw.getAttribute('data-value') || '').trim();
if (!raw) return;
const m = /(oklch\([^)]+\))/i.exec(raw);
const toCopy = (m && m[1]) ? m[1].trim() : raw;
const ok = await copyText(toCopy);
if (ok) pulseCopied(sw);
});
/* ---------- Theme switching (delegated, persists) ---------- */
const globalTheme = getStoredTheme();
// Set initial theme on all popovers + radios
host.querySelectorAll('.acss-matrix__alpha-pop').forEach(pop => {
setPopoverTheme(pop, globalTheme);
syncPopoverRadios(pop);
});
host.addEventListener('change', (e) => {
const input = e.target;
if (!input || !input.classList || !input.classList.contains('acss-matrix__theme-input')) return;
const pop = input.closest('.acss-matrix__alpha-pop');
if (!pop) return;
const t = validTheme(input.value);
setPopoverTheme(pop, t);
setStoredTheme(t);
// Apply to *all* popovers so the user's preference carries over
host.querySelectorAll('.acss-matrix__alpha-pop').forEach(p => {
setPopoverTheme(p, t);
syncPopoverRadios(p);
});
});
/* ---------- Popover open: rebuild + sync theme ---------- */
document.addEventListener('toggle', (e) => {
const pop = e.target;
if (!pop || !pop.classList || !pop.classList.contains('acss-matrix__alpha-pop')) return;
if (!host.contains(pop)) return;
if (pop.matches(':popover-open')) {
// Ensure current stored theme is applied (in case it changed elsewhere)
const t = getStoredTheme();
setPopoverTheme(pop, t);
syncPopoverRadios(pop);
const popId = pop.id;
const sw = host.querySelector(`.acss-matrix__swatch[data-popover="${CSS.escape(popId)}"]`);
if (sw) buildTransparency(sw);
}
}, true);
})();
</script>
<?php
return ob_get_clean();
});This sites main colors
Primary
Copied
-primary-ultra-light
Copied
-primary-light
Copied
-primary-semi-light
Copied
-primary
Copied
-primary-hover
Copied
-primary-semi-dark
Copied
-primary-dark
Copied
-primary-ultra-dark
Base
Copied
-base-ultra-light
Copied
-base-light
Copied
-base-semi-light
Copied
-base
Copied
-base-hover
Copied
-base-semi-dark
Copied
-base-dark
Copied
-base-ultra-dark







