From a4da3026d5a75dbc6dfef3ebafd64fdd828d7b13 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 11:28:50 +0000 Subject: [PATCH 1/7] docs(user-manual): add Polish color-system guide with section-by-section recipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds user-manual/system-kolorow.md — a practical, task-oriented walkthrough of the color system built around a real landing-page layout (alternating light/dark bands with a single brand accent). Covers the three-layer mental model, the .sf-surface--* vs data-theme vs --sf-color-text--on-* decision, the primary/action split, ramps vs alpha variants, status tokens, and a section-by-section recipe. Also records three framework nits (status -subtle alpha 0.12 vs 0.10 for info/danger, the subtle-naming overload, and the old-engine .sf-surface degradation). Passes check:doc-refs (all --sf-*/.sf-* references live). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- user-manual/system-kolorow.md | 487 ++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 user-manual/system-kolorow.md diff --git a/user-manual/system-kolorow.md b/user-manual/system-kolorow.md new file mode 100644 index 00000000..6dbe43bc --- /dev/null +++ b/user-manual/system-kolorow.md @@ -0,0 +1,487 @@ +# System kolorów SLASHED — pełna instrukcja użytkownika + +Ten przewodnik tłumaczy **kiedy, na jakim elemencie i jakiego narzędzia użyć**, +żeby pokolorować stronę na SLASHED — na konkretnym przykładzie landing page'a +(typu „WordPress sites that load faster, convert better”). Jeśli gubisz się w +tym, czym różni się `surface` od `color-on-*` od `data-theme` — to jest +dokument dla Ciebie. + +> Źródło prawdy: `core/tokens.css` i `core/themes.css`. Jeśli cokolwiek tutaj +> kłóci się z kodem — wygrywa kod. Krótszy słownik tokenów: [`colors.md`](colors.md). + +--- + +## 1. Model mentalny — trzy warstwy + +Cały system to **trzy warstwy**. Zawsze pracujesz na najwyższej, do której się da +zejść — im wyżej, tym mniej decyzji podejmujesz ręcznie. + +``` +WARSTWA 3 Powierzchnie .sf-surface--primary, .sf-btn--action, .sf-card + (klasy) → „pomaluj cały blok, tekst dobierz sam” + ▲ +WARSTWA 2 Tokeny semantyczne --sf-color-text, --sf-color-bg, --sf-color-border, + (role) --sf-color-link, --sf-color-heading + ▲ → „to jest tekst / tło / obramowanie” (nie kolor!) + ▲ +WARSTWA 1 Kolory źródłowe --sf-color-primary, --sf-color-action, … + (marka) → ustawiasz RAZ przy brandingu, potem nie ruszasz +``` + +Reguła nadrzędna: **im wyżej, tym lepiej.** + +1. Da się użyć gotowej **powierzchni/komponentu**? Użyj (`.sf-surface--*`, `.sf-btn`, `.sf-card`). +2. Nie da się? Sięgnij po **token semantyczny** (`--sf-color-text`, `--sf-color-bg`…). +3. Prawie nigdy nie odwołuj się bezpośrednio do **koloru źródłowego** (`--sf-color-primary`) + w treści strony — to knob do brandingu, nie do malowania akapitów. + +Dlaczego to działa: warstwa 2 i 3 **same przełączają się** w tryb ciemny, na hover, +pod `prefers-contrast` itd. Jeśli wpiszesz gdzieś `color: #1a1a1a`, tracisz to +wszystko i musisz pisać własne reguły `[data-theme="dark"]`. Nie rób tego. + +--- + +## 2. Trzy sposoby nakładania koloru — drzewko decyzyjne + +To najważniejsza tabela w całym dokumencie. Zanim pomalujesz cokolwiek, zadaj +sobie pytanie: **czym jest ten element?** + +| Chcę… | Użyj | Dlaczego | +|---|---|---| +| pojedynczy **kolorowy kafelek/płytę** (jeden brandowy blok, karta CTA), a tekst w środku ma sam się skontrastować | klasa powierzchni `.sf-surface--primary` (`--action`, `--inverse`, `--success`…) | ustawia tło + auto-dobiera kolor tekstu, linków, obramowań, focus-ringu | +| **całą sekcję w innym trybie** (jasna strona, ale ciemny pas z kartami, formularzem, przyciskami) | atrybut `data-theme="dark"` na `
` | przełącza *cały* zestaw tokenów trybu — tła, tekst, karty, inputy w środku adaptują się jak w prawdziwym dark mode | +| **treść na neutralnym tle strony** (akapit, nagłówek, obramowanie, link) | token semantyczny `--sf-color-text`, `--sf-color-heading`, `--sf-color-border`, `--sf-color-link` | to są *role*, nie kolory — same śledzą motyw | +| **przycisk / link / akcent interaktywny** | `.sf-btn` (+ wariant) albo `--sf-color-action` | interaktywność ma swój osobny kolor (patrz §3) | +| **tekst leżący wprost na jednolitym kolorze marki** (napis na pomarańczowym) | `--sf-color-text--on-primary` (`--on-action`, `--on-danger`…) | auto-dobiera czerń albo biel pod ten konkretny kolor | +| **delikatny barwny wash** (tło alertu, podświetlony wiersz) | wariant `-subtle` / `-tint` albo rampa numeryczna (`-100`, `-200`) | patrz §6 | + +### Kluczowa różnica: `.sf-surface--*` vs `data-theme` vs `--sf-color-*-on` + +To jest dokładnie to, co Cię myli — rozbijmy na czynniki pierwsze: + +- **`.sf-surface--primary`** = *„weź kolor marki i zrób z niego jednolitą płytę”.* + Tło = `--sf-color-primary`, a framework policzy, czy tekst ma być czarny czy + biały (`--sf-color-text--on-primary`) i przepisze to na WSZYSTKIE tokeny + potomków (`--sf-color-text`, `--sf-color-heading`, `--sf-color-link`, + `--sf-color-border`, focus-ring, karetka). Efekt: cokolwiek włożysz do środka, + będzie czytelne. Używasz do **jednej kolorowej rzeczy**: baner CTA, wyróżniona + karta cennika, badge. + +- **`data-theme="dark"`** (lub `="light"`) = *„ta sekcja żyje w innym trybie”.* + Nie maluje jednym kolorem marki — przełącza cały motyw: `--sf-color-bg` robi się + ciemne, `--sf-color-text` jasne, a karty (`.sf-card`), inputy i przyciski w + środku **adaptują się same**, tak jak zrobiłyby to w dark mode całej strony. + Używasz do **całego pasa/sekcji** z wieloma elementami (ciemna sekcja z trzema + kartami cennika i przyciskami). + +- **`--sf-color-text--on-*`** = *„sam kolor tekstu na znanym tle marki”.* + Nie tło, nie płyta — tylko wartość koloru. Sięgasz po nią, gdy malujesz coś + ręcznie (np. własny badge) i potrzebujesz czcionki, która skontrastuje się z + konkretnym `--sf-color-primary`. + +Zapamiętaj skrótowo: +**jeden kolorowy klocek → `.sf-surface--*`; +cały ciemny pas → `data-theme`; +sam kolor napisu na kolorze → `--sf-color-text--on-*`.** + +--- + +## 3. `primary` vs `action` — rozróżnienie, które psuje najwięcej stron + +Framework rozdziela **kolor marki** od **koloru interakcji** na dwa osobne knoby. +Na naszym przykładzie oba są pomarańczowe — ale to nie znaczy, że to jedno i to samo. + +| Token | Rola | Na przykładowej stronie | +|---|---|---| +| `--sf-color-primary` | tożsamość marki | akcent w nagłówku hero („**actually** win business”), wyróżniona płyta, znaczniki dekoracyjne | +| `--sf-color-action` | **domyślny kolor interaktywny** | każdy przycisk CTA, link, focus-ring, kontrolka formularza | + +**Najczęstszy błąd:** malowanie przycisków przez `--sf-color-primary`. Przyciski +i linki domyślnie biorą `--sf-color-action`. Trzymaj je rozdzielnie — dzięki temu +możesz zmienić kolor wszystkich CTA bez ruszania koloru logo i odwrotnie. + +Do stanów interakcji nie kombinuj z wartościami — są gotowe aliasy: + +```css +--sf-color-action /* stan spoczynkowy */ +--sf-color-action--hover /* = -600, hover */ +--sf-color-action--active /* = -800, wciśnięcie */ +``` + +(ten sam wzorzec dla `primary`, `secondary`, `tertiary`, `neutral`). + +--- + +## 4. Sekcja po sekcji — jak zbudować przykładową stronę + +Landing z załącznika to naprzemienne pasy **jasny → ciemny → jasny → ciemny**, +z jednym pomarańczowym akcentem. Poniżej każdy pas rozpisany na właściwe narzędzia. + +### 4.1. Hero (jasny pas) — „WordPress sites that load faster…” + +Tło strony jest domyślne (nie ustawiasz go — to `--sf-color-bg`). Malujesz tylko treść. + +```html +
+
+

+ WordPress sites that load faster, convert better, and + actually win business +

+

Podtytuł idzie kolorem drugorzędnym.

+ Book a call +
+
+``` + +Co się dzieje z kolorami: +- Nagłówek `

` **nie dostaje żadnej klasy koloru** — bierze `--sf-color-heading` + automatycznie z reguł bazowych. Nie pisz `color:` ręcznie. +- Pomarańczowy akcent w nagłówku: `.sf-text-gradient` (gradient marki na tekście) + albo, jeśli chcesz płaski kolor, ``. +- Podtytuł „ściszony”: klasa rozmiaru + token `--sf-color-text--secondary` + (np. własna klasa: `.lead { color: var(--sf-color-text--secondary); }`). +- Przycisk CTA: `.sf-btn .sf-btn--action`. Tło, kolor napisu (`--on-action`), + hover i focus-ring — wszystko gotowe. +- Pływająca karta/widget po prawej: `.sf-card` — dostaje `--sf-color-surface` jako + tło i `--sf-color-border` jako obramowanie, bez dotykania kolorów. + +### 4.2. Ciemny pas — „Three ways to work together” (trzy karty cennika) + +To jest **cała ciemna sekcja z wieloma elementami** → `data-theme="dark"`, nie +`.sf-surface`. + +```html +
+
+

Three ways to work together

+
+
+
+
+
+
+
+``` + +Dlaczego `data-theme="dark"`, a nie `.sf-surface--inverse`: +- `data-theme="dark"` przełącza **cały motyw sekcji** — `--sf-color-bg` robi się + ciemne, a karty `.sf-card` w środku **same** biorą ciemne `--sf-color-surface`, + jasny tekst, właściwe obramowania. Dokładnie to widać na makiecie. +- `.sf-surface--inverse` dałoby jedną jednolitą ciemną płytę, ale karty w środku + nie „wskoczyłyby” w tryb ciemny tak naturalnie — inverse jest do pojedynczego + klocka, nie do pasa z zagnieżdżonymi komponentami. +- `.sf-full-bleed` rozciąga tło na całą szerokość ekranu, a `.sf-container` + trzyma treść w kolumnie. + +Wyróżniona (środkowa, pomarańczowa) karta — to **jeden kolorowy klocek**, więc tu +już wchodzi powierzchnia: + +```html +
+``` + +`.sf-surface--primary` na karcie = pomarańczowe tło + auto-kontrast napisów w środku. + +### 4.3. Jasny pas — tabela porównawcza „Agency results. Freelancer access.” + +Wracamy na neutralne tło. Wszystko na tokenach semantycznych: + +```css +.compare { border: var(--sf-border-width-1) solid var(--sf-color-border); } +.compare thead { background: var(--sf-color-inset); } /* delikatnie wciśnięty nagłówek */ +.compare td, .compare th { border-block: var(--sf-border-width-1) solid var(--sf-color-border--subtle); } +.compare .highlight { color: var(--sf-color-action); } /* wyróżniona kolumna */ +``` + +- Linie tabeli: `--sf-color-border` (mocniejsze) i `--sf-color-border--subtle` (cieńsze). +- Tło paska nagłówka: `--sf-color-inset` (płyta lekko cofnięta względem `--sf-color-bg`). +- Nigdzie nie podajesz konkretnego szarego — te tokeny same się dostroją w dark mode. + +### 4.4. Ciemny pas — opinie „4.9 across 50+ projects” + +Znów `data-theme="dark"` na sekcji + `.sf-card` na cytatach. Gwiazdki oceny mogą +użyć `--sf-color-warning` (klasyczny „złoty” akcent ocen), logotypy klientów — +`--sf-color-text--secondary`, żeby były obecne, ale nie krzyczały. + +### 4.5. Jasny pas — proces „A 5-phase process” (stepper) + +Aktywny krok = interakcja/stan → `--sf-color-action` i stan `.sf-is-active`: + +```css +.step { color: var(--sf-color-text--secondary); } /* krok nieaktywny */ +.step.sf-is-active { color: var(--sf-color-action); } /* krok bieżący */ +.step__dot { background: var(--sf-color-border); } +.step.sf-is-active .step__dot { background: var(--sf-color-action); } +``` + +`.sf-is-*` to klasy stanu (patrz [`docs/states.md`](../docs/states.md)) — sygnalizują +stan JS-em, a kolory zostają w tokenach. + +### 4.6. Ciemny pas CTA — „Ready to build something that actually performs” + +`data-theme="dark"` + przycisk `.sf-btn--action`. Ponieważ to sekcja w trybie +ciemnym, `--sf-color-action` automatycznie użyje swojego wariantu dla ciemnego tła — +nic nie robisz ręcznie. + +### 4.7. Jasny pas — cennik „Your site doesn't stop working after launch day” + +Trzy karty, środkowa wyróżniona na pomarańczowo (dokładnie wzorzec z §4.2): + +```html +
+
Core
+
Commerce
+
Custom
+
+``` + +Alternatywa dla wyróżnienia „ramką zamiast wypełnienia” — użyj rampy albo obramowania marki: + +```css +.plan--featured { + border-color: var(--sf-color-primary); + background: var(--sf-color-primary-superlight); /* ledwie widoczny ciepły wash */ +} +``` + +Kiedy `.sf-surface--primary` (pełny pomarańcz), a kiedy `-superlight` (delikatny wash)? +Pełna płyta = maksymalne wyróżnienie; wash = subtelny akcent bez krzyku. Wybór estetyczny. + +### 4.8. Ciemny pas — „I don't take on every project” (dwie kolumny z listami) + +`data-theme="dark"` + znaczniki list w kolorze marki: + +```html +
+``` + +Gdybyś chciał listę „robię / nie robię” w barwach statusów: `--sf-color-success` +i `--sf-color-danger` na ikonkach. + +### 4.9. Jasny pas — FAQ „Questions I get asked a lot” + +Akordeon = wiersze rozdzielone `--sf-color-border`, pytanie w `--sf-color-heading`, +odpowiedź w `--sf-color-text`. Ikona +/- w `--sf-color-action`. + +### 4.10. Ciemny pas — formularz kontaktowy „Let's talk about your project” + +`data-theme="dark"` na sekcji i… nic więcej przy kolorach inputów. Kontrolki z +`optional/forms.css` **same** wezmą ciemne tło pola, jasny tekst, obramowanie i +focus-ring w kolorze `--sf-color-action`. To jest cała nagroda za trzymanie się +tokenów semantycznych — formularz „po prostu działa” w ciemnym pasie. + +> Uwaga na `color-scheme`: `data-theme="dark"` ustawia je za Ciebie, więc natywne +> elementy (scrollbary, autouzupełnianie, kalendarz w ``) też będą +> ciemne. Jeśli kiedyś zrobisz własny tryb bez `data-theme`, pamiętaj ustawić +> `color-scheme` ręcznie. + +### 4.11. Stopka (ciemna) + +Najciemniejszy pas. Dwie opcje: +- `data-theme="dark"` — jeśli stopka ma linki, inputy newslettera itp. (adaptują się). +- `.sf-surface--inverse` albo `.sf-surface--secondary` — jeśli to zwarta, jednolita + płyta bez interaktywnych komponentów wymagających pełnego motywu. + +--- + +## 5. Tokeny semantyczne — pełna ściąga „na co którego” + +To są role, których używasz na neutralnym tle strony (poza kolorowymi płytami): + +| Token | Na czym | +|---|---| +| `--sf-color-text` | tekst akapitów, treść | +| `--sf-color-text--secondary` | podtytuły, metadane, „ściszony” tekst | +| `--sf-color-heading` | nagłówki (h1–h6 biorą go automatycznie) | +| `--sf-color-link` | linki (śledzi hue `action`, ale z bezpiecznym kontrastem) | +| `--sf-color-border` | obramowania, dividery | +| `--sf-color-border--subtle` / `--strong` | cieńsze / mocniejsze linie | +| `--sf-color-bg` | tło strony (rzadko ustawiasz — jest domyślne) | +| `--sf-color-surface` | tło kart/kontenerów (`.sf-card` używa go sam) | +| `--sf-color-inset` | płyta cofnięta (nagłówek tabeli, pole kodu) | +| `--sf-color-raised` | płyta wyniesiona (uniesiona karta, popover) | +| `--sf-color-inverse` | odwrócone tło (ciemne w jasnym trybie) | + +Wszystkie **same przełączają się** w dark mode i pod `data-theme`. Nigdy nie +podajesz pod nie konkretnego hexa. + +--- + +## 6. Rampy, alfa i statusy — kiedy które + +### Rampy numeryczne 50 → 950 (marka) + +`primary`, `secondary`, `tertiary`, `action`, `neutral`, `base` mają drabinę +`-50` (ledwie widoczny tint) → `-500` (sam kolor) → `-950` (prawie czarny). +Aliasy do tych, po które naprawdę sięgasz: + +``` +--sf-color-primary-superlight (= -50) subtelne tło / wash +--sf-color-primary-xlight (= -200) tło pigułki/badge +--sf-color-primary-lighter (= -400) obramowania na kolorowym komponencie +--sf-color-primary-darker (= -600) hover, tekst-na-tincie +--sf-color-primary-xdark (= -800) stan wciśnięty +``` + +**Ważne:** rampa numeryczna jest policzona względem **konkretnego** tła +(`--sf-color-surface`). Używaj jej tylko, gdy znasz tło pod spodem. + +### Warianty alfa (przezroczyste) + +Gdy element leży na **nieznanym** tle (badge, który może trafić na jasną albo +ciemną kartę) — użyj wariantów alfa zamiast rampy numerycznej: + +| Token | Krycie | Alias | +|---|---|---| +| `-a5` | 5% | `-tint` | +| `-a10` | 10% | `-subtle` | +| `-a30` | 30% | `-muted` | +| `-a50` | 50% | — | + +Alfa zostaje poprawna na każdym tle; rampa numeryczna „rozjedzie się”, gdy tło +się zmieni. + +### Statusy: `success`, `warning`, `info`, `danger` + +Nie mają pełnej rampy — mają zestaw celowy: + +| Token | Na czym | +|---|---| +| `--sf-color-{status}` | ikony, drobne akcenty, obramowania | +| `--sf-color-{status}-strong` | jednolite tło z większym kontrastem, hover na przycisku statusu | +| `--sf-color-{status}-subtle` | tinted tło kontenera (np. pudełko alertu) | +| `--sf-color-{status}-muted` (~30%) | mocniejszy wash, np. tło badge | +| `--sf-color-{status}-tint` (~5%) | najlżejszy wash | + +Przykład — alert błędu: + +```css +.alert--danger { + background: var(--sf-color-danger-subtle); + border-color: var(--sf-color-danger); + color: var(--sf-color-danger-strong); +} +``` + +--- + +## 7. Tekst wprost na kolorze — `--sf-color-text--on-*` + +Ilekroć napis leży bezpośrednio na jednolitym kolorze marki/statusu, użyj +pasującego `--sf-color-text--on-*` zamiast wpisywać czerń/biel. Framework +sam wybierze wariant dający lepszy kontrast pod ten konkretny kolor: + +```css +.badge--primary { + background: var(--sf-color-primary); + color: var(--sf-color-text--on-primary); +} +``` + +Dostępne: `--on-primary`, `--on-secondary`, `--on-tertiary`, `--on-action`, +`--on-neutral`, `--on-success`, `--on-warning`, `--on-info`, `--on-danger`, +`--on-inverse`. + +**Uwaga na „pas niejednoznaczny” (L ≈ 0.52–0.67).** Jeśli Twój kolor marki +wpada w środek jasności, binarny wybór czerń/biel może nie wyrobić 4.5:1. +Wtedy albo przesuń próg dla tej powierzchni: + +```css +.sf-surface--primary { --sf-contrast-threshold: 0.55; } +``` + +…albo przypnij kolor tekstu ręcznie: + +```css +.sf-surface--primary { --sf-color-text--on-primary: oklch(0.15 0 0); } +``` + +Te nadpisania trzymaj w warstwie `slashed.overrides`, żeby przetrwały aktualizacje. + +--- + +## 8. Najczęstsze błędy (i jak je naprawić) + +1. **Malowanie przycisku przez `--sf-color-primary`.** → Przyciski to `--sf-color-action` + (albo `.sf-btn--action`). `primary` to marka, nie interakcja (§3). +2. **Wpisywanie `#hex` / `rgb()` w treści strony.** → Tracisz dark mode i hover. + Zejdź na tokeny semantyczne (§5). +3. **Pisanie własnych reguł `[data-theme="dark"] { color: … }`.** → Niepotrzebne. + Tokeny semantyczne robią to za Ciebie. +4. **Użycie `.sf-surface--inverse` na całym ciemnym pasie z kartami i formularzem.** + → To zadanie dla `data-theme="dark"`; `.sf-surface--*` jest do pojedynczego klocka (§2). +5. **Rampa numeryczna (`-200`) na elemencie pływającym nad nieznanym tłem.** + → Użyj wariantu alfa (`-subtle` / `-tint`), bo rampa jest liczona pod konkretne tło (§6). +6. **Ręczne dobieranie czerni/bieli na kolorowym tle.** → `--sf-color-text--on-*` (§7). + +--- + +## 9. Znalezione nieścisłości we frameworku + +Podczas pisania tej instrukcji przejrzałem źródła. Poniżej to, co warto poprawić — +nic krytycznego, ale realne: + +### 9.1. Niespójna alfa w `-subtle` dla statusów *(realna nieścisłość)* + +W `core/tokens.css` (blok „Status triplets”) warianty `-subtle` nie mają jednej alfy: + +```css +--sf-color-success-subtle: … / 0.12; +--sf-color-warning-subtle: … / 0.12; +--sf-color-info-subtle: … / 0.1; /* ← 10%, nie 12% */ +--sf-color-danger-subtle: … / 0.1; /* ← 10%, nie 12% */ +``` + +`success` i `warning` mają 12%, a `info` i `danger` 10% — mimo że siedzą pod tym +samym komentarzem „triplet” i pełnią tę samą rolę (tło alertu). Dokumentacja +(`user-manual/colors.md`) opisuje je zbiorczo jako „~12% alpha”. Efekt: pudełko +alertu błędu (`danger`) będzie odrobinę bledsze niż sukcesu przy tej samej treści. +**Sugestia:** ujednolicić wszystkie cztery do `0.12` (albo świadomie udokumentować +różnicę). `-muted` (0.3) i `-tint` (0.05) są już spójne we wszystkich czterech. + +### 9.2. Kolizja nazwy `-subtle` między marką a statusami *(pułapka, nie błąd)* + +W rampach marki alias `-subtle` = `-a10` = **10%** krycia. W statusach `-subtle` +(dla success/warning) = **12%**. Ta sama końcówka nazwy, inna nieprzezroczystość. +Nie jest to błąd, ale łatwo o pomyłkę, gdy myślisz „subtle to zawsze 10%”. Warte +zdania w dokumentacji. + +### 9.3. Degradacja `.sf-surface--*` na starych silnikach *(świadoma, warto wiedzieć)* + +Auto-kontrast wnętrza powierzchni (przepisanie `--sf-color-heading`, +`--sf-color-link`, obramowań itd. na kolor kontrastowy) siedzi w bloku +`@supports (color: oklch(from red l c h))` w `core/macros.css`. Reguła bazowa +poza tym blokiem ustawia tylko `color` na samej płycie (przez `--sf-color-text--on-*`), +ale **nie** przemapowuje tokenów potomków. Na silnikach bez relatywnego `oklch` +(Chrome < 119, Safari < 16.4, Firefox < 128) nagłówek lub link *wewnątrz* +`.sf-surface--primary` może wziąć ciemne tokeny strony i słabo kontrastować z +kolorowym tłem. To celowa, udokumentowana degradacja — ale jeśli wspierasz stare +przeglądarki i wkładasz nagłówki/linki do kolorowych płyt, przetestuj to albo +przypnij kolory jawnie w `slashed.overrides`. + +--- + +## 10. Ściąga „potrzebuję…” + +| Potrzebuję… | Sięgam po | +|---|---| +| przycisk / link / focus-ring | `.sf-btn--action` lub `--sf-color-action` (+ `--hover`) | +| kolorowy hero/marketingowy blok | `--sf-color-primary` / `.sf-text-gradient` | +| cały ciemny pas z kartami i formularzem | `data-theme="dark"` na `
` | +| pojedynczy kolorowy klocek (wyróżniona karta, baner) | `.sf-surface--primary` (`--action`, `--inverse`…) | +| tekst, nagłówki, obramowania na tle strony | `--sf-color-text`, `--sf-color-heading`, `--sf-color-border` | +| tła kart/paneli | `--sf-color-surface`, `--sf-color-inset`, `--sf-color-raised` | +| feedback sukces/ostrzeżenie/info/błąd | token statusu (`-subtle` tło, `-strong` hover) | +| tekst wprost na jednolitym kolorze | `--sf-color-text--on-*` | +| tint marki nad ZNANYM tłem | rampa numeryczna (`-100`…`-400` / `-superlight`…) | +| tint marki nad NIEZNANYM tłem | wariant alfa (`-tint` / `-subtle` / `-muted`) | + +--- + +## Zobacz też + +- [`colors.md`](colors.md) — zwięzły słownik 10 kolorów źródłowych i tokenów +- [`../docs/theming.md`](../docs/theming.md) — rebranding w 6 tokenach + silnik fluid +- [`../docs/tokens.md`](../docs/tokens.md) — pełny wykaz tokenów +- [`../docs/states.md`](../docs/states.md) — klasy stanu `.sf-is-*` From 09652d3232eb0c2994455a2ca9e5057cd65a5dbc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 15:32:08 +0000 Subject: [PATCH 2/7] fix(tokens): make brand colour ramps monotonic for any source colour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The numeric brand ramps (--sf-color-{primary,secondary,tertiary,action, neutral}-50…950) previously generated each step with color-mix() toward the theme's --sf-color-surface (tints) / --sf-color-text (shades). When a chosen source colour fell outside the lightness band between those two anchors — a brand darker than the text colour, or a project that lightened --sf-color- neutral — the shade half inverted: steps 600–950 came out lighter than 500 and the ramp folded into a "U" (50 ≈ 950). Generate each step in OKLCH instead by pulling the family colour's own lightness a fixed fraction toward an ABSOLUTE target (--sf-palette-tint-l / --sf-palette-shade-l), clamped with max()/min() so a tint can never end darker than the base nor a shade lighter. The ladder is now monotonic light→dark for any source colour and any anchor configuration; chroma is tapered toward the extremes. Output is visually unchanged for default-palette colours (already in-band); only out-of-band / moved-anchor cases are corrected. base is untouched (already absolute-lightness). Breaking: removed the --sf-palette-mix-50…950 knobs; replaced with two lightness anchors --sf-palette-tint-l (0.97) and --sf-palette-shade-l (0.1). - core/tokens.css: new ramp formulas + anchor knobs (base/alpha/status unchanged) - tests/ramp-monotonic.spec.js: sweep the lightness axis for all 5 families, assert the ramp never folds and no step is transparent - token surface: snapshot, annotations, token-tiers, regenerated docs/registry - demo/index.html: refresh coverage inventory + per-token default strings - docs/llm-guide.md, user-manual/{colors,system-kolorow}.md: document the model - configurator/domain-patterns.json: match "palette" so the new knobs categorise - CHANGELOG: Bug Fixes + Breaking Changes entries Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- CHANGELOG.md | 6 +- badges/badge-optimal.json | 2 +- .../src/data/api-index.generated.json | 296 ++++----------- configurator/src/data/domain-patterns.json | 2 +- .../src/data/token-registry.generated.json | 40 ++- core/tokens.css | 130 +++---- demo/index.html | 114 +++--- dist/css-custom-data.json | 148 +++----- docs/api-index.json | 336 ++++-------------- docs/api-index.md | 120 +++---- docs/llm-guide.md | 32 +- docs/registry.json | 14 +- docs/token-annotations.json | 12 +- docs/token-index.json | 178 +++------- docs/token-index.md | 130 +++---- docs/tokens.md | 116 +++--- scripts/token-tiers.js | 9 +- tests/ramp-monotonic.spec.js | 101 ++++++ tests/token-api.snapshot.json | 12 +- token-registry.json | 40 ++- user-manual/colors.md | 14 +- user-manual/system-kolorow.md | 18 +- 22 files changed, 738 insertions(+), 1132 deletions(-) create mode 100644 tests/ramp-monotonic.spec.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 39aec0c8..84b815b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## Unreleased ### Bug Fixes -- **layout:** `@container` breakpoints for `.sf-grid-cols-*`, `.sf-bento` and `.sf-alternate` now use `rem` instead of `em`. Inside a container query an `em` resolves against the query container's own font-size, which under the default fluid type scale is inherited from `body` (a `clamp()` over `100vw`, ~16–20px) — so the same fixed-width container rendered a different column count depending on the *viewport*: an 800px container showed `.sf-grid-cols-3` as 3 columns at a 500px viewport but 1 column at 1200px+. `rem` resolves against the fixed root (`html` stays 16px; fluid type is applied to `body`), restoring the documented "responds to its own container width, not the viewport" contract. Thresholds are unchanged numerically (30rem = 480px, 48rem = 768px) and still honour user zoom / root-font-size. Also corrects `docs/architecture.md`, which wrongly listed `.sf-grid` / `.sf-sidebar` as `@container` primitives (both are intrinsic and carry no container query). +- **tokens:** the numeric brand ramps (`--sf-color-{primary,secondary,tertiary,action,neutral}-50…950`) no longer fold into a "U". The previous model generated each step with `color-mix()` toward the theme's `--sf-color-surface` (tints) / `--sf-color-text` (shades) — so when a chosen source colour fell outside the band between those two anchors (e.g. a brand darker than the text colour, or a project that lightened `--sf-color-neutral`), the shade half inverted and climbed back up: steps 600–950 came out *lighter* than 500, and 50 ≈ 950. The ramp is now generated in OKLCH by pulling the family colour's own lightness a fixed fraction toward an **absolute** target — `--sf-palette-tint-l` (tints) / `--sf-palette-shade-l` (shades) — clamped with `max()`/`min()` so a tint can never end darker than the base nor a shade lighter. The ladder is therefore monotonic light→dark for **any** source colour and any anchor configuration. Chroma is tapered toward the extremes to avoid oversaturation. For default-palette colours (which already sat inside the safe band) the output is visually unchanged; only out-of-band / moved-anchor cases are corrected. `base` is unchanged (it already used absolute lightness steps). New parametric test `tests/ramp-monotonic.spec.js` sweeps the lightness axis for all five families and asserts the ramp never folds and no step is transparent. +- **layout:** `@container` breakpoints for `.sf-grid-cols-*`, `.sf-bento` and `.sf-alternate` now use `rem` instead of `em`. + +### Breaking Changes +- **tokens:** removed the `--sf-palette-mix-50…950` ramp-shape knobs (color-mix percentages of the old model) and replaced them with two lightness-anchor knobs — `--sf-palette-tint-l` (default `0.97`) and `--sf-palette-shade-l` (default `0.1`) — which set how light the lightest / how dark the darkest generated palette step may reach. Per-step pull fraction and chroma taper are now baked into each family. If you overrode `--sf-palette-mix-*` to reshape the ramp, retune via the two new anchors instead (or override individual `--sf-color-{family}-{step}` resolved tokens). Inside a container query an `em` resolves against the query container's own font-size, which under the default fluid type scale is inherited from `body` (a `clamp()` over `100vw`, ~16–20px) — so the same fixed-width container rendered a different column count depending on the *viewport*: an 800px container showed `.sf-grid-cols-3` as 3 columns at a 500px viewport but 1 column at 1200px+. `rem` resolves against the fixed root (`html` stays 16px; fluid type is applied to `body`), restoring the documented "responds to its own container width, not the viewport" contract. Thresholds are unchanged numerically (30rem = 480px, 48rem = 768px) and still honour user zoom / root-font-size. Also corrects `docs/architecture.md`, which wrongly listed `.sf-grid` / `.sf-sidebar` as `@container` primitives (both are intrinsic and carry no container query). ## [0.7.18] - 2026-07-16 diff --git a/badges/badge-optimal.json b/badges/badge-optimal.json index 46b854cc..31ef54a3 100644 --- a/badges/badge-optimal.json +++ b/badges/badge-optimal.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "label": "optimal", - "message": "19.5 kB gzip", + "message": "19.6 kB gzip", "color": "brightgreen", "namedLogo": "css3" } diff --git a/configurator/src/data/api-index.generated.json b/configurator/src/data/api-index.generated.json index 22ada5fb..b8584b98 100644 --- a/configurator/src/data/api-index.generated.json +++ b/configurator/src/data/api-index.generated.json @@ -2,21 +2,21 @@ "_sync": { "generatedBy": "configurator/scripts/sync-api.mjs", "source": "docs/api-index.json", - "tokensHash": "5a5ec9f40624", + "tokensHash": "5c5b69ba4fa3", "bundles": [ "full", "optimal" ], "counts": { - "tokens": 754, + "tokens": 746, "byTier": { "PUBLIC": 693, - "PUBLIC-ADVANCED": 60, + "PUBLIC-ADVANCED": 52, "INTERNAL": 1 }, "byCategory": { "Layout tokens": 53, - "Core tokens": 623, + "Core tokens": 615, "Macro tokens": 32, "Component tokens": 46 } @@ -2236,7 +2236,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Very light action shade. Hover fills on white surfaces, badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2257,7 +2257,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Light action shade. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2278,7 +2278,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Light-mid action shade. Borders on light backgrounds, low-emphasis fills.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2299,7 +2299,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Mid-light action shade. Disabled state fills, decorative accents.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2320,7 +2320,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Lightest action tint. Background fill for subtle action-tinted surfaces.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2362,7 +2362,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Mid-dark action shade. Text on light surfaces, icon fills.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2383,7 +2383,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Dark action shade. Strong text and icon fills on light backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2404,7 +2404,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Very dark action shade. High-contrast text on white.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2425,7 +2425,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Near-black action shade. Extreme contrast on white surfaces.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2446,7 +2446,7 @@ "group": "action", "description": "Semantic action-color scale derived from --sf-color-action. Covers fills, hover/active states, and tint variants for primary interactive elements.", "note": "Darkest action tint. Near-black for dark-theme surface accents.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4231,7 +4231,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Very light neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4252,7 +4252,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Light neutral shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4273,7 +4273,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Light-mid neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4294,7 +4294,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Mid-light neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4315,7 +4315,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Lightest neutral tint.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4357,7 +4357,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Mid-dark neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4378,7 +4378,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Dark neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4399,7 +4399,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Very dark neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4420,7 +4420,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Near-black neutral shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4441,7 +4441,7 @@ "group": "neutral", "description": "Semantic neutral-color scale derived from --sf-color-neutral. Useful for muted UI chrome.", "note": "Darkest neutral tint.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4882,7 +4882,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Very light primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4903,7 +4903,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Light primary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4924,7 +4924,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Light-mid primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4945,7 +4945,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Mid-light primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -4966,7 +4966,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Lightest primary tint.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5008,7 +5008,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Mid-dark primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5029,7 +5029,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Dark primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5050,7 +5050,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Very dark primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5071,7 +5071,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Near-black primary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5092,7 +5092,7 @@ "group": "primary", "description": "Semantic primary-color scale derived from --sf-color-primary. Covers fills, hover/active states, and tint variants for the primary palette role.", "note": "Darkest primary tint.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5554,7 +5554,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Very light secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5575,7 +5575,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Light secondary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5596,7 +5596,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Light-mid secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5617,7 +5617,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Mid-light secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5638,7 +5638,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Lightest secondary tint.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5680,7 +5680,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Mid-dark secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5701,7 +5701,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Dark secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5722,7 +5722,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Very dark secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5743,7 +5743,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Near-black secondary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -5764,7 +5764,7 @@ "group": "secondary", "description": "Semantic secondary-color scale derived from --sf-color-secondary.", "note": "Darkest secondary tint.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6436,7 +6436,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Very light tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6457,7 +6457,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Light tertiary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6478,7 +6478,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Light-mid tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6499,7 +6499,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Mid-light tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6520,7 +6520,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Lightest tertiary tint.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6562,7 +6562,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Mid-dark tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6583,7 +6583,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Dark tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6604,7 +6604,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Very dark tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6625,7 +6625,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Near-black tertiary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -6646,7 +6646,7 @@ "group": "tertiary", "description": "Semantic tertiary-color scale derived from --sf-color-tertiary.", "note": "Darkest tertiary tint.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "syntax": null, @@ -11255,15 +11255,15 @@ ] }, { - "name": "--sf-palette-mix-100", + "name": "--sf-palette-shade-l", "tier": "PUBLIC-ADVANCED", "role": "knob", "namespace": "palette", "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 100. Controls blend depth toward the surface. Default 8%.", - "note": "Color-mix percentage for palette step 100. Controls blend depth toward the surface. Default 8%.", - "value": "8%", + "group": "Palette ramp lightness anchors", + "description": "Absolute OKLCH lightness the shade steps (600-950) pull toward; sets how dark the darkest palette step can reach. Default 0.1.", + "note": "Absolute OKLCH lightness the shade steps (600-950) pull toward; sets how dark the darkest palette step can reach. Default 0.1.", + "value": "0.1", "aliasOf": null, "registered": false, "syntax": null, @@ -11276,183 +11276,15 @@ ] }, { - "name": "--sf-palette-mix-200", + "name": "--sf-palette-tint-l", "tier": "PUBLIC-ADVANCED", "role": "knob", "namespace": "palette", "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 200. Controls blend depth toward the surface. Default 20%.", - "note": "Color-mix percentage for palette step 200. Controls blend depth toward the surface. Default 20%.", - "value": "20%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-300", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 300. Controls blend depth toward the surface. Default 40%.", - "note": "Color-mix percentage for palette step 300. Controls blend depth toward the surface. Default 40%.", - "value": "40%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-400", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 400 (near-mid tint). Controls blend depth. Default 65%.", - "note": "Color-mix percentage for palette step 400 (near-mid tint). Controls blend depth. Default 65%.", - "value": "65%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-50", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for the lightest palette step (50). Controls how far step 50 blends toward the surface. Default 4%.", - "note": "Color-mix percentage for the lightest palette step (50). Controls how far step 50 blends toward the surface. Default 4%.", - "value": "4%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-600", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 600 (near-mid shade). Controls blend depth toward the text color. Default 82%.", - "note": "Color-mix percentage for palette step 600 (near-mid shade). Controls blend depth toward the text color. Default 82%.", - "value": "82%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-700", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 700. Controls blend depth toward the text color. Default 62%.", - "note": "Color-mix percentage for palette step 700. Controls blend depth toward the text color. Default 62%.", - "value": "62%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-800", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 800 (dark shade). Controls blend depth toward text. Default 38%.", - "note": "Color-mix percentage for palette step 800 (dark shade). Controls blend depth toward text. Default 38%.", - "value": "38%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-900", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 900 (very dark shade). Controls blend depth toward text. Default 18%.", - "note": "Color-mix percentage for palette step 900 (very dark shade). Controls blend depth toward text. Default 18%.", - "value": "18%", - "aliasOf": null, - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-950", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for the darkest palette step (950). Controls how far step 950 blends toward the text color. Default 8%.", - "note": "Color-mix percentage for the darkest palette step (950). Controls how far step 950 blends toward the text color. Default 8%.", - "value": "8%", + "group": "Palette ramp lightness anchors", + "description": "Absolute OKLCH lightness the tint steps (50-400) pull toward; sets how light the lightest palette step can reach. Default 0.97.", + "note": "Absolute OKLCH lightness the tint steps (50-400) pull toward; sets how light the lightest palette step can reach. Default 0.97.", + "value": "0.97", "aliasOf": null, "registered": false, "syntax": null, diff --git a/configurator/src/data/domain-patterns.json b/configurator/src/data/domain-patterns.json index 8fda785b..8703ab22 100644 --- a/configurator/src/data/domain-patterns.json +++ b/configurator/src/data/domain-patterns.json @@ -1,6 +1,6 @@ { "macros": ["prose", "flow-space", "line-clamp", "aspect", "scroll-shadow", "scrim", "surface-color", "surface-bg", "content-intrinsic", "overlap-"], - "colors": ["color", "contrast", "palette-mix", "lumlocker", "gradient"], + "colors": ["color", "contrast", "palette", "lumlocker", "gradient"], "typography": ["font", "--sf-text", "leading", "tracking", "weight", "body-font", "heading-font", "body-em", "body-text", "heading-text", "display-l-", "display-m-", "-h1-", "-h2-", "-h3-", "-h4-", "-h5-", "-h6-", diff --git a/configurator/src/data/token-registry.generated.json b/configurator/src/data/token-registry.generated.json index 2899b694..5e23826f 100644 --- a/configurator/src/data/token-registry.generated.json +++ b/configurator/src/data/token-registry.generated.json @@ -1,7 +1,7 @@ { "_meta": { "generatedBy": "scripts/gen-token-registry.js", - "nextId": 798 + "nextId": 800 }, "tokens": [ { @@ -1993,43 +1993,53 @@ }, { "id": 489, - "name": "--sf-palette-mix-100" + "name": "--sf-palette-mix-100", + "removed": true }, { "id": 490, - "name": "--sf-palette-mix-200" + "name": "--sf-palette-mix-200", + "removed": true }, { "id": 491, - "name": "--sf-palette-mix-300" + "name": "--sf-palette-mix-300", + "removed": true }, { "id": 492, - "name": "--sf-palette-mix-400" + "name": "--sf-palette-mix-400", + "removed": true }, { "id": 493, - "name": "--sf-palette-mix-50" + "name": "--sf-palette-mix-50", + "removed": true }, { "id": 494, - "name": "--sf-palette-mix-600" + "name": "--sf-palette-mix-600", + "removed": true }, { "id": 495, - "name": "--sf-palette-mix-700" + "name": "--sf-palette-mix-700", + "removed": true }, { "id": 496, - "name": "--sf-palette-mix-800" + "name": "--sf-palette-mix-800", + "removed": true }, { "id": 497, - "name": "--sf-palette-mix-900" + "name": "--sf-palette-mix-900", + "removed": true }, { "id": 498, - "name": "--sf-palette-mix-950" + "name": "--sf-palette-mix-950", + "removed": true }, { "id": 499, @@ -3239,6 +3249,14 @@ { "id": 797, "name": "--sf-density" + }, + { + "id": 798, + "name": "--sf-palette-shade-l" + }, + { + "id": 799, + "name": "--sf-palette-tint-l" } ] } diff --git a/core/tokens.css b/core/tokens.css index a5c8ce84..319103dd 100644 --- a/core/tokens.css +++ b/core/tokens.css @@ -704,37 +704,37 @@ :root { /* ---------------------------------------------------------- - Palette shade mix percentages — PUBLIC-ADVANCED - Controls how far each numeric step blends toward surface (tints, - steps 50-400) or toward text (shades, steps 600-950). 500 = the - base color itself (no mixing). These are values - consumed by color-mix() in every family below. + Palette ramp lightness anchors — PUBLIC-ADVANCED + Each numeric step is generated in OKLCH by pulling the family + colour's own lightness a fixed fraction toward an ABSOLUTE target: + tints (50-400) toward --sf-palette-tint-l, shades (600-950) toward + --sf-palette-shade-l. 500 = the family colour itself. Because the + targets are absolute (not the theme's surface/text tokens) and the + pull is clamped (max()/min()) so a tint can never end darker than + the base nor a shade lighter, the ramp is MONOTONIC light→dark for + ANY source colour and any anchor configuration — it cannot fold. + Per-step pull fractions and chroma taper are baked into each family + below; these two knobs set how light the lightest / how dark the + darkest step may reach. The `base` family keeps its own absolute + ladder (near-white→near-black) and does not read these. ---------------------------------------------------------- */ - --sf-palette-mix-50: 4%; - --sf-palette-mix-100: 8%; - --sf-palette-mix-200: 20%; - --sf-palette-mix-300: 40%; - --sf-palette-mix-400: 65%; - --sf-palette-mix-600: 82%; - --sf-palette-mix-700: 62%; - --sf-palette-mix-800: 38%; - --sf-palette-mix-900: 18%; - --sf-palette-mix-950: 8%; + --sf-palette-tint-l: 0.97; + --sf-palette-shade-l: 0.1; /* ---------------------------------------------------------- primary ---------------------------------------------------------- */ - --sf-color-primary-50: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface)); - --sf-color-primary-100: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface)); - --sf-color-primary-200: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface)); - --sf-color-primary-300: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface)); - --sf-color-primary-400: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface)); + --sf-color-primary-50: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h); + --sf-color-primary-100: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h); + --sf-color-primary-200: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h); + --sf-color-primary-300: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h); + --sf-color-primary-400: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h); --sf-color-primary-500: var(--sf-color-primary); - --sf-color-primary-600: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text)); - --sf-color-primary-700: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text)); - --sf-color-primary-800: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text)); - --sf-color-primary-900: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text)); - --sf-color-primary-950: color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text)); + --sf-color-primary-600: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h); + --sf-color-primary-700: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h); + --sf-color-primary-800: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h); + --sf-color-primary-900: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h); + --sf-color-primary-950: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h); --sf-color-primary-a5: oklch(from var(--sf-color-primary) l c h / 0.05); --sf-color-primary-a10: oklch(from var(--sf-color-primary) l c h / 0.10); @@ -759,17 +759,17 @@ /* ---------------------------------------------------------- secondary ---------------------------------------------------------- */ - --sf-color-secondary-50: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface)); - --sf-color-secondary-100: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface)); - --sf-color-secondary-200: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface)); - --sf-color-secondary-300: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface)); - --sf-color-secondary-400: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface)); + --sf-color-secondary-50: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h); + --sf-color-secondary-100: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h); + --sf-color-secondary-200: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h); + --sf-color-secondary-300: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h); + --sf-color-secondary-400: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h); --sf-color-secondary-500: var(--sf-color-secondary); - --sf-color-secondary-600: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text)); - --sf-color-secondary-700: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text)); - --sf-color-secondary-800: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text)); - --sf-color-secondary-900: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text)); - --sf-color-secondary-950: color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text)); + --sf-color-secondary-600: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h); + --sf-color-secondary-700: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h); + --sf-color-secondary-800: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h); + --sf-color-secondary-900: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h); + --sf-color-secondary-950: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h); --sf-color-secondary-a5: oklch(from var(--sf-color-secondary) l c h / 0.05); --sf-color-secondary-a10: oklch(from var(--sf-color-secondary) l c h / 0.10); @@ -794,17 +794,17 @@ /* ---------------------------------------------------------- tertiary ---------------------------------------------------------- */ - --sf-color-tertiary-50: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface)); - --sf-color-tertiary-100: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface)); - --sf-color-tertiary-200: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface)); - --sf-color-tertiary-300: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface)); - --sf-color-tertiary-400: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface)); + --sf-color-tertiary-50: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h); + --sf-color-tertiary-100: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h); + --sf-color-tertiary-200: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h); + --sf-color-tertiary-300: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h); + --sf-color-tertiary-400: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h); --sf-color-tertiary-500: var(--sf-color-tertiary); - --sf-color-tertiary-600: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text)); - --sf-color-tertiary-700: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text)); - --sf-color-tertiary-800: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text)); - --sf-color-tertiary-900: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text)); - --sf-color-tertiary-950: color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text)); + --sf-color-tertiary-600: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h); + --sf-color-tertiary-700: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h); + --sf-color-tertiary-800: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h); + --sf-color-tertiary-900: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h); + --sf-color-tertiary-950: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h); --sf-color-tertiary-a5: oklch(from var(--sf-color-tertiary) l c h / 0.05); --sf-color-tertiary-a10: oklch(from var(--sf-color-tertiary) l c h / 0.10); @@ -829,17 +829,17 @@ /* ---------------------------------------------------------- action ---------------------------------------------------------- */ - --sf-color-action-50: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface)); - --sf-color-action-100: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface)); - --sf-color-action-200: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface)); - --sf-color-action-300: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface)); - --sf-color-action-400: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface)); + --sf-color-action-50: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h); + --sf-color-action-100: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h); + --sf-color-action-200: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h); + --sf-color-action-300: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h); + --sf-color-action-400: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h); --sf-color-action-500: var(--sf-color-action); - --sf-color-action-600: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text)); - --sf-color-action-700: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text)); - --sf-color-action-800: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text)); - --sf-color-action-900: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text)); - --sf-color-action-950: color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text)); + --sf-color-action-600: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h); + --sf-color-action-700: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h); + --sf-color-action-800: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h); + --sf-color-action-900: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h); + --sf-color-action-950: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h); --sf-color-action-a5: oklch(from var(--sf-color-action) l c h / 0.05); --sf-color-action-a10: oklch(from var(--sf-color-action) l c h / 0.10); @@ -864,17 +864,17 @@ /* ---------------------------------------------------------- neutral ---------------------------------------------------------- */ - --sf-color-neutral-50: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface)); - --sf-color-neutral-100: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface)); - --sf-color-neutral-200: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface)); - --sf-color-neutral-300: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface)); - --sf-color-neutral-400: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface)); + --sf-color-neutral-50: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h); + --sf-color-neutral-100: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h); + --sf-color-neutral-200: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h); + --sf-color-neutral-300: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h); + --sf-color-neutral-400: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h); --sf-color-neutral-500: var(--sf-color-neutral); - --sf-color-neutral-600: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text)); - --sf-color-neutral-700: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text)); - --sf-color-neutral-800: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text)); - --sf-color-neutral-900: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text)); - --sf-color-neutral-950: color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text)); + --sf-color-neutral-600: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h); + --sf-color-neutral-700: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h); + --sf-color-neutral-800: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h); + --sf-color-neutral-900: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h); + --sf-color-neutral-950: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h); --sf-color-neutral-a5: oklch(from var(--sf-color-neutral) l c h / 0.05); --sf-color-neutral-a10: oklch(from var(--sf-color-neutral) l c h / 0.10); diff --git a/demo/index.html b/demo/index.html index f82a828a..f9425835 100644 --- a/demo/index.html +++ b/demo/index.html @@ -4380,17 +4380,17 @@

Design tokens 7
--sf-color-action
--sf-color-action--active
--sf-color-action--hover
-
--sf-color-action-100
-
--sf-color-action-200
-
--sf-color-action-300
-
--sf-color-action-400
-
--sf-color-action-50
+
--sf-color-action-100
+
--sf-color-action-200
+
--sf-color-action-300
+
--sf-color-action-400
+
--sf-color-action-50
--sf-color-action-500
-
--sf-color-action-600
-
--sf-color-action-700
-
--sf-color-action-800
-
--sf-color-action-900
-
--sf-color-action-950
+
--sf-color-action-600
+
--sf-color-action-700
+
--sf-color-action-800
+
--sf-color-action-900
+
--sf-color-action-950
--sf-color-action-a10
--sf-color-action-a30
--sf-color-action-a5
@@ -4475,17 +4475,17 @@

Design tokens 7
--sf-color-neutral
--sf-color-neutral--active
--sf-color-neutral--hover
-
--sf-color-neutral-100
-
--sf-color-neutral-200
-
--sf-color-neutral-300
-
--sf-color-neutral-400
-
--sf-color-neutral-50
+
--sf-color-neutral-100
+
--sf-color-neutral-200
+
--sf-color-neutral-300
+
--sf-color-neutral-400
+
--sf-color-neutral-50
--sf-color-neutral-500
-
--sf-color-neutral-600
-
--sf-color-neutral-700
-
--sf-color-neutral-800
-
--sf-color-neutral-900
-
--sf-color-neutral-950
+
--sf-color-neutral-600
+
--sf-color-neutral-700
+
--sf-color-neutral-800
+
--sf-color-neutral-900
+
--sf-color-neutral-950
--sf-color-neutral-a10
--sf-color-neutral-a30
--sf-color-neutral-a5
@@ -4506,17 +4506,17 @@

Design tokens 7
--sf-color-primary
--sf-color-primary--active
--sf-color-primary--hover
-
--sf-color-primary-100
-
--sf-color-primary-200
-
--sf-color-primary-300
-
--sf-color-primary-400
-
--sf-color-primary-50
+
--sf-color-primary-100
+
--sf-color-primary-200
+
--sf-color-primary-300
+
--sf-color-primary-400
+
--sf-color-primary-50
--sf-color-primary-500
-
--sf-color-primary-600
-
--sf-color-primary-700
-
--sf-color-primary-800
-
--sf-color-primary-900
-
--sf-color-primary-950
+
--sf-color-primary-600
+
--sf-color-primary-700
+
--sf-color-primary-800
+
--sf-color-primary-900
+
--sf-color-primary-950
--sf-color-primary-a10
--sf-color-primary-a30
--sf-color-primary-a5
@@ -4538,17 +4538,17 @@

Design tokens 7
--sf-color-secondary
--sf-color-secondary--active
--sf-color-secondary--hover
-
--sf-color-secondary-100
-
--sf-color-secondary-200
-
--sf-color-secondary-300
-
--sf-color-secondary-400
-
--sf-color-secondary-50
+
--sf-color-secondary-100
+
--sf-color-secondary-200
+
--sf-color-secondary-300
+
--sf-color-secondary-400
+
--sf-color-secondary-50
--sf-color-secondary-500
-
--sf-color-secondary-600
-
--sf-color-secondary-700
-
--sf-color-secondary-800
-
--sf-color-secondary-900
-
--sf-color-secondary-950
+
--sf-color-secondary-600
+
--sf-color-secondary-700
+
--sf-color-secondary-800
+
--sf-color-secondary-900
+
--sf-color-secondary-950
--sf-color-secondary-a10
--sf-color-secondary-a30
--sf-color-secondary-a5
@@ -4580,17 +4580,17 @@

Design tokens 7
--sf-color-tertiary
--sf-color-tertiary--active
--sf-color-tertiary--hover
-
--sf-color-tertiary-100
-
--sf-color-tertiary-200
-
--sf-color-tertiary-300
-
--sf-color-tertiary-400
-
--sf-color-tertiary-50
+
--sf-color-tertiary-100
+
--sf-color-tertiary-200
+
--sf-color-tertiary-300
+
--sf-color-tertiary-400
+
--sf-color-tertiary-50
--sf-color-tertiary-500
-
--sf-color-tertiary-600
-
--sf-color-tertiary-700
-
--sf-color-tertiary-800
-
--sf-color-tertiary-900
-
--sf-color-tertiary-950
+
--sf-color-tertiary-600
+
--sf-color-tertiary-700
+
--sf-color-tertiary-800
+
--sf-color-tertiary-900
+
--sf-color-tertiary-950
--sf-color-tertiary-a10
--sf-color-tertiary-a30
--sf-color-tertiary-a5
@@ -4810,16 +4810,8 @@

Design tokens 7
--sf-opacity-muted
--sf-optical-sizing
--sf-overlap-pull
-
--sf-palette-mix-100
-
--sf-palette-mix-200
-
--sf-palette-mix-300
-
--sf-palette-mix-400
-
--sf-palette-mix-50
-
--sf-palette-mix-600
-
--sf-palette-mix-700
-
--sf-palette-mix-800
-
--sf-palette-mix-900
-
--sf-palette-mix-950
+
--sf-palette-tint-l
+
--sf-palette-shade-l
--sf-print-base-size
--sf-print-page-margin
--sf-print-page-size
@@ -5029,7 +5021,7 @@

Design tokens 7
--sf-z-tooltip
- +

diff --git a/dist/css-custom-data.json b/dist/css-custom-data.json index 9859c871..0409883e 100644 --- a/dist/css-custom-data.json +++ b/dist/css-custom-data.json @@ -538,27 +538,27 @@ }, { "name": "--sf-color-action-100", - "description": "Very light action shade. Hover fills on white surfaces, badge backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))`", + "description": "Very light action shade. Hover fills on white surfaces, badge backgrounds.\n\nDefault: `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)`", "syntax": "*" }, { "name": "--sf-color-action-200", - "description": "Light action shade. Subtle fills and outlined badge backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))`", + "description": "Light action shade. Subtle fills and outlined badge backgrounds.\n\nDefault: `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)`", "syntax": "*" }, { "name": "--sf-color-action-300", - "description": "Light-mid action shade. Borders on light backgrounds, low-emphasis fills.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))`", + "description": "Light-mid action shade. Borders on light backgrounds, low-emphasis fills.\n\nDefault: `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-action-400", - "description": "Mid-light action shade. Disabled state fills, decorative accents.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))`", + "description": "Mid-light action shade. Disabled state fills, decorative accents.\n\nDefault: `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-action-50", - "description": "Lightest action tint. Background fill for subtle action-tinted surfaces.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))`", + "description": "Lightest action tint. Background fill for subtle action-tinted surfaces.\n\nDefault: `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)`", "syntax": "*" }, { @@ -568,27 +568,27 @@ }, { "name": "--sf-color-action-600", - "description": "Mid-dark action shade. Text on light surfaces, icon fills.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))`", + "description": "Mid-dark action shade. Text on light surfaces, icon fills.\n\nDefault: `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)`", "syntax": "*" }, { "name": "--sf-color-action-700", - "description": "Dark action shade. Strong text and icon fills on light backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))`", + "description": "Dark action shade. Strong text and icon fills on light backgrounds.\n\nDefault: `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-action-800", - "description": "Very dark action shade. High-contrast text on white.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))`", + "description": "Very dark action shade. High-contrast text on white.\n\nDefault: `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-action-900", - "description": "Near-black action shade. Extreme contrast on white surfaces.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))`", + "description": "Near-black action shade. Extreme contrast on white surfaces.\n\nDefault: `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)`", "syntax": "*" }, { "name": "--sf-color-action-950", - "description": "Darkest action tint. Near-black for dark-theme surface accents.\n\nDefault: `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))`", + "description": "Darkest action tint. Near-black for dark-theme surface accents.\n\nDefault: `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)`", "syntax": "*" }, { @@ -1013,27 +1013,27 @@ }, { "name": "--sf-color-neutral-100", - "description": "Very light neutral shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))`", + "description": "Very light neutral shade.\n\nDefault: `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-200", - "description": "Light neutral shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))`", + "description": "Light neutral shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-300", - "description": "Light-mid neutral shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))`", + "description": "Light-mid neutral shade.\n\nDefault: `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-400", - "description": "Mid-light neutral shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))`", + "description": "Mid-light neutral shade.\n\nDefault: `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-50", - "description": "Lightest neutral tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))`", + "description": "Lightest neutral tint.\n\nDefault: `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)`", "syntax": "*" }, { @@ -1043,27 +1043,27 @@ }, { "name": "--sf-color-neutral-600", - "description": "Mid-dark neutral shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))`", + "description": "Mid-dark neutral shade.\n\nDefault: `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-700", - "description": "Dark neutral shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))`", + "description": "Dark neutral shade.\n\nDefault: `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-800", - "description": "Very dark neutral shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))`", + "description": "Very dark neutral shade.\n\nDefault: `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-900", - "description": "Near-black neutral shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))`", + "description": "Near-black neutral shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)`", "syntax": "*" }, { "name": "--sf-color-neutral-950", - "description": "Darkest neutral tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))`", + "description": "Darkest neutral tint.\n\nDefault: `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)`", "syntax": "*" }, { @@ -1168,27 +1168,27 @@ }, { "name": "--sf-color-primary-100", - "description": "Very light primary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))`", + "description": "Very light primary shade.\n\nDefault: `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)`", "syntax": "*" }, { "name": "--sf-color-primary-200", - "description": "Light primary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))`", + "description": "Light primary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)`", "syntax": "*" }, { "name": "--sf-color-primary-300", - "description": "Light-mid primary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))`", + "description": "Light-mid primary shade.\n\nDefault: `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-primary-400", - "description": "Mid-light primary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))`", + "description": "Mid-light primary shade.\n\nDefault: `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-primary-50", - "description": "Lightest primary tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))`", + "description": "Lightest primary tint.\n\nDefault: `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)`", "syntax": "*" }, { @@ -1198,27 +1198,27 @@ }, { "name": "--sf-color-primary-600", - "description": "Mid-dark primary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))`", + "description": "Mid-dark primary shade.\n\nDefault: `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)`", "syntax": "*" }, { "name": "--sf-color-primary-700", - "description": "Dark primary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))`", + "description": "Dark primary shade.\n\nDefault: `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-primary-800", - "description": "Very dark primary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))`", + "description": "Very dark primary shade.\n\nDefault: `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-primary-900", - "description": "Near-black primary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))`", + "description": "Near-black primary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)`", "syntax": "*" }, { "name": "--sf-color-primary-950", - "description": "Darkest primary tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))`", + "description": "Darkest primary tint.\n\nDefault: `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)`", "syntax": "*" }, { @@ -1328,27 +1328,27 @@ }, { "name": "--sf-color-secondary-100", - "description": "Very light secondary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))`", + "description": "Very light secondary shade.\n\nDefault: `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-200", - "description": "Light secondary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))`", + "description": "Light secondary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-300", - "description": "Light-mid secondary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))`", + "description": "Light-mid secondary shade.\n\nDefault: `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-400", - "description": "Mid-light secondary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))`", + "description": "Mid-light secondary shade.\n\nDefault: `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-50", - "description": "Lightest secondary tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))`", + "description": "Lightest secondary tint.\n\nDefault: `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)`", "syntax": "*" }, { @@ -1358,27 +1358,27 @@ }, { "name": "--sf-color-secondary-600", - "description": "Mid-dark secondary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))`", + "description": "Mid-dark secondary shade.\n\nDefault: `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-700", - "description": "Dark secondary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))`", + "description": "Dark secondary shade.\n\nDefault: `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-800", - "description": "Very dark secondary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))`", + "description": "Very dark secondary shade.\n\nDefault: `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-900", - "description": "Near-black secondary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))`", + "description": "Near-black secondary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)`", "syntax": "*" }, { "name": "--sf-color-secondary-950", - "description": "Darkest secondary tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))`", + "description": "Darkest secondary tint.\n\nDefault: `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)`", "syntax": "*" }, { @@ -1538,27 +1538,27 @@ }, { "name": "--sf-color-tertiary-100", - "description": "Very light tertiary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))`", + "description": "Very light tertiary shade.\n\nDefault: `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-200", - "description": "Light tertiary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))`", + "description": "Light tertiary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.\n\nDefault: `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-300", - "description": "Light-mid tertiary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))`", + "description": "Light-mid tertiary shade.\n\nDefault: `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-400", - "description": "Mid-light tertiary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))`", + "description": "Mid-light tertiary shade.\n\nDefault: `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-50", - "description": "Lightest tertiary tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))`", + "description": "Lightest tertiary tint.\n\nDefault: `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)`", "syntax": "*" }, { @@ -1568,27 +1568,27 @@ }, { "name": "--sf-color-tertiary-600", - "description": "Mid-dark tertiary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))`", + "description": "Mid-dark tertiary shade.\n\nDefault: `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-700", - "description": "Dark tertiary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))`", + "description": "Dark tertiary shade.\n\nDefault: `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-800", - "description": "Very dark tertiary shade.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))`", + "description": "Very dark tertiary shade.\n\nDefault: `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-900", - "description": "Near-black tertiary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))`", + "description": "Near-black tertiary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.\n\nDefault: `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)`", "syntax": "*" }, { "name": "--sf-color-tertiary-950", - "description": "Darkest tertiary tint.\n\nDefault: `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))`", + "description": "Darkest tertiary tint.\n\nDefault: `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)`", "syntax": "*" }, { @@ -2682,53 +2682,13 @@ "syntax": "*" }, { - "name": "--sf-palette-mix-100", - "description": "Color-mix percentage for palette step 100. Controls blend depth toward the surface. Default 8%.\n\nDefault: `8%`\n\n(advanced token)", + "name": "--sf-palette-shade-l", + "description": "Absolute OKLCH lightness the shade steps (600-950) pull toward; sets how dark the darkest palette step can reach. Default 0.1.\n\nDefault: `0.1`\n\n(advanced token)", "syntax": "*" }, { - "name": "--sf-palette-mix-200", - "description": "Color-mix percentage for palette step 200. Controls blend depth toward the surface. Default 20%.\n\nDefault: `20%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-300", - "description": "Color-mix percentage for palette step 300. Controls blend depth toward the surface. Default 40%.\n\nDefault: `40%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-400", - "description": "Color-mix percentage for palette step 400 (near-mid tint). Controls blend depth. Default 65%.\n\nDefault: `65%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-50", - "description": "Color-mix percentage for the lightest palette step (50). Controls how far step 50 blends toward the surface. Default 4%.\n\nDefault: `4%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-600", - "description": "Color-mix percentage for palette step 600 (near-mid shade). Controls blend depth toward the text color. Default 82%.\n\nDefault: `82%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-700", - "description": "Color-mix percentage for palette step 700. Controls blend depth toward the text color. Default 62%.\n\nDefault: `62%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-800", - "description": "Color-mix percentage for palette step 800 (dark shade). Controls blend depth toward text. Default 38%.\n\nDefault: `38%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-900", - "description": "Color-mix percentage for palette step 900 (very dark shade). Controls blend depth toward text. Default 18%.\n\nDefault: `18%`\n\n(advanced token)", - "syntax": "*" - }, - { - "name": "--sf-palette-mix-950", - "description": "Color-mix percentage for the darkest palette step (950). Controls how far step 950 blends toward the text color. Default 8%.\n\nDefault: `8%`\n\n(advanced token)", + "name": "--sf-palette-tint-l", + "description": "Absolute OKLCH lightness the tint steps (50-400) pull toward; sets how light the lightest palette step can reach. Default 0.97.\n\nDefault: `0.97`\n\n(advanced token)", "syntax": "*" }, { diff --git a/docs/api-index.json b/docs/api-index.json index 001980db..ddfbc63a 100644 --- a/docs/api-index.json +++ b/docs/api-index.json @@ -25,21 +25,21 @@ "optimal" ], "counts": { - "total": 1079, + "total": 1071, "by_type": { "class": 325, - "token": 754 + "token": 746 }, "by_tier": { "INTERNAL": 1, "PUBLIC": 1018, - "PUBLIC-ADVANCED": 60 + "PUBLIC-ADVANCED": 52 }, "by_role": { "consumption": 489, - "knob": 265 + "knob": 257 }, - "tokens": 754, + "tokens": 746, "classes": 325, "sf_classes": 289, "is_classes": 28, @@ -48,7 +48,7 @@ "Accessibility": 8, "Component tokens": 46, "Components": 30, - "Core tokens": 623, + "Core tokens": 615, "Forms": 1, "Layout primitives": 145, "Layout tokens": 53, @@ -2838,7 +2838,7 @@ "area": "core", "group": "action", "description": "Very light action shade. Hover fills on white surfaces, badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -2864,7 +2864,7 @@ "area": "core", "group": "action", "description": "Light action shade. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -2890,7 +2890,7 @@ "area": "core", "group": "action", "description": "Light-mid action shade. Borders on light backgrounds, low-emphasis fills.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -2916,7 +2916,7 @@ "area": "core", "group": "action", "description": "Mid-light action shade. Disabled state fills, decorative accents.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -2942,7 +2942,7 @@ "area": "core", "group": "action", "description": "Lightest action tint. Background fill for subtle action-tinted surfaces.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -2994,7 +2994,7 @@ "area": "core", "group": "action", "description": "Mid-dark action shade. Text on light surfaces, icon fills.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -3020,7 +3020,7 @@ "area": "core", "group": "action", "description": "Dark action shade. Strong text and icon fills on light backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -3046,7 +3046,7 @@ "area": "core", "group": "action", "description": "Very dark action shade. High-contrast text on white.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -3072,7 +3072,7 @@ "area": "core", "group": "action", "description": "Near-black action shade. Extreme contrast on white surfaces.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -3098,7 +3098,7 @@ "area": "core", "group": "action", "description": "Darkest action tint. Near-black for dark-theme surface accents.", - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5308,7 +5308,7 @@ "area": "core", "group": "neutral", "description": "Very light neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5334,7 +5334,7 @@ "area": "core", "group": "neutral", "description": "Light neutral shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5360,7 +5360,7 @@ "area": "core", "group": "neutral", "description": "Light-mid neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5386,7 +5386,7 @@ "area": "core", "group": "neutral", "description": "Mid-light neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5412,7 +5412,7 @@ "area": "core", "group": "neutral", "description": "Lightest neutral tint.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5464,7 +5464,7 @@ "area": "core", "group": "neutral", "description": "Mid-dark neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5490,7 +5490,7 @@ "area": "core", "group": "neutral", "description": "Dark neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5516,7 +5516,7 @@ "area": "core", "group": "neutral", "description": "Very dark neutral shade.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5542,7 +5542,7 @@ "area": "core", "group": "neutral", "description": "Near-black neutral shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -5568,7 +5568,7 @@ "area": "core", "group": "neutral", "description": "Darkest neutral tint.", - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6114,7 +6114,7 @@ "area": "core", "group": "primary", "description": "Very light primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6140,7 +6140,7 @@ "area": "core", "group": "primary", "description": "Light primary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6166,7 +6166,7 @@ "area": "core", "group": "primary", "description": "Light-mid primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6192,7 +6192,7 @@ "area": "core", "group": "primary", "description": "Mid-light primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6218,7 +6218,7 @@ "area": "core", "group": "primary", "description": "Lightest primary tint.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6270,7 +6270,7 @@ "area": "core", "group": "primary", "description": "Mid-dark primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6296,7 +6296,7 @@ "area": "core", "group": "primary", "description": "Dark primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6322,7 +6322,7 @@ "area": "core", "group": "primary", "description": "Very dark primary shade.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6348,7 +6348,7 @@ "area": "core", "group": "primary", "description": "Near-black primary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6374,7 +6374,7 @@ "area": "core", "group": "primary", "description": "Darkest primary tint.", - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6946,7 +6946,7 @@ "area": "core", "group": "secondary", "description": "Very light secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6972,7 +6972,7 @@ "area": "core", "group": "secondary", "description": "Light secondary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -6998,7 +6998,7 @@ "area": "core", "group": "secondary", "description": "Light-mid secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7024,7 +7024,7 @@ "area": "core", "group": "secondary", "description": "Mid-light secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7050,7 +7050,7 @@ "area": "core", "group": "secondary", "description": "Lightest secondary tint.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7102,7 +7102,7 @@ "area": "core", "group": "secondary", "description": "Mid-dark secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7128,7 +7128,7 @@ "area": "core", "group": "secondary", "description": "Dark secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7154,7 +7154,7 @@ "area": "core", "group": "secondary", "description": "Very dark secondary shade.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7180,7 +7180,7 @@ "area": "core", "group": "secondary", "description": "Near-black secondary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -7206,7 +7206,7 @@ "area": "core", "group": "secondary", "description": "Darkest secondary tint.", - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8038,7 +8038,7 @@ "area": "core", "group": "tertiary", "description": "Very light tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8064,7 +8064,7 @@ "area": "core", "group": "tertiary", "description": "Light tertiary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8090,7 +8090,7 @@ "area": "core", "group": "tertiary", "description": "Light-mid tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8116,7 +8116,7 @@ "area": "core", "group": "tertiary", "description": "Mid-light tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8142,7 +8142,7 @@ "area": "core", "group": "tertiary", "description": "Lightest tertiary tint.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))", + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8194,7 +8194,7 @@ "area": "core", "group": "tertiary", "description": "Mid-dark tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8220,7 +8220,7 @@ "area": "core", "group": "tertiary", "description": "Dark tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8246,7 +8246,7 @@ "area": "core", "group": "tertiary", "description": "Very dark tertiary shade.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8272,7 +8272,7 @@ "area": "core", "group": "tertiary", "description": "Near-black tertiary shade at step 900 on the numeric scale. Extreme contrast on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -8298,7 +8298,7 @@ "area": "core", "group": "tertiary", "description": "Darkest tertiary tint.", - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)", "aliasOf": null, "registered": false, "animatable": false, @@ -14006,16 +14006,16 @@ ] }, { - "name": "--sf-palette-mix-100", + "name": "--sf-palette-shade-l", "type": "token", "tier": "PUBLIC-ADVANCED", "role": "knob", "namespace": "palette", "category": "Core tokens", "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 100. Controls blend depth toward the surface. Default 8%.", - "value": "8%", + "group": "Palette ramp lightness anchors", + "description": "Absolute OKLCH lightness the shade steps (600-950) pull toward; sets how dark the darkest palette step can reach. Default 0.1.", + "value": "0.1", "aliasOf": null, "registered": false, "animatable": false, @@ -14032,224 +14032,16 @@ ] }, { - "name": "--sf-palette-mix-200", + "name": "--sf-palette-tint-l", "type": "token", "tier": "PUBLIC-ADVANCED", "role": "knob", "namespace": "palette", "category": "Core tokens", "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 200. Controls blend depth toward the surface. Default 20%.", - "value": "20%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-300", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 300. Controls blend depth toward the surface. Default 40%.", - "value": "40%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-400", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 400 (near-mid tint). Controls blend depth. Default 65%.", - "value": "65%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-50", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for the lightest palette step (50). Controls how far step 50 blends toward the surface. Default 4%.", - "value": "4%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-600", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 600 (near-mid shade). Controls blend depth toward the text color. Default 82%.", - "value": "82%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-700", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 700. Controls blend depth toward the text color. Default 62%.", - "value": "62%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-800", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 800 (dark shade). Controls blend depth toward text. Default 38%.", - "value": "38%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-900", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for palette step 900 (very dark shade). Controls blend depth toward text. Default 18%.", - "value": "18%", - "aliasOf": null, - "registered": false, - "animatable": false, - "syntax": null, - "inherits": null, - "optional": false, - "layer": "slashed.tokens", - "sourceFiles": [ - "core/tokens.css" - ], - "bundles": [ - "full", - "optimal" - ] - }, - { - "name": "--sf-palette-mix-950", - "type": "token", - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "namespace": "palette", - "category": "Core tokens", - "area": "core", - "group": "Palette shade mix percentages", - "description": "Color-mix percentage for the darkest palette step (950). Controls how far step 950 blends toward the text color. Default 8%.", - "value": "8%", + "group": "Palette ramp lightness anchors", + "description": "Absolute OKLCH lightness the tint steps (50-400) pull toward; sets how light the lightest palette step can reach. Default 0.97.", + "value": "0.97", "aliasOf": null, "registered": false, "animatable": false, diff --git a/docs/api-index.md b/docs/api-index.md index a87508b9..6c94ff19 100644 --- a/docs/api-index.md +++ b/docs/api-index.md @@ -10,15 +10,15 @@ and a short description. The machine-readable companion (with all columns) is [registry.json](registry.json); for the tier contract see [architecture.md](architecture.md). -**1079 elements** — 754 tokens, 325 classes. +**1071 elements** — 746 tokens, 325 classes. | Tier | Count | Meaning | |---|---|---| | PUBLIC | 1018 | Everyday surface. SemVer-stable. | -| PUBLIC-ADVANCED | 60 | Same SemVer guarantee; niche/powerful. | +| PUBLIC-ADVANCED | 52 | Same SemVer guarantee; niche/powerful. | | INTERNAL | 1 | Implementation detail; may change without a major bump. | -## Tokens (754) +## Tokens (746) ### Component tokens (46) @@ -71,7 +71,7 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-field-padding-inline` | PUBLIC | consumption | field | `var(--sf-space-s)` | Horizontal (inline) inner padding for form field inputs. Reserved for a future .sf-field class — declared but not yet consumed by any shipped rule. | | `--sf-field-radius` | PUBLIC | consumption | field | `var(--sf-radius-m)` | Border radius for form field inputs. Defaults to --sf-radius-m; override to reshape all inputs at once. Reserved for a future .sf-field class — declared but not yet consumed by any shipped rule. | -### Core tokens (623) +### Core tokens (615) | Token | Tier | Role | Namespace | Default | Description | |---|---|---|---|---|---| @@ -117,17 +117,17 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-action` | PUBLIC | consumption | color | `light-dark(var(--sf-color-action-source-light), var(--sf-color-action-source-dark, oklch(from var(--sf-color-action-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | Primary interactive color. Applied to filled buttons, active indicators, and brand accent surfaces. | | `--sf-color-action--active` | PUBLIC | consumption | color | `var(--sf-color-action-xdark)` | Action color at pressed/active brightness. | | `--sf-color-action--hover` | PUBLIC | consumption | color | `var(--sf-color-action-darker)` | Action color at hover brightness. | -| `--sf-color-action-100` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))` | Very light action shade. Hover fills on white surfaces, badge backgrounds. | -| `--sf-color-action-200` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))` | Light action shade. Subtle fills and outlined badge backgrounds. | -| `--sf-color-action-300` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))` | Light-mid action shade. Borders on light backgrounds, low-emphasis fills. | -| `--sf-color-action-400` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))` | Mid-light action shade. Disabled state fills, decorative accents. | -| `--sf-color-action-50` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))` | Lightest action tint. Background fill for subtle action-tinted surfaces. | +| `--sf-color-action-100` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | Very light action shade. Hover fills on white surfaces, badge backgrounds. | +| `--sf-color-action-200` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | Light action shade. Subtle fills and outlined badge backgrounds. | +| `--sf-color-action-300` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | Light-mid action shade. Borders on light backgrounds, low-emphasis fills. | +| `--sf-color-action-400` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | Mid-light action shade. Disabled state fills, decorative accents. | +| `--sf-color-action-50` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | Lightest action tint. Background fill for subtle action-tinted surfaces. | | `--sf-color-action-500` | PUBLIC | consumption | color | `var(--sf-color-action)` | Mid action shade — the 'pure' hue. Accessible on both light and dark backgrounds. | -| `--sf-color-action-600` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))` | Mid-dark action shade. Text on light surfaces, icon fills. | -| `--sf-color-action-700` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))` | Dark action shade. Strong text and icon fills on light backgrounds. | -| `--sf-color-action-800` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))` | Very dark action shade. High-contrast text on white. | -| `--sf-color-action-900` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))` | Near-black action shade. Extreme contrast on white surfaces. | -| `--sf-color-action-950` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))` | Darkest action tint. Near-black for dark-theme surface accents. | +| `--sf-color-action-600` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | Mid-dark action shade. Text on light surfaces, icon fills. | +| `--sf-color-action-700` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | Dark action shade. Strong text and icon fills on light backgrounds. | +| `--sf-color-action-800` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | Very dark action shade. High-contrast text on white. | +| `--sf-color-action-900` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | Near-black action shade. Extreme contrast on white surfaces. | +| `--sf-color-action-950` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | Darkest action tint. Near-black for dark-theme surface accents. | | `--sf-color-action-a10` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) l c h / 0.10)` | 10% opacity action tint. Subtle hover or selected-row background. | | `--sf-color-action-a30` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) l c h / 0.30)` | 30% opacity action tint. | | `--sf-color-action-a5` | PUBLIC | consumption | color | `oklch(from var(--sf-color-action) l c h / 0.05)` | 5% opacity action tint. Barely-there hover highlight. | @@ -212,17 +212,17 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-neutral` | PUBLIC | consumption | color | `light-dark(var(--sf-color-neutral-source-light), var(--sf-color-neutral-source-dark, oklch(from var(--sf-color-neutral-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | Neutral interactive color for low-emphasis actions and tertiary buttons. | | `--sf-color-neutral--active` | PUBLIC | consumption | color | `var(--sf-color-neutral-xdark)` | Neutral color at pressed/active brightness. | | `--sf-color-neutral--hover` | PUBLIC | consumption | color | `var(--sf-color-neutral-darker)` | Neutral color at hover brightness. | -| `--sf-color-neutral-100` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))` | Very light neutral shade. | -| `--sf-color-neutral-200` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))` | Light neutral shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | -| `--sf-color-neutral-300` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))` | Light-mid neutral shade. | -| `--sf-color-neutral-400` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))` | Mid-light neutral shade. | -| `--sf-color-neutral-50` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))` | Lightest neutral tint. | +| `--sf-color-neutral-100` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | Very light neutral shade. | +| `--sf-color-neutral-200` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | Light neutral shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | +| `--sf-color-neutral-300` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | Light-mid neutral shade. | +| `--sf-color-neutral-400` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | Mid-light neutral shade. | +| `--sf-color-neutral-50` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | Lightest neutral tint. | | `--sf-color-neutral-500` | PUBLIC | consumption | color | `var(--sf-color-neutral)` | Mid neutral shade — the 'pure' hue. | -| `--sf-color-neutral-600` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))` | Mid-dark neutral shade. | -| `--sf-color-neutral-700` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))` | Dark neutral shade. | -| `--sf-color-neutral-800` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))` | Very dark neutral shade. | -| `--sf-color-neutral-900` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))` | Near-black neutral shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | -| `--sf-color-neutral-950` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))` | Darkest neutral tint. | +| `--sf-color-neutral-600` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | Mid-dark neutral shade. | +| `--sf-color-neutral-700` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | Dark neutral shade. | +| `--sf-color-neutral-800` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | Very dark neutral shade. | +| `--sf-color-neutral-900` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | Near-black neutral shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | +| `--sf-color-neutral-950` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | Darkest neutral tint. | | `--sf-color-neutral-a10` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) l c h / 0.10)` | 10% opacity neutral tint. | | `--sf-color-neutral-a30` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) l c h / 0.30)` | 30% opacity neutral tint. | | `--sf-color-neutral-a5` | PUBLIC | consumption | color | `oklch(from var(--sf-color-neutral) l c h / 0.05)` | 5% opacity neutral tint. | @@ -243,17 +243,17 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-primary` | PUBLIC | consumption | color | `light-dark(var(--sf-color-primary-source-light), var(--sf-color-primary-source-dark, oklch(from var(--sf-color-primary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | Primary brand palette color. Independent from --sf-color-action by default; override either source token to couple or separate brand and action roles. | | `--sf-color-primary--active` | PUBLIC | consumption | color | `var(--sf-color-primary-xdark)` | Primary color at pressed/active brightness. | | `--sf-color-primary--hover` | PUBLIC | consumption | color | `var(--sf-color-primary-darker)` | Primary color at hover brightness. | -| `--sf-color-primary-100` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))` | Very light primary shade. | -| `--sf-color-primary-200` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))` | Light primary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | -| `--sf-color-primary-300` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))` | Light-mid primary shade. | -| `--sf-color-primary-400` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))` | Mid-light primary shade. | -| `--sf-color-primary-50` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))` | Lightest primary tint. | +| `--sf-color-primary-100` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | Very light primary shade. | +| `--sf-color-primary-200` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | Light primary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | +| `--sf-color-primary-300` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | Light-mid primary shade. | +| `--sf-color-primary-400` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | Mid-light primary shade. | +| `--sf-color-primary-50` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | Lightest primary tint. | | `--sf-color-primary-500` | PUBLIC | consumption | color | `var(--sf-color-primary)` | Mid primary shade — the 'pure' hue. | -| `--sf-color-primary-600` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))` | Mid-dark primary shade. | -| `--sf-color-primary-700` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))` | Dark primary shade. | -| `--sf-color-primary-800` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))` | Very dark primary shade. | -| `--sf-color-primary-900` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))` | Near-black primary shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | -| `--sf-color-primary-950` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))` | Darkest primary tint. | +| `--sf-color-primary-600` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | Mid-dark primary shade. | +| `--sf-color-primary-700` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | Dark primary shade. | +| `--sf-color-primary-800` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | Very dark primary shade. | +| `--sf-color-primary-900` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | Near-black primary shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | +| `--sf-color-primary-950` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | Darkest primary tint. | | `--sf-color-primary-a10` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) l c h / 0.10)` | 10% opacity primary tint. | | `--sf-color-primary-a30` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) l c h / 0.30)` | 30% opacity primary tint. | | `--sf-color-primary-a5` | PUBLIC | consumption | color | `oklch(from var(--sf-color-primary) l c h / 0.05)` | 5% opacity primary tint. | @@ -275,17 +275,17 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-secondary` | PUBLIC | consumption | color | `light-dark(var(--sf-color-secondary-source-light), var(--sf-color-secondary-source-dark, oklch(from var(--sf-color-secondary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | Raw secondary palette token for the secondary brand color. | | `--sf-color-secondary--active` | PUBLIC | consumption | color | `var(--sf-color-secondary-xdark)` | Secondary color at pressed/active brightness. | | `--sf-color-secondary--hover` | PUBLIC | consumption | color | `var(--sf-color-secondary-darker)` | Secondary color at hover brightness. | -| `--sf-color-secondary-100` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))` | Very light secondary shade. | -| `--sf-color-secondary-200` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))` | Light secondary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | -| `--sf-color-secondary-300` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))` | Light-mid secondary shade. | -| `--sf-color-secondary-400` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))` | Mid-light secondary shade. | -| `--sf-color-secondary-50` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))` | Lightest secondary tint. | +| `--sf-color-secondary-100` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | Very light secondary shade. | +| `--sf-color-secondary-200` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | Light secondary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | +| `--sf-color-secondary-300` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | Light-mid secondary shade. | +| `--sf-color-secondary-400` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | Mid-light secondary shade. | +| `--sf-color-secondary-50` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | Lightest secondary tint. | | `--sf-color-secondary-500` | PUBLIC | consumption | color | `var(--sf-color-secondary)` | Mid secondary shade — the 'pure' hue. | -| `--sf-color-secondary-600` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))` | Mid-dark secondary shade. | -| `--sf-color-secondary-700` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))` | Dark secondary shade. | -| `--sf-color-secondary-800` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))` | Very dark secondary shade. | -| `--sf-color-secondary-900` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))` | Near-black secondary shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | -| `--sf-color-secondary-950` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))` | Darkest secondary tint. | +| `--sf-color-secondary-600` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | Mid-dark secondary shade. | +| `--sf-color-secondary-700` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | Dark secondary shade. | +| `--sf-color-secondary-800` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | Very dark secondary shade. | +| `--sf-color-secondary-900` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | Near-black secondary shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | +| `--sf-color-secondary-950` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | Darkest secondary tint. | | `--sf-color-secondary-a10` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) l c h / 0.10)` | 10% opacity secondary tint. | | `--sf-color-secondary-a30` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) l c h / 0.30)` | 30% opacity secondary tint. | | `--sf-color-secondary-a5` | PUBLIC | consumption | color | `oklch(from var(--sf-color-secondary) l c h / 0.05)` | 5% opacity secondary tint. | @@ -317,17 +317,17 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-tertiary` | PUBLIC | consumption | color | `light-dark(var(--sf-color-tertiary-source-light), var(--sf-color-tertiary-source-dark, oklch(from var(--sf-color-tertiary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | Raw tertiary palette token for the third brand color. | | `--sf-color-tertiary--active` | PUBLIC | consumption | color | `var(--sf-color-tertiary-xdark)` | Tertiary color at pressed/active brightness. | | `--sf-color-tertiary--hover` | PUBLIC | consumption | color | `var(--sf-color-tertiary-darker)` | Tertiary color at hover brightness. | -| `--sf-color-tertiary-100` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))` | Very light tertiary shade. | -| `--sf-color-tertiary-200` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))` | Light tertiary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | -| `--sf-color-tertiary-300` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))` | Light-mid tertiary shade. | -| `--sf-color-tertiary-400` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))` | Mid-light tertiary shade. | -| `--sf-color-tertiary-50` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))` | Lightest tertiary tint. | +| `--sf-color-tertiary-100` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | Very light tertiary shade. | +| `--sf-color-tertiary-200` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | Light tertiary shade at step 200 on the numeric scale. Subtle fills and outlined badge backgrounds. | +| `--sf-color-tertiary-300` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | Light-mid tertiary shade. | +| `--sf-color-tertiary-400` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | Mid-light tertiary shade. | +| `--sf-color-tertiary-50` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | Lightest tertiary tint. | | `--sf-color-tertiary-500` | PUBLIC | consumption | color | `var(--sf-color-tertiary)` | Mid tertiary shade — the 'pure' hue. | -| `--sf-color-tertiary-600` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))` | Mid-dark tertiary shade. | -| `--sf-color-tertiary-700` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))` | Dark tertiary shade. | -| `--sf-color-tertiary-800` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))` | Very dark tertiary shade. | -| `--sf-color-tertiary-900` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))` | Near-black tertiary shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | -| `--sf-color-tertiary-950` | PUBLIC | consumption | color | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))` | Darkest tertiary tint. | +| `--sf-color-tertiary-600` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | Mid-dark tertiary shade. | +| `--sf-color-tertiary-700` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | Dark tertiary shade. | +| `--sf-color-tertiary-800` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | Very dark tertiary shade. | +| `--sf-color-tertiary-900` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | Near-black tertiary shade at step 900 on the numeric scale. Extreme contrast on light surfaces. | +| `--sf-color-tertiary-950` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | Darkest tertiary tint. | | `--sf-color-tertiary-a10` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) l c h / 0.10)` | 10% opacity tertiary tint. | | `--sf-color-tertiary-a30` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) l c h / 0.30)` | 30% opacity tertiary tint. | | `--sf-color-tertiary-a5` | PUBLIC | consumption | color | `oklch(from var(--sf-color-tertiary) l c h / 0.05)` | 5% opacity tertiary tint. | @@ -518,16 +518,8 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-opacity-disabled` | PUBLIC | knob | opacity | `0.45` | Opacity for disabled UI elements (typically 0.4–0.5). | | `--sf-opacity-muted` | PUBLIC | knob | opacity | `0.5` | General de-emphasis opacity for secondary content, ghost elements, or non-primary layers. Default 0.5. | | `--sf-optical-sizing` | PUBLIC-ADVANCED | knob | optical | `auto` | CSS font-optical-sizing value. 'auto' lets the browser optimize letterforms for the rendered size. Set 'none' to disable optical sizing. | -| `--sf-palette-mix-100` | PUBLIC-ADVANCED | knob | palette | `8%` | Color-mix percentage for palette step 100. Controls blend depth toward the surface. Default 8%. | -| `--sf-palette-mix-200` | PUBLIC-ADVANCED | knob | palette | `20%` | Color-mix percentage for palette step 200. Controls blend depth toward the surface. Default 20%. | -| `--sf-palette-mix-300` | PUBLIC-ADVANCED | knob | palette | `40%` | Color-mix percentage for palette step 300. Controls blend depth toward the surface. Default 40%. | -| `--sf-palette-mix-400` | PUBLIC-ADVANCED | knob | palette | `65%` | Color-mix percentage for palette step 400 (near-mid tint). Controls blend depth. Default 65%. | -| `--sf-palette-mix-50` | PUBLIC-ADVANCED | knob | palette | `4%` | Color-mix percentage for the lightest palette step (50). Controls how far step 50 blends toward the surface. Default 4%. | -| `--sf-palette-mix-600` | PUBLIC-ADVANCED | knob | palette | `82%` | Color-mix percentage for palette step 600 (near-mid shade). Controls blend depth toward the text color. Default 82%. | -| `--sf-palette-mix-700` | PUBLIC-ADVANCED | knob | palette | `62%` | Color-mix percentage for palette step 700. Controls blend depth toward the text color. Default 62%. | -| `--sf-palette-mix-800` | PUBLIC-ADVANCED | knob | palette | `38%` | Color-mix percentage for palette step 800 (dark shade). Controls blend depth toward text. Default 38%. | -| `--sf-palette-mix-900` | PUBLIC-ADVANCED | knob | palette | `18%` | Color-mix percentage for palette step 900 (very dark shade). Controls blend depth toward text. Default 18%. | -| `--sf-palette-mix-950` | PUBLIC-ADVANCED | knob | palette | `8%` | Color-mix percentage for the darkest palette step (950). Controls how far step 950 blends toward the text color. Default 8%. | +| `--sf-palette-shade-l` | PUBLIC-ADVANCED | knob | palette | `0.1` | Absolute OKLCH lightness the shade steps (600-950) pull toward; sets how dark the darkest palette step can reach. Default 0.1. | +| `--sf-palette-tint-l` | PUBLIC-ADVANCED | knob | palette | `0.97` | Absolute OKLCH lightness the tint steps (50-400) pull toward; sets how light the lightest palette step can reach. Default 0.97. | | `--sf-print-base-size` | PUBLIC-ADVANCED | knob | print | `11pt` | Base font size for @media print stylesheets. Default 11pt. Override on :root to adjust printed body text size. | | `--sf-print-page-margin` | PUBLIC-ADVANCED | knob | print | `2cm` | Page margin for printed output. Default 2cm. Maps to @page margin. | | `--sf-print-page-size` | PUBLIC-ADVANCED | knob | print | `a4` | Target paper size for printing. Default 'a4'. Maps to @page size. Common values: a4, letter, legal. | diff --git a/docs/llm-guide.md b/docs/llm-guide.md index d86af41d..d3373e40 100644 --- a/docs/llm-guide.md +++ b/docs/llm-guide.md @@ -1,6 +1,6 @@ # Slashed Framework — LLM Reference Guide -> Version: **0.7.18** · Tokens: **754** · Prefix: `--sf-` +> Version: **0.7.18** · Tokens: **746** · Prefix: `--sf-` --- @@ -407,21 +407,13 @@ Examples: `--sf-color-danger-subtle`, `--sf-color-warning-strong`. /* Alpha variants */ --sf-color-{family}-a5 / -a10 / -a30 / -a50 / -a80 -/* PUBLIC-ADVANCED: ramp shape for the five mid-tone brand families */ ---sf-palette-mix-50: 4%; /* How far step 50 blends toward surface */ ---sf-palette-mix-100: 8%; /* … */ ---sf-palette-mix-200: 20%; ---sf-palette-mix-300: 40%; ---sf-palette-mix-400: 65%; -/* step 500 is the source color itself; no separate mix knob exists */ ---sf-palette-mix-600: 82%; ---sf-palette-mix-700: 62%; ---sf-palette-mix-800: 38%; ---sf-palette-mix-900: 18%; ---sf-palette-mix-950: 8%; /* deepest step */ +/* PUBLIC-ADVANCED: ramp lightness anchors for the five mid-tone families */ +--sf-palette-tint-l: 0.97; /* absolute OKLCH L the tint steps (50–400) reach toward */ +--sf-palette-shade-l: 0.1; /* absolute OKLCH L the shade steps (600–950) reach toward */ +/* step 500 is the source color itself; per-step pull + chroma taper are baked in */ ``` -All six families honour the 50=Lightest / 950=Darkest contract. The five mid-tone brand families (`primary`, `secondary`, `tertiary`, `action`, `neutral`) are generated with `color-mix` anchored to `--sf-color-surface` and `--sf-color-text` as the two poles. **`base` uses fixed OKLCH lightness steps** (0.97 at step 50 → 0.06 at step 950) preserving the source hue and chroma. The `--sf-palette-mix-*` knobs do not affect `base`. Because it is an absolute scale, `base` deliberately has **no relative aliases** (`-lighter` / `-darker` / `-xlight` / `-superlight` / …) — those exist only on the five mid-tone brand families, where the source sits in the middle of the ramp. For mode-adaptive surface adjustments on base-coloured elements use `--sf-color-inset` / `--sf-color-raised` / `--sf-color-bg` or the `--sf-color-base--hover` / `--sf-color-base--active` tokens (which use relative oklch offsets and adapt to both modes automatically). +All six families honour the 50=Lightest / 950=Darkest contract. The five mid-tone brand families (`primary`, `secondary`, `tertiary`, `action`, `neutral`) are generated in OKLCH by pulling the family colour's own lightness a fixed fraction toward an **absolute** target — `--sf-palette-tint-l` for tints (50–400), `--sf-palette-shade-l` for shades (600–950) — clamped (`max()`/`min()`) so a tint can never end darker than the base nor a shade lighter. Because the poles are absolute (not the theme's `--sf-color-surface` / `--sf-color-text`), the ramp stays monotonic light→dark for **any** source colour and any anchor configuration — it cannot fold into a "U". **`base` uses fixed OKLCH lightness steps** (0.97 at step 50 → 0.06 at step 950) preserving the source hue and chroma; it does not read the `--sf-palette-*-l` knobs. Because it is an absolute scale, `base` deliberately has **no relative aliases** (`-lighter` / `-darker` / `-xlight` / `-superlight` / …) — those exist only on the five mid-tone brand families, where the source sits in the middle of the ramp. For mode-adaptive surface adjustments on base-coloured elements use `--sf-color-inset` / `--sf-color-raised` / `--sf-color-bg` or the `--sf-color-base--hover` / `--sf-color-base--active` tokens (which use relative oklch offsets and adapt to both modes automatically). Status families (success/warning/info/danger) have **no numeric scale** — use their triplets. @@ -1310,15 +1302,13 @@ Example — if your primary brand color has L ≈ 0.6 and you prefer white text: Each step up the type scale subtracts `step-index × taper` from that step's default line-height. -### 11.5 Palette mix percentages +### 11.5 Palette ramp lightness anchors ```css -/* Shape of the 50–950 numeric palette ramp */ ---sf-palette-mix-50: 4% /* how far step 50 blends toward surface */ ---sf-palette-mix-100: 8% ---sf-palette-mix-200: 20% ---sf-palette-mix-300: 40% -/* … similarly for all steps */ +/* Absolute OKLCH lightness poles the 50–950 numeric ramp reaches toward */ +--sf-palette-tint-l: 0.97 /* how light the lightest step (50) can reach */ +--sf-palette-shade-l: 0.1 /* how dark the darkest step (950) can reach */ +/* per-step pull fraction + chroma taper are baked into each family */ ``` ### 11.6 Scroll and mask diff --git a/docs/registry.json b/docs/registry.json index 63394ad6..44f78c39 100644 --- a/docs/registry.json +++ b/docs/registry.json @@ -19,7 +19,7 @@ "optional/utilities.css" ], "counts": { - "tokens": 754, + "tokens": 746, "sf_classes": 289, "is_classes": 28 } @@ -562,16 +562,8 @@ "--sf-opacity-muted", "--sf-optical-sizing", "--sf-overlap-pull", - "--sf-palette-mix-100", - "--sf-palette-mix-200", - "--sf-palette-mix-300", - "--sf-palette-mix-400", - "--sf-palette-mix-50", - "--sf-palette-mix-600", - "--sf-palette-mix-700", - "--sf-palette-mix-800", - "--sf-palette-mix-900", - "--sf-palette-mix-950", + "--sf-palette-shade-l", + "--sf-palette-tint-l", "--sf-print-base-size", "--sf-print-page-margin", "--sf-print-page-size", diff --git a/docs/token-annotations.json b/docs/token-annotations.json index ba6aef20..e2ae2770 100644 --- a/docs/token-annotations.json +++ b/docs/token-annotations.json @@ -804,16 +804,8 @@ "--sf-density": "Compact ↔ comfortable dial for interactive control geometry (the --sf-size-* rung ladder). Default 1; below 1 packs controls tighter (dashboards, data tables), above 1 loosens them. A deliberate design/user choice, not a viewport response — orthogonal to --sf-space-scale (whitespace) and --sf-section-scale (section rhythm). The --sf-touch-target accessibility floor is independent, so a small value can't shrink native controls below the WCAG target. Like the other global multipliers it is a :root dial (the size ladder is computed at :root and inherits, so nested overrides don't retroactively rescale it).", "--sf-text-scale": "Global type-size multiplier. Scales the entire fluid type scale. 1.08 gives noticeably larger body text without breaking layout.", "--sf-text-display-scale": "Multiplier applied only to the display/hero type scale (--sf-text-display-*). Tune headline impact independently of body text.", - "--sf-palette-mix-50": "Color-mix percentage for the lightest palette step (50). Controls how far step 50 blends toward the surface. Default 4%.", - "--sf-palette-mix-100": "Color-mix percentage for palette step 100. Controls blend depth toward the surface. Default 8%.", - "--sf-palette-mix-200": "Color-mix percentage for palette step 200. Controls blend depth toward the surface. Default 20%.", - "--sf-palette-mix-300": "Color-mix percentage for palette step 300. Controls blend depth toward the surface. Default 40%.", - "--sf-palette-mix-400": "Color-mix percentage for palette step 400 (near-mid tint). Controls blend depth. Default 65%.", - "--sf-palette-mix-600": "Color-mix percentage for palette step 600 (near-mid shade). Controls blend depth toward the text color. Default 82%.", - "--sf-palette-mix-700": "Color-mix percentage for palette step 700. Controls blend depth toward the text color. Default 62%.", - "--sf-palette-mix-800": "Color-mix percentage for palette step 800 (dark shade). Controls blend depth toward text. Default 38%.", - "--sf-palette-mix-900": "Color-mix percentage for palette step 900 (very dark shade). Controls blend depth toward text. Default 18%.", - "--sf-palette-mix-950": "Color-mix percentage for the darkest palette step (950). Controls how far step 950 blends toward the text color. Default 8%.", + "--sf-palette-tint-l": "Absolute OKLCH lightness the tint steps (50-400) pull toward; sets how light the lightest palette step can reach. Default 0.97.", + "--sf-palette-shade-l": "Absolute OKLCH lightness the shade steps (600-950) pull toward; sets how dark the darkest palette step can reach. Default 0.1.", "--sf-print-base-size": "Base font size for @media print stylesheets. Default 11pt. Override on :root to adjust printed body text size.", "--sf-print-page-margin": "Page margin for printed output. Default 2cm. Maps to @page margin.", "--sf-print-page-size": "Target paper size for printing. Default 'a4'. Maps to @page size. Common values: a4, letter, legal.", diff --git a/docs/token-index.json b/docs/token-index.json index 360cae07..401c896f 100644 --- a/docs/token-index.json +++ b/docs/token-index.json @@ -8,14 +8,14 @@ "optional/tokens.components.css" ], "counts": { - "tokens": 754, + "tokens": 746, "by_tier": { "PUBLIC": 693, - "PUBLIC-ADVANCED": 60, + "PUBLIC-ADVANCED": 52, "INTERNAL": 1 }, "by_role": { - "knob": 265, + "knob": 257, "consumption": 489 } } @@ -883,7 +883,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)" }, "--sf-color-action-200": { "tier": "PUBLIC", @@ -891,7 +891,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)" }, "--sf-color-action-300": { "tier": "PUBLIC", @@ -899,7 +899,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)" }, "--sf-color-action-400": { "tier": "PUBLIC", @@ -907,7 +907,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)" }, "--sf-color-action-50": { "tier": "PUBLIC", @@ -915,7 +915,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)" }, "--sf-color-action-500": { "tier": "PUBLIC", @@ -931,7 +931,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)" }, "--sf-color-action-700": { "tier": "PUBLIC", @@ -939,7 +939,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)" }, "--sf-color-action-800": { "tier": "PUBLIC", @@ -947,7 +947,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)" }, "--sf-color-action-900": { "tier": "PUBLIC", @@ -955,7 +955,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)" }, "--sf-color-action-950": { "tier": "PUBLIC", @@ -963,7 +963,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)" }, "--sf-color-action-a10": { "tier": "PUBLIC", @@ -1643,7 +1643,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)" }, "--sf-color-neutral-200": { "tier": "PUBLIC", @@ -1651,7 +1651,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)" }, "--sf-color-neutral-300": { "tier": "PUBLIC", @@ -1659,7 +1659,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)" }, "--sf-color-neutral-400": { "tier": "PUBLIC", @@ -1667,7 +1667,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)" }, "--sf-color-neutral-50": { "tier": "PUBLIC", @@ -1675,7 +1675,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)" }, "--sf-color-neutral-500": { "tier": "PUBLIC", @@ -1691,7 +1691,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)" }, "--sf-color-neutral-700": { "tier": "PUBLIC", @@ -1699,7 +1699,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)" }, "--sf-color-neutral-800": { "tier": "PUBLIC", @@ -1707,7 +1707,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)" }, "--sf-color-neutral-900": { "tier": "PUBLIC", @@ -1715,7 +1715,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)" }, "--sf-color-neutral-950": { "tier": "PUBLIC", @@ -1723,7 +1723,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)" }, "--sf-color-neutral-a10": { "tier": "PUBLIC", @@ -1891,7 +1891,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)" }, "--sf-color-primary-200": { "tier": "PUBLIC", @@ -1899,7 +1899,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)" }, "--sf-color-primary-300": { "tier": "PUBLIC", @@ -1907,7 +1907,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)" }, "--sf-color-primary-400": { "tier": "PUBLIC", @@ -1915,7 +1915,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)" }, "--sf-color-primary-50": { "tier": "PUBLIC", @@ -1923,7 +1923,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)" }, "--sf-color-primary-500": { "tier": "PUBLIC", @@ -1939,7 +1939,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)" }, "--sf-color-primary-700": { "tier": "PUBLIC", @@ -1947,7 +1947,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)" }, "--sf-color-primary-800": { "tier": "PUBLIC", @@ -1955,7 +1955,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)" }, "--sf-color-primary-900": { "tier": "PUBLIC", @@ -1963,7 +1963,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)" }, "--sf-color-primary-950": { "tier": "PUBLIC", @@ -1971,7 +1971,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)" }, "--sf-color-primary-a10": { "tier": "PUBLIC", @@ -2147,7 +2147,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)" }, "--sf-color-secondary-200": { "tier": "PUBLIC", @@ -2155,7 +2155,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)" }, "--sf-color-secondary-300": { "tier": "PUBLIC", @@ -2163,7 +2163,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)" }, "--sf-color-secondary-400": { "tier": "PUBLIC", @@ -2171,7 +2171,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)" }, "--sf-color-secondary-50": { "tier": "PUBLIC", @@ -2179,7 +2179,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)" }, "--sf-color-secondary-500": { "tier": "PUBLIC", @@ -2195,7 +2195,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)" }, "--sf-color-secondary-700": { "tier": "PUBLIC", @@ -2203,7 +2203,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)" }, "--sf-color-secondary-800": { "tier": "PUBLIC", @@ -2211,7 +2211,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)" }, "--sf-color-secondary-900": { "tier": "PUBLIC", @@ -2219,7 +2219,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)" }, "--sf-color-secondary-950": { "tier": "PUBLIC", @@ -2227,7 +2227,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)" }, "--sf-color-secondary-a10": { "tier": "PUBLIC", @@ -2483,7 +2483,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)" }, "--sf-color-tertiary-200": { "tier": "PUBLIC", @@ -2491,7 +2491,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)" }, "--sf-color-tertiary-300": { "tier": "PUBLIC", @@ -2499,7 +2499,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)" }, "--sf-color-tertiary-400": { "tier": "PUBLIC", @@ -2507,7 +2507,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)" }, "--sf-color-tertiary-50": { "tier": "PUBLIC", @@ -2515,7 +2515,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))" + "value": "oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)" }, "--sf-color-tertiary-500": { "tier": "PUBLIC", @@ -2531,7 +2531,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)" }, "--sf-color-tertiary-700": { "tier": "PUBLIC", @@ -2539,7 +2539,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)" }, "--sf-color-tertiary-800": { "tier": "PUBLIC", @@ -2547,7 +2547,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)" }, "--sf-color-tertiary-900": { "tier": "PUBLIC", @@ -2555,7 +2555,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)" }, "--sf-color-tertiary-950": { "tier": "PUBLIC", @@ -2563,7 +2563,7 @@ "files": [ "core/tokens.css" ], - "value": "color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))" + "value": "oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)" }, "--sf-color-tertiary-a10": { "tier": "PUBLIC", @@ -4317,85 +4317,21 @@ ], "value": "var(--sf-space-xl)" }, - "--sf-palette-mix-100": { + "--sf-palette-shade-l": { "tier": "PUBLIC-ADVANCED", "role": "knob", "files": [ "core/tokens.css" ], - "value": "8%" + "value": "0.1" }, - "--sf-palette-mix-200": { + "--sf-palette-tint-l": { "tier": "PUBLIC-ADVANCED", "role": "knob", "files": [ "core/tokens.css" ], - "value": "20%" - }, - "--sf-palette-mix-300": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "40%" - }, - "--sf-palette-mix-400": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "65%" - }, - "--sf-palette-mix-50": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "4%" - }, - "--sf-palette-mix-600": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "82%" - }, - "--sf-palette-mix-700": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "62%" - }, - "--sf-palette-mix-800": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "38%" - }, - "--sf-palette-mix-900": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "18%" - }, - "--sf-palette-mix-950": { - "tier": "PUBLIC-ADVANCED", - "role": "knob", - "files": [ - "core/tokens.css" - ], - "value": "8%" + "value": "0.97" }, "--sf-print-base-size": { "tier": "PUBLIC-ADVANCED", diff --git a/docs/token-index.md b/docs/token-index.md index d00e8582..7cf95e8e 100644 --- a/docs/token-index.md +++ b/docs/token-index.md @@ -8,12 +8,12 @@ A cross-reference of every `--sf-*` custom property by **source file** and for the flat name list see [registry.json](registry.json); for the tier contract and naming rules see [architecture.md](architecture.md). -**754 tokens** (deduplicated by name across the 4 token source files). +**746 tokens** (deduplicated by name across the 4 token source files). | Tier | Count | Meaning | |---|---|---| | PUBLIC | 693 | Everyday knobs. SemVer-stable. | -| PUBLIC-ADVANCED | 60 | Same SemVer guarantee; niche/powerful. | +| PUBLIC-ADVANCED | 52 | Same SemVer guarantee; niche/powerful. | | INTERNAL | 1 | Implementation detail; may change without a major bump. | Every token also carries a **role** — an orthogonal, SemVer-neutral hint about @@ -22,7 +22,7 @@ declared value (a value that references `var(--sf-…)` is a derived output): | Role | Count | Meaning | |---|---|---| -| knob | 265 | Input you **set** to configure the system (a literal primitive: length, number, colour literal, keyword, font stack, easing curve …). | +| knob | 257 | Input you **set** to configure the system (a literal primitive: length, number, colour literal, keyword, font stack, easing curve …). | | consumption | 489 | Ready-to-use output you **read**; derived from other tokens via `var(--sf-…)` (incl. `light-dark()`/`oklch(from …)`/`color-mix()`). | ## INTERNAL tokens @@ -53,16 +53,8 @@ declared value (a value that references `var(--sf-…)` is a derived output): - `--sf-mask-scrim-start` - `--sf-motion-scale` - `--sf-optical-sizing` -- `--sf-palette-mix-100` -- `--sf-palette-mix-200` -- `--sf-palette-mix-300` -- `--sf-palette-mix-400` -- `--sf-palette-mix-50` -- `--sf-palette-mix-600` -- `--sf-palette-mix-700` -- `--sf-palette-mix-800` -- `--sf-palette-mix-900` -- `--sf-palette-mix-950` +- `--sf-palette-shade-l` +- `--sf-palette-tint-l` - `--sf-print-base-size` - `--sf-print-page-margin` - `--sf-print-page-size` @@ -203,17 +195,17 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-action` | PUBLIC | consumption | Core | `light-dark(var(--sf-color-action-source-light), var(--sf-color-action-source-dark, oklch(from var(--sf-color-action-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-action--active` | PUBLIC | consumption | Core | `var(--sf-color-action-xdark)` | | `--sf-color-action--hover` | PUBLIC | consumption | Core | `var(--sf-color-action-darker)` | -| `--sf-color-action-100` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-action-200` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-action-300` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-action-400` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-action-50` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-action-100` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-action-200` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-action-300` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-action-400` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-action-50` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-action-500` | PUBLIC | consumption | Core | `var(--sf-color-action)` | -| `--sf-color-action-600` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-action-700` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-action-800` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-action-900` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-action-950` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-action-600` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-action-700` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-action-800` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-action-900` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-action-950` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-action-a10` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) l c h / 0.10)` | | `--sf-color-action-a30` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) l c h / 0.30)` | | `--sf-color-action-a5` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-action) l c h / 0.05)` | @@ -298,17 +290,17 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-neutral` | PUBLIC | consumption | Core | `light-dark(var(--sf-color-neutral-source-light), var(--sf-color-neutral-source-dark, oklch(from var(--sf-color-neutral-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-neutral--active` | PUBLIC | consumption | Core | `var(--sf-color-neutral-xdark)` | | `--sf-color-neutral--hover` | PUBLIC | consumption | Core | `var(--sf-color-neutral-darker)` | -| `--sf-color-neutral-100` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-neutral-200` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-neutral-300` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-neutral-400` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-neutral-50` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-neutral-100` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-neutral-200` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-neutral-300` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-neutral-400` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-neutral-50` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-neutral-500` | PUBLIC | consumption | Core | `var(--sf-color-neutral)` | -| `--sf-color-neutral-600` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-neutral-700` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-neutral-800` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-neutral-900` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-neutral-950` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-neutral-600` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-neutral-700` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-neutral-800` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-neutral-900` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-neutral-950` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-neutral-a10` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) l c h / 0.10)` | | `--sf-color-neutral-a30` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) l c h / 0.30)` | | `--sf-color-neutral-a5` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-neutral) l c h / 0.05)` | @@ -329,17 +321,17 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-primary` | PUBLIC | consumption | Core | `light-dark(var(--sf-color-primary-source-light), var(--sf-color-primary-source-dark, oklch(from var(--sf-color-primary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-primary--active` | PUBLIC | consumption | Core | `var(--sf-color-primary-xdark)` | | `--sf-color-primary--hover` | PUBLIC | consumption | Core | `var(--sf-color-primary-darker)` | -| `--sf-color-primary-100` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-primary-200` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-primary-300` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-primary-400` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-primary-50` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-primary-100` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-primary-200` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-primary-300` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-primary-400` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-primary-50` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-primary-500` | PUBLIC | consumption | Core | `var(--sf-color-primary)` | -| `--sf-color-primary-600` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-primary-700` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-primary-800` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-primary-900` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-primary-950` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-primary-600` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-primary-700` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-primary-800` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-primary-900` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-primary-950` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-primary-a10` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) l c h / 0.10)` | | `--sf-color-primary-a30` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) l c h / 0.30)` | | `--sf-color-primary-a5` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-primary) l c h / 0.05)` | @@ -361,17 +353,17 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-secondary` | PUBLIC | consumption | Core | `light-dark(var(--sf-color-secondary-source-light), var(--sf-color-secondary-source-dark, oklch(from var(--sf-color-secondary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-secondary--active` | PUBLIC | consumption | Core | `var(--sf-color-secondary-xdark)` | | `--sf-color-secondary--hover` | PUBLIC | consumption | Core | `var(--sf-color-secondary-darker)` | -| `--sf-color-secondary-100` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-secondary-200` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-secondary-300` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-secondary-400` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-secondary-50` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-secondary-100` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-secondary-200` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-secondary-300` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-secondary-400` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-secondary-50` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-secondary-500` | PUBLIC | consumption | Core | `var(--sf-color-secondary)` | -| `--sf-color-secondary-600` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-secondary-700` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-secondary-800` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-secondary-900` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-secondary-950` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-secondary-600` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-secondary-700` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-secondary-800` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-secondary-900` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-secondary-950` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-secondary-a10` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) l c h / 0.10)` | | `--sf-color-secondary-a30` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) l c h / 0.30)` | | `--sf-color-secondary-a5` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-secondary) l c h / 0.05)` | @@ -403,17 +395,17 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-tertiary` | PUBLIC | consumption | Core | `light-dark(var(--sf-color-tertiary-source-light), var(--sf-color-tertiary-source-dark, oklch(from var(--sf-color-tertiary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-tertiary--active` | PUBLIC | consumption | Core | `var(--sf-color-tertiary-xdark)` | | `--sf-color-tertiary--hover` | PUBLIC | consumption | Core | `var(--sf-color-tertiary-darker)` | -| `--sf-color-tertiary-100` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-tertiary-200` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-tertiary-300` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-tertiary-400` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-tertiary-50` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-tertiary-100` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-tertiary-200` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-tertiary-300` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-tertiary-400` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-tertiary-50` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-tertiary-500` | PUBLIC | consumption | Core | `var(--sf-color-tertiary)` | -| `--sf-color-tertiary-600` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-tertiary-700` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-tertiary-800` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-tertiary-900` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-tertiary-950` | PUBLIC | consumption | Core | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-tertiary-600` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-tertiary-700` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-tertiary-800` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-tertiary-900` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-tertiary-950` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-tertiary-a10` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) l c h / 0.10)` | | `--sf-color-tertiary-a30` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) l c h / 0.30)` | | `--sf-color-tertiary-a5` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-tertiary) l c h / 0.05)` | @@ -633,16 +625,8 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-opacity-muted` | PUBLIC | knob | Core | `0.5` | | `--sf-optical-sizing` | PUBLIC-ADVANCED | knob | Core | `auto` | | `--sf-overlap-pull` | PUBLIC | consumption | Macros | `var(--sf-space-xl)` | -| `--sf-palette-mix-100` | PUBLIC-ADVANCED | knob | Core | `8%` | -| `--sf-palette-mix-200` | PUBLIC-ADVANCED | knob | Core | `20%` | -| `--sf-palette-mix-300` | PUBLIC-ADVANCED | knob | Core | `40%` | -| `--sf-palette-mix-400` | PUBLIC-ADVANCED | knob | Core | `65%` | -| `--sf-palette-mix-50` | PUBLIC-ADVANCED | knob | Core | `4%` | -| `--sf-palette-mix-600` | PUBLIC-ADVANCED | knob | Core | `82%` | -| `--sf-palette-mix-700` | PUBLIC-ADVANCED | knob | Core | `62%` | -| `--sf-palette-mix-800` | PUBLIC-ADVANCED | knob | Core | `38%` | -| `--sf-palette-mix-900` | PUBLIC-ADVANCED | knob | Core | `18%` | -| `--sf-palette-mix-950` | PUBLIC-ADVANCED | knob | Core | `8%` | +| `--sf-palette-shade-l` | PUBLIC-ADVANCED | knob | Core | `0.1` | +| `--sf-palette-tint-l` | PUBLIC-ADVANCED | knob | Core | `0.97` | | `--sf-print-base-size` | PUBLIC-ADVANCED | knob | Core | `11pt` | | `--sf-print-page-margin` | PUBLIC-ADVANCED | knob | Core | `2cm` | | `--sf-print-page-size` | PUBLIC-ADVANCED | knob | Core | `a4` | diff --git a/docs/tokens.md b/docs/tokens.md index 938d4f73..8fdf67f5 100644 --- a/docs/tokens.md +++ b/docs/tokens.md @@ -3,7 +3,7 @@ > **Generated** from source by `scripts/gen-token-reference.js` — > run `npm run docs:tokens` to refresh. Do not edit by hand. -**754 tokens.** Every `--sf-*` custom property and its default value, grouped by source file. +**746 tokens.** Every `--sf-*` custom property and its default value, grouped by source file. If a token is defined in multiple files, it is listed once per section — so this count can be higher than `docs/registry.json` (which deduplicates by name). See [architecture.md](architecture.md) for the PUBLIC / PUBLIC-ADVANCED / INTERNAL @@ -13,7 +13,7 @@ rebrand workflow. ## Core tokens (`core/tokens.css`) -623 tokens. +615 tokens. | Token | Default | |---|---| @@ -59,17 +59,17 @@ rebrand workflow. | `--sf-color-action` | `light-dark(var(--sf-color-action-source-light), var(--sf-color-action-source-dark, oklch(from var(--sf-color-action-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-action--active` | `var(--sf-color-action-xdark)` | | `--sf-color-action--hover` | `var(--sf-color-action-darker)` | -| `--sf-color-action-100` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-action-200` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-action-300` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-action-400` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-action-50` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-action-100` | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-action-200` | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-action-300` | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-action-400` | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-action-50` | `oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-action-500` | `var(--sf-color-action)` | -| `--sf-color-action-600` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-action-700` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-action-800` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-action-900` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-action-950` | `color-mix(in oklab, var(--sf-color-action) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-action-600` | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-action-700` | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-action-800` | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-action-900` | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-action-950` | `oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-action-a10` | `oklch(from var(--sf-color-action) l c h / 0.10)` | | `--sf-color-action-a30` | `oklch(from var(--sf-color-action) l c h / 0.30)` | | `--sf-color-action-a5` | `oklch(from var(--sf-color-action) l c h / 0.05)` | @@ -154,17 +154,17 @@ rebrand workflow. | `--sf-color-neutral` | `light-dark(var(--sf-color-neutral-source-light), var(--sf-color-neutral-source-dark, oklch(from var(--sf-color-neutral-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-neutral--active` | `var(--sf-color-neutral-xdark)` | | `--sf-color-neutral--hover` | `var(--sf-color-neutral-darker)` | -| `--sf-color-neutral-100` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-neutral-200` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-neutral-300` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-neutral-400` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-neutral-50` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-neutral-100` | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-neutral-200` | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-neutral-300` | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-neutral-400` | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-neutral-50` | `oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-neutral-500` | `var(--sf-color-neutral)` | -| `--sf-color-neutral-600` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-neutral-700` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-neutral-800` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-neutral-900` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-neutral-950` | `color-mix(in oklab, var(--sf-color-neutral) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-neutral-600` | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-neutral-700` | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-neutral-800` | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-neutral-900` | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-neutral-950` | `oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-neutral-a10` | `oklch(from var(--sf-color-neutral) l c h / 0.10)` | | `--sf-color-neutral-a30` | `oklch(from var(--sf-color-neutral) l c h / 0.30)` | | `--sf-color-neutral-a5` | `oklch(from var(--sf-color-neutral) l c h / 0.05)` | @@ -185,17 +185,17 @@ rebrand workflow. | `--sf-color-primary` | `light-dark(var(--sf-color-primary-source-light), var(--sf-color-primary-source-dark, oklch(from var(--sf-color-primary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-primary--active` | `var(--sf-color-primary-xdark)` | | `--sf-color-primary--hover` | `var(--sf-color-primary-darker)` | -| `--sf-color-primary-100` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-primary-200` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-primary-300` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-primary-400` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-primary-50` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-primary-100` | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-primary-200` | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-primary-300` | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-primary-400` | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-primary-50` | `oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-primary-500` | `var(--sf-color-primary)` | -| `--sf-color-primary-600` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-primary-700` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-primary-800` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-primary-900` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-primary-950` | `color-mix(in oklab, var(--sf-color-primary) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-primary-600` | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-primary-700` | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-primary-800` | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-primary-900` | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-primary-950` | `oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-primary-a10` | `oklch(from var(--sf-color-primary) l c h / 0.10)` | | `--sf-color-primary-a30` | `oklch(from var(--sf-color-primary) l c h / 0.30)` | | `--sf-color-primary-a5` | `oklch(from var(--sf-color-primary) l c h / 0.05)` | @@ -217,17 +217,17 @@ rebrand workflow. | `--sf-color-secondary` | `light-dark(var(--sf-color-secondary-source-light), var(--sf-color-secondary-source-dark, oklch(from var(--sf-color-secondary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-secondary--active` | `var(--sf-color-secondary-xdark)` | | `--sf-color-secondary--hover` | `var(--sf-color-secondary-darker)` | -| `--sf-color-secondary-100` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-secondary-200` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-secondary-300` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-secondary-400` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-secondary-50` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-secondary-100` | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-secondary-200` | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-secondary-300` | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-secondary-400` | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-secondary-50` | `oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-secondary-500` | `var(--sf-color-secondary)` | -| `--sf-color-secondary-600` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-secondary-700` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-secondary-800` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-secondary-900` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-secondary-950` | `color-mix(in oklab, var(--sf-color-secondary) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-secondary-600` | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-secondary-700` | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-secondary-800` | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-secondary-900` | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-secondary-950` | `oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-secondary-a10` | `oklch(from var(--sf-color-secondary) l c h / 0.10)` | | `--sf-color-secondary-a30` | `oklch(from var(--sf-color-secondary) l c h / 0.30)` | | `--sf-color-secondary-a5` | `oklch(from var(--sf-color-secondary) l c h / 0.05)` | @@ -259,17 +259,17 @@ rebrand workflow. | `--sf-color-tertiary` | `light-dark(var(--sf-color-tertiary-source-light), var(--sf-color-tertiary-source-dark, oklch(from var(--sf-color-tertiary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)))` | | `--sf-color-tertiary--active` | `var(--sf-color-tertiary-xdark)` | | `--sf-color-tertiary--hover` | `var(--sf-color-tertiary-darker)` | -| `--sf-color-tertiary-100` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-100), var(--sf-color-surface))` | -| `--sf-color-tertiary-200` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-200), var(--sf-color-surface))` | -| `--sf-color-tertiary-300` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-300), var(--sf-color-surface))` | -| `--sf-color-tertiary-400` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-400), var(--sf-color-surface))` | -| `--sf-color-tertiary-50` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-50), var(--sf-color-surface))` | +| `--sf-color-tertiary-100` | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h)` | +| `--sf-color-tertiary-200` | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h)` | +| `--sf-color-tertiary-300` | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h)` | +| `--sf-color-tertiary-400` | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h)` | +| `--sf-color-tertiary-50` | `oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h)` | | `--sf-color-tertiary-500` | `var(--sf-color-tertiary)` | -| `--sf-color-tertiary-600` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-600), var(--sf-color-text))` | -| `--sf-color-tertiary-700` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-700), var(--sf-color-text))` | -| `--sf-color-tertiary-800` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-800), var(--sf-color-text))` | -| `--sf-color-tertiary-900` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-900), var(--sf-color-text))` | -| `--sf-color-tertiary-950` | `color-mix(in oklab, var(--sf-color-tertiary) var(--sf-palette-mix-950), var(--sf-color-text))` | +| `--sf-color-tertiary-600` | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h)` | +| `--sf-color-tertiary-700` | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h)` | +| `--sf-color-tertiary-800` | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h)` | +| `--sf-color-tertiary-900` | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h)` | +| `--sf-color-tertiary-950` | `oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h)` | | `--sf-color-tertiary-a10` | `oklch(from var(--sf-color-tertiary) l c h / 0.10)` | | `--sf-color-tertiary-a30` | `oklch(from var(--sf-color-tertiary) l c h / 0.30)` | | `--sf-color-tertiary-a5` | `oklch(from var(--sf-color-tertiary) l c h / 0.05)` | @@ -460,16 +460,8 @@ rebrand workflow. | `--sf-opacity-disabled` | `0.45` | | `--sf-opacity-muted` | `0.5` | | `--sf-optical-sizing` | `auto` | -| `--sf-palette-mix-100` | `8%` | -| `--sf-palette-mix-200` | `20%` | -| `--sf-palette-mix-300` | `40%` | -| `--sf-palette-mix-400` | `65%` | -| `--sf-palette-mix-50` | `4%` | -| `--sf-palette-mix-600` | `82%` | -| `--sf-palette-mix-700` | `62%` | -| `--sf-palette-mix-800` | `38%` | -| `--sf-palette-mix-900` | `18%` | -| `--sf-palette-mix-950` | `8%` | +| `--sf-palette-shade-l` | `0.1` | +| `--sf-palette-tint-l` | `0.97` | | `--sf-print-base-size` | `11pt` | | `--sf-print-page-margin` | `2cm` | | `--sf-print-page-size` | `a4` | diff --git a/scripts/token-tiers.js b/scripts/token-tiers.js index 954e4215..06f9265a 100644 --- a/scripts/token-tiers.js +++ b/scripts/token-tiers.js @@ -77,11 +77,12 @@ const ADVANCED = new Set([ const STEP = '(?:2xs|xs|s|m|l|xl|2xl|3xl|4xl)'; const ADVANCED_PATTERNS = [ new RegExp(`^--sf-(?:space|text)-${STEP}-to-${STEP}$`), - // · Palette ramp-shape knobs (core/tokens.css): - // `--sf-palette-mix-{step}` — color-mix() percentages reshaping the - // entire numeric palette ladder at once. Niche/powerful, documented + // · Palette ramp lightness anchors (core/tokens.css): + // `--sf-palette-tint-l` / `--sf-palette-shade-l` — absolute OKLCH + // lightness targets the tint/shade steps pull toward, reshaping the + // whole numeric palette ladder at once. Niche/powerful, documented // as PUBLIC-ADVANCED in the core palette section. - /^--sf-palette-mix-\d+$/, + /^--sf-palette-(?:tint|shade)-l$/, ]; /** diff --git a/tests/ramp-monotonic.spec.js b/tests/ramp-monotonic.spec.js new file mode 100644 index 00000000..09414487 --- /dev/null +++ b/tests/ramp-monotonic.spec.js @@ -0,0 +1,101 @@ +// @ts-check +// Proves the numeric brand ramp (--sf-color-{family}-50…950) never FOLDS — +// its luminance is monotonically non-increasing from step 50 to 950 for ANY +// source colour the user picks, at any lightness of that colour. +// +// This is the guarantee the absolute-anchor ramp model buys us: each step +// pulls the family colour's own OKLCH lightness a fixed fraction toward an +// ABSOLUTE target (--sf-palette-tint-l / --sf-palette-shade-l), clamped so a +// tint can never end darker than the base nor a shade lighter. The ladder +// therefore stays light→dark regardless of where the source sits relative to +// the theme's text/surface tokens. The previous color-mix()-toward-text/surface +// model folded into a "U" when the source fell outside the anchor band. +// +// fixture.html loads the full bundle (palette tokens are core, gated behind the +// relative-colour @supports block Chromium/Firefox/WebKit satisfy). +import { test, expect } from '@playwright/test'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const FIXTURE = pathToFileURL(path.join(import.meta.dirname, 'fixture.html')).href; + +const FAMILIES = ['primary', 'secondary', 'tertiary', 'action', 'neutral']; +const STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; + +// Source lightnesses spanning the whole axis, including values OUTSIDE the +// default anchor band (0.06 is darker than the text anchor; 0.98 is lighter +// than the surface anchor) — exactly where the old model folded. +const SOURCE_LS = [0.06, 0.22, 0.5, 0.78, 0.98]; + +// Self-contained for page.evaluate: for one family, sweep several source +// lightnesses and return, per sweep, the {step, lum, alpha} of every step. +function sweepFamily([family, steps, sourceLs]) { + const root = document.documentElement; + root.setAttribute('data-theme', 'light'); + const cv = document.createElement('canvas'); cv.width = cv.height = 1; + const ctx = cv.getContext('2d', { willReadFrequently: true }); + const lin = v => { v /= 255; return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4; }; + const el = document.createElement('div'); document.body.appendChild(el); + + const sweeps = sourceLs.map(L => { + root.style.setProperty(`--sf-color-${family}-source-light`, `oklch(${L} 0.16 264)`); + const rows = steps.map(step => { + el.style.backgroundColor = `var(--sf-color-${family}-${step})`; + const c = getComputedStyle(el).backgroundColor; + ctx.clearRect(0, 0, 1, 1); ctx.fillStyle = '#000'; ctx.fillStyle = c; ctx.fillRect(0, 0, 1, 1); + const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data; + return { step, lum: 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b), alpha: a }; + }); + return { L, rows }; + }); + + el.remove(); + root.style.removeProperty(`--sf-color-${family}-source-light`); + return sweeps; +} + +test.describe('Brand ramp is monotonic for any source colour', () => { + for (const family of FAMILIES) { + test(`${family} ramp never folds across the lightness axis`, async ({ page }) => { + await page.goto(FIXTURE); + const sweeps = await page.evaluate(sweepFamily, [family, STEPS, SOURCE_LS]); + + const EPS = 0.006; // absorbs 8-bit rounding; clamped extremes go flat (equal), a fold increases + for (const { L, rows } of sweeps) { + for (const { step, alpha } of rows) { + expect(alpha, `${family}-${step} (source L=${L}) should be opaque`).toBe(255); + } + for (let i = 0; i < rows.length - 1; i++) { + expect( + rows[i + 1].lum, + `${family} (source L=${L}): step ${rows[i + 1].step} must not be lighter than ${rows[i].step}` + ).toBeLessThanOrEqual(rows[i].lum + EPS); + } + } + }); + } + + test('default palette keeps light-to-dark endpoints (50 light, 950 dark)', async ({ page }) => { + await page.goto(FIXTURE); + for (const family of FAMILIES) { + const ends = await page.evaluate(([fam, steps]) => { + document.documentElement.setAttribute('data-theme', 'light'); + const cv = document.createElement('canvas'); cv.width = cv.height = 1; + const ctx = cv.getContext('2d', { willReadFrequently: true }); + const lin = v => { v /= 255; return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4; }; + const el = document.createElement('div'); document.body.appendChild(el); + const read = step => { + el.style.backgroundColor = `var(--sf-color-${fam}-${step})`; + ctx.clearRect(0, 0, 1, 1); ctx.fillStyle = getComputedStyle(el).backgroundColor; ctx.fillRect(0, 0, 1, 1); + const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data; + return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b); + }; + const res = { light: read(steps[0]), dark: read(steps[steps.length - 1]) }; + el.remove(); + return res; + }, [family, STEPS]); + expect(ends.light, `${family}-50 should be light`).toBeGreaterThan(0.6); + expect(ends.dark, `${family}-950 should be dark`).toBeLessThan(0.15); + } + }); +}); diff --git a/tests/token-api.snapshot.json b/tests/token-api.snapshot.json index 64fd35fd..5c3f49a0 100644 --- a/tests/token-api.snapshot.json +++ b/tests/token-api.snapshot.json @@ -536,16 +536,8 @@ "--sf-opacity-muted", "--sf-optical-sizing", "--sf-overlap-pull", - "--sf-palette-mix-100", - "--sf-palette-mix-200", - "--sf-palette-mix-300", - "--sf-palette-mix-400", - "--sf-palette-mix-50", - "--sf-palette-mix-600", - "--sf-palette-mix-700", - "--sf-palette-mix-800", - "--sf-palette-mix-900", - "--sf-palette-mix-950", + "--sf-palette-shade-l", + "--sf-palette-tint-l", "--sf-print-base-size", "--sf-print-page-margin", "--sf-print-page-size", diff --git a/token-registry.json b/token-registry.json index 2899b694..5e23826f 100644 --- a/token-registry.json +++ b/token-registry.json @@ -1,7 +1,7 @@ { "_meta": { "generatedBy": "scripts/gen-token-registry.js", - "nextId": 798 + "nextId": 800 }, "tokens": [ { @@ -1993,43 +1993,53 @@ }, { "id": 489, - "name": "--sf-palette-mix-100" + "name": "--sf-palette-mix-100", + "removed": true }, { "id": 490, - "name": "--sf-palette-mix-200" + "name": "--sf-palette-mix-200", + "removed": true }, { "id": 491, - "name": "--sf-palette-mix-300" + "name": "--sf-palette-mix-300", + "removed": true }, { "id": 492, - "name": "--sf-palette-mix-400" + "name": "--sf-palette-mix-400", + "removed": true }, { "id": 493, - "name": "--sf-palette-mix-50" + "name": "--sf-palette-mix-50", + "removed": true }, { "id": 494, - "name": "--sf-palette-mix-600" + "name": "--sf-palette-mix-600", + "removed": true }, { "id": 495, - "name": "--sf-palette-mix-700" + "name": "--sf-palette-mix-700", + "removed": true }, { "id": 496, - "name": "--sf-palette-mix-800" + "name": "--sf-palette-mix-800", + "removed": true }, { "id": 497, - "name": "--sf-palette-mix-900" + "name": "--sf-palette-mix-900", + "removed": true }, { "id": 498, - "name": "--sf-palette-mix-950" + "name": "--sf-palette-mix-950", + "removed": true }, { "id": 499, @@ -3239,6 +3249,14 @@ { "id": 797, "name": "--sf-density" + }, + { + "id": 798, + "name": "--sf-palette-shade-l" + }, + { + "id": 799, + "name": "--sf-palette-tint-l" } ] } diff --git a/user-manual/colors.md b/user-manual/colors.md index e3461607..17f83820 100644 --- a/user-manual/colors.md +++ b/user-manual/colors.md @@ -150,9 +150,17 @@ background: Use these (not the numeric 50–950 ramp) when the element sits on top of a background you don't control — e.g. a colored badge that might appear on a -light or dark card. The numeric ramp is baked against a specific surface/text -color and will look wrong if the background changes underneath it; the alpha -variants stay correct anywhere. +light or dark card. The numeric ramp gives **solid** colors, so it can't blend +into an unknown background; the alpha variants stay correct anywhere. + +> **How the numeric ramp is generated.** Each step pulls the family color's own +> OKLCH lightness a fixed fraction toward an **absolute** target — +> `--sf-palette-tint-l` (`0.97`) for tints 50–400, `--sf-palette-shade-l` +> (`0.1`) for shades 600–950 — clamped so a tint is never darker than the base +> and a shade never lighter. The ramp is therefore **monotonic light→dark for +> any source color** you pick, and does not fold even if your brand color is +> very dark/light or you move the neutral/base anchors. (`base` is a separate +> absolute grey ladder; status colors have no numeric ramp.) ## Status colors diff --git a/user-manual/system-kolorow.md b/user-manual/system-kolorow.md index 6dbe43bc..628bb65e 100644 --- a/user-manual/system-kolorow.md +++ b/user-manual/system-kolorow.md @@ -324,8 +324,17 @@ Aliasy do tych, po które naprawdę sięgasz: --sf-color-primary-xdark (= -800) stan wciśnięty ``` -**Ważne:** rampa numeryczna jest policzona względem **konkretnego** tła -(`--sf-color-surface`). Używaj jej tylko, gdy znasz tło pod spodem. +**Jak liczona jest rampa.** Każdy krok przyciąga jasność OKLCH koloru marki o +ustalony ułamek ku **absolutnej** kotwicy — `--sf-palette-tint-l` (`0.97`) dla +tintów 50–400, `--sf-palette-shade-l` (`0.1`) dla cieni 600–950 — z klamrą, więc +tint nigdy nie jest ciemniejszy od bazy, a cień nigdy jaśniejszy. Dzięki temu +rampa jest **monotoniczna (jasno→ciemno) dla dowolnego koloru źródłowego** i +**nie składa się w „U"** — nawet gdy Twój brand jest bardzo ciemny/jasny albo +przesuniesz kotwice `neutral`/`base`. (`base` to osobna, absolutna drabina +szarości; statusy nie mają rampy numerycznej.) + +Kroki dają **jednolite** (nieprzezroczyste) kolory, więc nie wtapiają się w +nieznane tło — do tego służą warianty alfa (niżej). ### Warianty alfa (przezroczyste) @@ -339,8 +348,9 @@ ciemną kartę) — użyj wariantów alfa zamiast rampy numerycznej: | `-a30` | 30% | `-muted` | | `-a50` | 50% | — | -Alfa zostaje poprawna na każdym tle; rampa numeryczna „rozjedzie się”, gdy tło -się zmieni. +Alfa przepuszcza tło pod spodem (przezroczystość), więc jest poprawna na każdym +tle; rampa numeryczna daje kolory jednolite, które nie reagują na to, co jest +pod nimi. ### Statusy: `success`, `warning`, `info`, `danger` From 09cb9f69be40f8c2dcb7e624957c2b9681709b02 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 15:51:56 +0000 Subject: [PATCH 3/7] feat(configurator): rewire Colors palette-ramp panel to the anchor model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Colors panel's "Palette ramp" section drove the ten removed --sf-palette-mix-* knobs (percentage-toward-surface/text sliders) and previewed each step with the old color-mix() formula. Swap it to the new model: - two 0–1 sliders for the lightness anchors --sf-palette-tint-l / --sf-palette-shade-l (replacing the ten percentage sliders) - Softer / Default / Punchy presets now patch the two anchors - the live primary-palette preview and the mini-palette strips compute each step with the absolute-anchor OKLCH formula, so the preview matches the framework and is always monotonic light→dark - domain-patterns keyword already updated to "palette" so the new knobs land in the colours domain (prior commit) Verified: svelte-check (0 errors), configurator unit suite (164 tests), curation gate, and a production vite build all pass; visually confirmed the panel renders the two anchor sliders and a monotonic palette preview. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- CHANGELOG.md | 1 + .../src/components/panels/ColorsPanel.svelte | 147 ++++++++---------- 2 files changed, 67 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84b815b2..accd1512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Bug Fixes - **tokens:** the numeric brand ramps (`--sf-color-{primary,secondary,tertiary,action,neutral}-50…950`) no longer fold into a "U". The previous model generated each step with `color-mix()` toward the theme's `--sf-color-surface` (tints) / `--sf-color-text` (shades) — so when a chosen source colour fell outside the band between those two anchors (e.g. a brand darker than the text colour, or a project that lightened `--sf-color-neutral`), the shade half inverted and climbed back up: steps 600–950 came out *lighter* than 500, and 50 ≈ 950. The ramp is now generated in OKLCH by pulling the family colour's own lightness a fixed fraction toward an **absolute** target — `--sf-palette-tint-l` (tints) / `--sf-palette-shade-l` (shades) — clamped with `max()`/`min()` so a tint can never end darker than the base nor a shade lighter. The ladder is therefore monotonic light→dark for **any** source colour and any anchor configuration. Chroma is tapered toward the extremes to avoid oversaturation. For default-palette colours (which already sat inside the safe band) the output is visually unchanged; only out-of-band / moved-anchor cases are corrected. `base` is unchanged (it already used absolute lightness steps). New parametric test `tests/ramp-monotonic.spec.js` sweeps the lightness axis for all five families and asserts the ramp never folds and no step is transparent. +- **configurator:** the Colors panel's "Palette ramp" section now edits the two lightness anchors (`--sf-palette-tint-l` / `--sf-palette-shade-l`) with two `0–1` sliders instead of the ten removed `--sf-palette-mix-*` percentage sliders; the Softer/Default/Punchy presets and the live palette preview were rewired to the absolute-anchor model so the preview matches the framework and stays monotonic. - **layout:** `@container` breakpoints for `.sf-grid-cols-*`, `.sf-bento` and `.sf-alternate` now use `rem` instead of `em`. ### Breaking Changes diff --git a/configurator/src/components/panels/ColorsPanel.svelte b/configurator/src/components/panels/ColorsPanel.svelte index 76b787a3..aa964e00 100644 --- a/configurator/src/components/panels/ColorsPanel.svelte +++ b/configurator/src/components/panels/ColorsPanel.svelte @@ -109,41 +109,42 @@ { name: "--sf-color-danger-source-dark", label: "Danger", side: "dark", default: "oklch(0.73 0.198 12)", colorKey: "danger" }, ]; - const MIX_STEPS = [ - { name: "--sf-palette-mix-50", label: "50", step: "tint", default: 4 }, - { name: "--sf-palette-mix-100", label: "100", step: "tint", default: 8 }, - { name: "--sf-palette-mix-200", label: "200", step: "tint", default: 20 }, - { name: "--sf-palette-mix-300", label: "300", step: "tint", default: 40 }, - { name: "--sf-palette-mix-400", label: "400", step: "tint", default: 65 }, - { name: "--sf-palette-mix-600", label: "600", step: "shade", default: 82 }, - { name: "--sf-palette-mix-700", label: "700", step: "shade", default: 62 }, - { name: "--sf-palette-mix-800", label: "800", step: "shade", default: 38 }, - { name: "--sf-palette-mix-900", label: "900", step: "shade", default: 18 }, - { name: "--sf-palette-mix-950", label: "950", step: "shade", default: 8 }, + // Baked per-step ramp curve — mirrors core/tokens.css: how far each step + // pulls its lightness toward the absolute anchor, plus a chroma taper. + // Preview-only (the shape is fixed in the framework); the two anchors below + // are the tunable public knobs. + const RAMP_CURVE = [ + { label: "50", step: "tint", frac: 0.95, taper: 0.20 }, + { label: "100", step: "tint", frac: 0.88, taper: 0.30 }, + { label: "200", step: "tint", frac: 0.72, taper: 0.50 }, + { label: "300", step: "tint", frac: 0.52, taper: 0.72 }, + { label: "400", step: "tint", frac: 0.30, taper: 0.88 }, + { label: "600", step: "shade", frac: 0.16, taper: 0.96 }, + { label: "700", step: "shade", frac: 0.36, taper: 0.88 }, + { label: "800", step: "shade", frac: 0.58, taper: 0.72 }, + { label: "900", step: "shade", frac: 0.78, taper: 0.52 }, + { label: "950", step: "shade", frac: 0.90, taper: 0.38 }, + ] as const; + + // The two PUBLIC-ADVANCED ramp anchors — absolute OKLCH lightness the tint + // (50–400) / shade (600–950) halves reach toward. Unitless 0–1. + const ANCHOR_KNOBS = [ + { name: "--sf-palette-tint-l", label: "Lightest step (L)", default: 0.97 }, + { name: "--sf-palette-shade-l", label: "Darkest step (L)", default: 0.1 }, ]; const CURVE_PRESETS = [ { label: "Softer", desc: "Low contrast palette", - patch: { - "--sf-palette-mix-50": "3%", "--sf-palette-mix-100": "6%", "--sf-palette-mix-200": "14%", - "--sf-palette-mix-300": "30%", "--sf-palette-mix-400": "55%", - "--sf-palette-mix-600": "72%", "--sf-palette-mix-700": "52%", - "--sf-palette-mix-800": "28%", "--sf-palette-mix-900": "12%", "--sf-palette-mix-950": "5%", - }, + patch: { "--sf-palette-tint-l": "0.93", "--sf-palette-shade-l": "0.2" }, }, { label: "Default", desc: "Balanced contrast", - patch: Object.fromEntries(MIX_STEPS.map((s) => [s.name, null])) as Record, + patch: Object.fromEntries(ANCHOR_KNOBS.map((k) => [k.name, null])) as Record, }, { label: "Punchy", desc: "High contrast palette", - patch: { - "--sf-palette-mix-50": "6%", "--sf-palette-mix-100": "12%", "--sf-palette-mix-200": "28%", - "--sf-palette-mix-300": "52%", "--sf-palette-mix-400": "78%", - "--sf-palette-mix-600": "90%", "--sf-palette-mix-700": "72%", - "--sf-palette-mix-800": "50%", "--sf-palette-mix-900": "26%", "--sf-palette-mix-950": "12%", - }, + patch: { "--sf-palette-tint-l": "0.98", "--sf-palette-shade-l": "0.05" }, }, ]; @@ -325,10 +326,11 @@ ) )); - function getMixValue(s: typeof MIX_STEPS[0]): number { - const raw = overrides[s.name]; - if (!raw) return s.default; - return parseFloat(raw); + function getAnchor(name: string, def: number): number { + const raw = overrides[name]; + if (raw === undefined) return def; + const n = parseFloat(raw); + return Number.isFinite(n) ? n : def; } // Build brand pairs: group by colorKey then render light/dark @@ -382,17 +384,22 @@ return stringifyOklch(Math.min(1.0, Math.max(l + 0.22, 0.88)), c * 0.8, h); } - // Build a concrete color-mix() expression and resolve it via the regular preview probe. - // Bypasses the themed probe entirely — produces correct dark tints/shades from literal values. - function computePaletteSwatch(sourceColor: string, step: string, surface: string, text: string): string { + // Preview one brand palette step with the framework's absolute-anchor model + // (core/tokens.css): pull the source lightness a fixed fraction toward + // --sf-palette-tint-l (tints) / --sf-palette-shade-l (shades), clamped with + // max()/min() so it can't fold, with a chroma taper. Independent of + // surface/text — the ramp no longer mixes toward them. + function computePaletteSwatch(sourceColor: string, step: string): string { void previewVersion.value; if (step === "500") return resolveColor(sourceColor) || sourceColor; - const isTint = parseInt(step) < 500; - const mixStepDef = MIX_STEPS.find((s) => s.label === step); - if (!mixStepDef) return sourceColor; - const pct = getMixValue(mixStepDef); - const endpoint = isTint ? surface : text; - const expr = `color-mix(in oklab, ${sourceColor} ${pct}%, ${endpoint})`; + const def = RAMP_CURVE.find((s) => s.label === step); + if (!def) return sourceColor; + const isTint = def.step === "tint"; + const target = isTint + ? getAnchor("--sf-palette-tint-l", 0.97) + : getAnchor("--sf-palette-shade-l", 0.1); + const clamp = isTint ? "max" : "min"; + const expr = `oklch(from ${sourceColor} ${clamp}(l, calc(l + (${target} - l) * ${def.frac})) calc(c * ${def.taper}) h)`; return resolveColor(expr) || expr; } @@ -409,10 +416,10 @@ // Route each color to the correct palette system: base uses the fixed-L ramp, // every other key uses the color-mix tint/shade curve toward surface/text. - function paletteSwatch(colorKey: string, sourceColor: string, step: string, surface: string, text: string): string { + function paletteSwatch(colorKey: string, sourceColor: string, step: string, _surface: string, _text: string): string { return colorKey === "base" ? computeBasePaletteSwatch(sourceColor, step) - : computePaletteSwatch(sourceColor, step, surface, text); + : computePaletteSwatch(sourceColor, step); } function handleLightChange(light: ColorSource, dark: ColorSource | undefined, newVal: string) { @@ -840,7 +847,7 @@ aria-expanded={showShadeCurve} class="w-full flex items-center justify-between cursor-pointer" > -
Shade / tint curve
+
Palette ramp
{showShadeCurve ? "▲" : "▼"} {#if showShadeCurve} @@ -850,12 +857,10 @@ ? (BRAND_SOURCES.find(s => s.name === "--sf-color-primary-source-dark")?.default ?? deriveDarkFromLight(_curvePrimLightSrc, "primary")) : deriveDarkFromLight(_curvePrimLightSrc, "primary"))} {@const _curvePrimSrc = curvePreviewSide === "light" ? _curvePrimLightSrc : _curvePrimDarkSrc} - {@const _curveSurface = curvePreviewSide === "light" ? getLightSurface() : getDarkSurface()} - {@const _curveText = curvePreviewSide === "light" ? getLightText() : getDarkText()} - {@const _miniSurface = curvePreviewSide === "light" ? getLightSurface() : getDarkSurface()} - {@const _miniText = curvePreviewSide === "light" ? getLightText() : getDarkText()}

- Controls how much color is mixed into each palette step. Step 500 is always the source color. + Set how light the lightest step and how dark the darkest step reach; every + step in between is derived automatically and stays light→dark for any + colour. Step 500 is always the source colour.

@@ -874,35 +879,18 @@ {/each}
- +
-
Tints (50–400) — mixed toward surface
+
Ramp anchors — absolute OKLCH lightness
- {#each MIX_STEPS.filter((s) => s.step === "tint") as s (s.name)} + {#each ANCHOR_KNOBS as k (k.name)} onSet(s.name, `${v}%`)} - onReset={() => onReset(s.name)} - /> - {/each} -
-
- - -
-
Shades (600–950) — mixed toward text
-
- {#each MIX_STEPS.filter((s) => s.step === "shade") as s (s.name)} - onSet(s.name, `${v}%`)} - onReset={() => onReset(s.name)} + label={k.label} + value={getAnchor(k.name, k.default)} + min={0} max={1} step={0.01} unit="" + overridden={k.name in overrides} + onChange={(v) => onSet(k.name, `${v}`)} + onReset={() => onReset(k.name)} /> {/each}
@@ -925,22 +913,19 @@
- {#each MIX_STEPS as s (s.name)} - {@const val = getMixValue(s)} - {@const step = s.label} - {@const swatch = computePaletteSwatch(_curvePrimSrc, step, _curveSurface, _curveText)} + {#each SWATCH_STEPS as step (step)} + {@const swatch = computePaletteSwatch(_curvePrimSrc, step)}
- {Math.round(val)}
{@render swatchTip(`primary-${step}`)}
{step}
{/each}
-

Bar height = mix amount · fill = the resolved primary palette swatch at each step

+

Live primary palette, 50 → 950 — always monotonic light→dark

@@ -969,7 +954,7 @@ {colorKey}
{#each SWATCH_STEPS as step (step)} - {@const swatch = computePaletteSwatch(miniSrc, step, _miniSurface, _miniText)} + {@const swatch = computePaletteSwatch(miniSrc, step)}
Date: Thu, 16 Jul 2026 16:28:05 +0000 Subject: [PATCH 4/7] =?UTF-8?q?fix:=20address=20PR=20#627=20review=20?= =?UTF-8?q?=E2=80=94=20changelog=20copy-paste,=20dark=20sweep,=20dead=20as?= =?UTF-8?q?signment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CHANGELOG: the layout em→rem explanation had leaked onto the tokens Breaking-Changes bullet (an Edit matched only the first sentence of the long layout line); restore the full layout Bug-Fixes bullet and end the tokens breaking bullet at its migration note (greptile P1). - tests/ramp-monotonic.spec.js: add a second data-theme="dark" sweep driving --sf-color-{family}-source-dark, so monotonicity is verified symmetrically in both modes, not just light (greptile P2). Now 11 cases, all green. - tests/ramp-monotonic.spec.js: drop the redundant `ctx.fillStyle = '#000'` write immediately overwritten by `ctx.fillStyle = c` (code-scanning nit). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- CHANGELOG.md | 4 ++-- tests/ramp-monotonic.spec.js | 46 ++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index accd1512..0f7dcf71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Bug Fixes - **tokens:** the numeric brand ramps (`--sf-color-{primary,secondary,tertiary,action,neutral}-50…950`) no longer fold into a "U". The previous model generated each step with `color-mix()` toward the theme's `--sf-color-surface` (tints) / `--sf-color-text` (shades) — so when a chosen source colour fell outside the band between those two anchors (e.g. a brand darker than the text colour, or a project that lightened `--sf-color-neutral`), the shade half inverted and climbed back up: steps 600–950 came out *lighter* than 500, and 50 ≈ 950. The ramp is now generated in OKLCH by pulling the family colour's own lightness a fixed fraction toward an **absolute** target — `--sf-palette-tint-l` (tints) / `--sf-palette-shade-l` (shades) — clamped with `max()`/`min()` so a tint can never end darker than the base nor a shade lighter. The ladder is therefore monotonic light→dark for **any** source colour and any anchor configuration. Chroma is tapered toward the extremes to avoid oversaturation. For default-palette colours (which already sat inside the safe band) the output is visually unchanged; only out-of-band / moved-anchor cases are corrected. `base` is unchanged (it already used absolute lightness steps). New parametric test `tests/ramp-monotonic.spec.js` sweeps the lightness axis for all five families and asserts the ramp never folds and no step is transparent. - **configurator:** the Colors panel's "Palette ramp" section now edits the two lightness anchors (`--sf-palette-tint-l` / `--sf-palette-shade-l`) with two `0–1` sliders instead of the ten removed `--sf-palette-mix-*` percentage sliders; the Softer/Default/Punchy presets and the live palette preview were rewired to the absolute-anchor model so the preview matches the framework and stays monotonic. -- **layout:** `@container` breakpoints for `.sf-grid-cols-*`, `.sf-bento` and `.sf-alternate` now use `rem` instead of `em`. +- **layout:** `@container` breakpoints for `.sf-grid-cols-*`, `.sf-bento` and `.sf-alternate` now use `rem` instead of `em`. Inside a container query an `em` resolves against the query container's own font-size, which under the default fluid type scale is inherited from `body` (a `clamp()` over `100vw`, ~16–20px) — so the same fixed-width container rendered a different column count depending on the *viewport*: an 800px container showed `.sf-grid-cols-3` as 3 columns at a 500px viewport but 1 column at 1200px+. `rem` resolves against the fixed root (`html` stays 16px; fluid type is applied to `body`), restoring the documented "responds to its own container width, not the viewport" contract. Thresholds are unchanged numerically (30rem = 480px, 48rem = 768px) and still honour user zoom / root-font-size. Also corrects `docs/architecture.md`, which wrongly listed `.sf-grid` / `.sf-sidebar` as `@container` primitives (both are intrinsic and carry no container query). ### Breaking Changes -- **tokens:** removed the `--sf-palette-mix-50…950` ramp-shape knobs (color-mix percentages of the old model) and replaced them with two lightness-anchor knobs — `--sf-palette-tint-l` (default `0.97`) and `--sf-palette-shade-l` (default `0.1`) — which set how light the lightest / how dark the darkest generated palette step may reach. Per-step pull fraction and chroma taper are now baked into each family. If you overrode `--sf-palette-mix-*` to reshape the ramp, retune via the two new anchors instead (or override individual `--sf-color-{family}-{step}` resolved tokens). Inside a container query an `em` resolves against the query container's own font-size, which under the default fluid type scale is inherited from `body` (a `clamp()` over `100vw`, ~16–20px) — so the same fixed-width container rendered a different column count depending on the *viewport*: an 800px container showed `.sf-grid-cols-3` as 3 columns at a 500px viewport but 1 column at 1200px+. `rem` resolves against the fixed root (`html` stays 16px; fluid type is applied to `body`), restoring the documented "responds to its own container width, not the viewport" contract. Thresholds are unchanged numerically (30rem = 480px, 48rem = 768px) and still honour user zoom / root-font-size. Also corrects `docs/architecture.md`, which wrongly listed `.sf-grid` / `.sf-sidebar` as `@container` primitives (both are intrinsic and carry no container query). +- **tokens:** removed the `--sf-palette-mix-50…950` ramp-shape knobs (color-mix percentages of the old model) and replaced them with two lightness-anchor knobs — `--sf-palette-tint-l` (default `0.97`) and `--sf-palette-shade-l` (default `0.1`) — which set how light the lightest / how dark the darkest generated palette step may reach. Per-step pull fraction and chroma taper are now baked into each family. If you overrode `--sf-palette-mix-*` to reshape the ramp, retune via the two new anchors instead (or override individual `--sf-color-{family}-{step}` resolved tokens). ## [0.7.18] - 2026-07-16 diff --git a/tests/ramp-monotonic.spec.js b/tests/ramp-monotonic.spec.js index 09414487..2b901281 100644 --- a/tests/ramp-monotonic.spec.js +++ b/tests/ramp-monotonic.spec.js @@ -29,20 +29,24 @@ const SOURCE_LS = [0.06, 0.22, 0.5, 0.78, 0.98]; // Self-contained for page.evaluate: for one family, sweep several source // lightnesses and return, per sweep, the {step, lum, alpha} of every step. -function sweepFamily([family, steps, sourceLs]) { +function sweepFamily([family, steps, sourceLs, theme]) { const root = document.documentElement; - root.setAttribute('data-theme', 'light'); + root.setAttribute('data-theme', theme); + // Sweep the theme's own source token: source-light under light, source-dark + // under dark — dark exercises the same clamp path with different source + // colours, so the guarantee is symmetric across both modes. + const prop = `--sf-color-${family}-source-${theme}`; const cv = document.createElement('canvas'); cv.width = cv.height = 1; const ctx = cv.getContext('2d', { willReadFrequently: true }); const lin = v => { v /= 255; return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4; }; const el = document.createElement('div'); document.body.appendChild(el); const sweeps = sourceLs.map(L => { - root.style.setProperty(`--sf-color-${family}-source-light`, `oklch(${L} 0.16 264)`); + root.style.setProperty(prop, `oklch(${L} 0.16 264)`); const rows = steps.map(step => { el.style.backgroundColor = `var(--sf-color-${family}-${step})`; const c = getComputedStyle(el).backgroundColor; - ctx.clearRect(0, 0, 1, 1); ctx.fillStyle = '#000'; ctx.fillStyle = c; ctx.fillRect(0, 0, 1, 1); + ctx.clearRect(0, 0, 1, 1); ctx.fillStyle = c; ctx.fillRect(0, 0, 1, 1); const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data; return { step, lum: 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b), alpha: a }; }); @@ -50,29 +54,31 @@ function sweepFamily([family, steps, sourceLs]) { }); el.remove(); - root.style.removeProperty(`--sf-color-${family}-source-light`); + root.style.removeProperty(prop); return sweeps; } test.describe('Brand ramp is monotonic for any source colour', () => { for (const family of FAMILIES) { - test(`${family} ramp never folds across the lightness axis`, async ({ page }) => { - await page.goto(FIXTURE); - const sweeps = await page.evaluate(sweepFamily, [family, STEPS, SOURCE_LS]); + for (const theme of ['light', 'dark']) { + test(`${family} ramp never folds across the lightness axis (${theme})`, async ({ page }) => { + await page.goto(FIXTURE); + const sweeps = await page.evaluate(sweepFamily, [family, STEPS, SOURCE_LS, theme]); - const EPS = 0.006; // absorbs 8-bit rounding; clamped extremes go flat (equal), a fold increases - for (const { L, rows } of sweeps) { - for (const { step, alpha } of rows) { - expect(alpha, `${family}-${step} (source L=${L}) should be opaque`).toBe(255); + const EPS = 0.006; // absorbs 8-bit rounding; clamped extremes go flat (equal), a fold increases + for (const { L, rows } of sweeps) { + for (const { step, alpha } of rows) { + expect(alpha, `${family}-${step} (${theme}, source L=${L}) should be opaque`).toBe(255); + } + for (let i = 0; i < rows.length - 1; i++) { + expect( + rows[i + 1].lum, + `${family} (${theme}, source L=${L}): step ${rows[i + 1].step} must not be lighter than ${rows[i].step}` + ).toBeLessThanOrEqual(rows[i].lum + EPS); + } } - for (let i = 0; i < rows.length - 1; i++) { - expect( - rows[i + 1].lum, - `${family} (source L=${L}): step ${rows[i + 1].step} must not be lighter than ${rows[i].step}` - ).toBeLessThanOrEqual(rows[i].lum + EPS); - } - } - }); + }); + } } test('default palette keeps light-to-dark endpoints (50 light, 950 dark)', async ({ page }) => { From 4e363f3b72bc130f532ed5fb0a299bfa0d1b859c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 16:37:15 +0000 Subject: [PATCH 5/7] =?UTF-8?q?docs(readme):=20sync=20design-token=20count?= =?UTF-8?q?=20754=20=E2=86=92=20746=20after=20palette-knob=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The palette-ramp refactor nets -8 tokens (10 --sf-palette-mix-* removed, 2 anchors added). check:doc-refs enforces the 'N design tokens' claims against the live total; update both README mentions to 746. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 08191626..cd6ec95e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

A cascade-layer CSS framework you never compile.
- 754 design tokens, automatic dark mode, fluid type & spacing — no build step, no Node, no JavaScript. + 746 design tokens, automatic dark mode, fluid type & spacing — no build step, no Node, no JavaScript.

@@ -67,7 +67,7 @@ Every letter of SLASHED is a design commitment, and each one is checkable agains ## What's inside -- **754 design tokens** (`--sf-*`) covering color, typography, spacing, layout, borders, shadows, motion, and z-index — catalogued in a machine-readable [API index](docs/api-index.json). +- **746 design tokens** (`--sf-*`) covering color, typography, spacing, layout, borders, shadows, motion, and z-index — catalogued in a machine-readable [API index](docs/api-index.json). - **Layout primitives** — `.sf-container`, `.sf-stack`, `.sf-grid`, `.sf-cluster`, `.sf-sidebar`, `.sf-switcher`, `.sf-cover`, `.sf-center`, `.sf-frame`, `.sf-reel`, `.sf-bento`, and more ([docs/layout.md](docs/layout.md)). - **Macros** — recipes like `.sf-prose`, `.sf-flow`, `.sf-truncate`, `.sf-aspect`, `.sf-scroll-shadow`, `.sf-surface` ([docs/macros.md](docs/macros.md)). - **State classes** — `.sf-is-*` classes mapped to ARIA semantics ([docs/states.md](docs/states.md)). From fa1391aa8e9c2be37f80d3b4eefdbacaea23327c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 16:41:53 +0000 Subject: [PATCH 6/7] fix(tokens): unify status -subtle alpha to 0.12; drop dev-notes from manual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - core/tokens.css: --sf-color-info-subtle and --sf-color-danger-subtle were 0.10 alpha while success/warning were 0.12, so danger/info alert backgrounds rendered slightly fainter than success/warning at the same content. Unify all four status -subtle washes to 0.12 (the finding documented while writing the colour manual). Regenerated value-bearing docs. - user-manual/system-kolorow.md: remove the "Znalezione nieścisłości we frameworku" section (§9) — maintainer-facing findings don't belong in a user manual (PR #627 review); renumber the cheatsheet §10 → §9. Also refresh one stale §8 rationale ("ramp computed for a specific background") to the new solid-colour-doesn't-blend wording. - CHANGELOG: note the status -subtle alpha fix. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- CHANGELOG.md | 1 + .../src/data/api-index.generated.json | 6 +-- core/tokens.css | 4 +- dist/css-custom-data.json | 4 +- docs/api-index.json | 4 +- docs/api-index.md | 4 +- docs/token-index.json | 4 +- docs/token-index.md | 4 +- docs/tokens.md | 4 +- user-manual/system-kolorow.md | 49 +------------------ 10 files changed, 20 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa568641..e0f2c376 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [0.7.19] - 2026-07-16 ### Bug Fixes +- **tokens:** `--sf-color-info-subtle` and `--sf-color-danger-subtle` were `0.10` alpha while `--sf-color-success-subtle` / `--sf-color-warning-subtle` were `0.12`, so a `danger`/`info` alert-box background rendered slightly fainter than a `success`/`warning` one at the same content. Unified all four status `-subtle` washes to `0.12` (the `-muted` `0.3` and `-tint` `0.05` rungs were already consistent). - **tokens:** the numeric brand ramps (`--sf-color-{primary,secondary,tertiary,action,neutral}-50…950`) no longer fold into a "U". The previous model generated each step with `color-mix()` toward the theme's `--sf-color-surface` (tints) / `--sf-color-text` (shades) — so when a chosen source colour fell outside the band between those two anchors (e.g. a brand darker than the text colour, or a project that lightened `--sf-color-neutral`), the shade half inverted and climbed back up: steps 600–950 came out *lighter* than 500, and 50 ≈ 950. The ramp is now generated in OKLCH by pulling the family colour's own lightness a fixed fraction toward an **absolute** target — `--sf-palette-tint-l` (tints) / `--sf-palette-shade-l` (shades) — clamped with `max()`/`min()` so a tint can never end darker than the base nor a shade lighter. The ladder is therefore monotonic light→dark for **any** source colour and any anchor configuration. Chroma is tapered toward the extremes to avoid oversaturation. For default-palette colours (which already sat inside the safe band) the output is visually unchanged; only out-of-band / moved-anchor cases are corrected. `base` is unchanged (it already used absolute lightness steps). New parametric test `tests/ramp-monotonic.spec.js` sweeps the lightness axis for all five families and asserts the ramp never folds and no step is transparent. - **configurator:** the Colors panel's "Palette ramp" section now edits the two lightness anchors (`--sf-palette-tint-l` / `--sf-palette-shade-l`) with two `0–1` sliders instead of the ten removed `--sf-palette-mix-*` percentage sliders; the Softer/Default/Punchy presets and the live palette preview were rewired to the absolute-anchor model so the preview matches the framework and stays monotonic. - **layout:** `@container` breakpoints for `.sf-grid-cols-*`, `.sf-bento` and `.sf-alternate` now use `rem` instead of `em`. Inside a container query an `em` resolves against the query container's own font-size, which under the default fluid type scale is inherited from `body` (a `clamp()` over `100vw`, ~16–20px) — so the same fixed-width container rendered a different column count depending on the *viewport*: an 800px container showed `.sf-grid-cols-3` as 3 columns at a 500px viewport but 1 column at 1200px+. `rem` resolves against the fixed root (`html` stays 16px; fluid type is applied to `body`), restoring the documented "responds to its own container width, not the viewport" contract. Thresholds are unchanged numerically (30rem = 480px, 48rem = 768px) and still honour user zoom / root-font-size. Also corrects `docs/architecture.md`, which wrongly listed `.sf-grid` / `.sf-sidebar` as `@container` primitives (both are intrinsic and carry no container query). diff --git a/configurator/src/data/api-index.generated.json b/configurator/src/data/api-index.generated.json index b8584b98..a2ea40cd 100644 --- a/configurator/src/data/api-index.generated.json +++ b/configurator/src/data/api-index.generated.json @@ -2,7 +2,7 @@ "_sync": { "generatedBy": "configurator/scripts/sync-api.mjs", "source": "docs/api-index.json", - "tokensHash": "5c5b69ba4fa3", + "tokensHash": "fb3441987ce7", "bundles": [ "full", "optimal" @@ -3727,7 +3727,7 @@ "group": "Status triplets", "description": "Three-shade status triplets (subtle / muted / strong) for each status role. Use subtle for backgrounds, muted for fills, strong for text on light surfaces.", "note": "Light danger tint for error row backgrounds and alert container fills.", - "value": "oklch(from var(--sf-color-danger) l c h / 0.1)", + "value": "oklch(from var(--sf-color-danger) l c h / 0.12)", "aliasOf": null, "registered": false, "syntax": null, @@ -3916,7 +3916,7 @@ "group": "Status triplets", "description": "Three-shade status triplets (subtle / muted / strong) for each status role. Use subtle for backgrounds, muted for fills, strong for text on light surfaces.", "note": "Light info tint for informational note backgrounds.", - "value": "oklch(from var(--sf-color-info) l c h / 0.1)", + "value": "oklch(from var(--sf-color-info) l c h / 0.12)", "aliasOf": null, "registered": false, "syntax": null, diff --git a/core/tokens.css b/core/tokens.css index 319103dd..d5dcc398 100644 --- a/core/tokens.css +++ b/core/tokens.css @@ -608,11 +608,11 @@ --sf-color-warning-muted: oklch(from var(--sf-color-warning) l c h / 0.3); --sf-color-warning-tint: oklch(from var(--sf-color-warning) l c h / 0.05); - --sf-color-info-subtle: oklch(from var(--sf-color-info) l c h / 0.1); + --sf-color-info-subtle: oklch(from var(--sf-color-info) l c h / 0.12); --sf-color-info-muted: oklch(from var(--sf-color-info) l c h / 0.3); --sf-color-info-tint: oklch(from var(--sf-color-info) l c h / 0.05); - --sf-color-danger-subtle: oklch(from var(--sf-color-danger) l c h / 0.1); + --sf-color-danger-subtle: oklch(from var(--sf-color-danger) l c h / 0.12); --sf-color-danger-muted: oklch(from var(--sf-color-danger) l c h / 0.3); --sf-color-danger-tint: oklch(from var(--sf-color-danger) l c h / 0.05); diff --git a/dist/css-custom-data.json b/dist/css-custom-data.json index 0409883e..3763c8aa 100644 --- a/dist/css-custom-data.json +++ b/dist/css-custom-data.json @@ -893,7 +893,7 @@ }, { "name": "--sf-color-danger-subtle", - "description": "Light danger tint for error row backgrounds and alert container fills.\n\nDefault: `oklch(from var(--sf-color-danger) l c h / 0.1)`", + "description": "Light danger tint for error row backgrounds and alert container fills.\n\nDefault: `oklch(from var(--sf-color-danger) l c h / 0.12)`", "syntax": "*" }, { @@ -938,7 +938,7 @@ }, { "name": "--sf-color-info-subtle", - "description": "Light info tint for informational note backgrounds.\n\nDefault: `oklch(from var(--sf-color-info) l c h / 0.1)`", + "description": "Light info tint for informational note backgrounds.\n\nDefault: `oklch(from var(--sf-color-info) l c h / 0.12)`", "syntax": "*" }, { diff --git a/docs/api-index.json b/docs/api-index.json index ddfbc63a..56b4f147 100644 --- a/docs/api-index.json +++ b/docs/api-index.json @@ -4684,7 +4684,7 @@ "area": "core", "group": "Status triplets", "description": "Light danger tint for error row backgrounds and alert container fills.", - "value": "oklch(from var(--sf-color-danger) l c h / 0.1)", + "value": "oklch(from var(--sf-color-danger) l c h / 0.12)", "aliasOf": null, "registered": false, "animatable": false, @@ -4918,7 +4918,7 @@ "area": "core", "group": "Status triplets", "description": "Light info tint for informational note backgrounds.", - "value": "oklch(from var(--sf-color-info) l c h / 0.1)", + "value": "oklch(from var(--sf-color-info) l c h / 0.12)", "aliasOf": null, "registered": false, "animatable": false, diff --git a/docs/api-index.md b/docs/api-index.md index 6c94ff19..fa63420c 100644 --- a/docs/api-index.md +++ b/docs/api-index.md @@ -188,7 +188,7 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-danger-source-dark` | PUBLIC | knob | color | `oklch(0.71 0.198 12)` | Registered dark counterpart of --sf-color-danger. | | `--sf-color-danger-source-light` | PUBLIC | knob | color | `oklch(0.48 0.22 12)` | OKLCH lightness source for the danger status color (covers destructive actions and form validation errors). | | `--sf-color-danger-strong` | PUBLIC | consumption | color | `light-dark( oklch(from var(--sf-color-danger-source-light) calc(l - 0.1) c h), oklch(from var(--sf-color-danger) clamp(0.70, calc(l + 0.15), 1) c h) )` | High-contrast danger color for alert body text and icons. | -| `--sf-color-danger-subtle` | PUBLIC | consumption | color | `oklch(from var(--sf-color-danger) l c h / 0.1)` | Light danger tint for error row backgrounds and alert container fills. | +| `--sf-color-danger-subtle` | PUBLIC | consumption | color | `oklch(from var(--sf-color-danger) l c h / 0.12)` | Light danger tint for error row backgrounds and alert container fills. | | `--sf-color-danger-tint` | PUBLIC | consumption | color | `oklch(from var(--sf-color-danger) l c h / 0.05)` | Near-transparent danger tint (5% alpha) for hover-state washes and the most subtle backgrounds. | | `--sf-color-dim` | PUBLIC | knob | color | `oklch(0 0 0 / 0.5)` | Backdrop overlay color for modals, drawers, and lightboxes. | | `--sf-color-heading` | PUBLIC | consumption | color | `light-dark( oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h), oklch(from var(--sf-color-neutral) clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1) c h) )` | Heading text color. Slightly stronger contrast than body text for visual hierarchy. | @@ -197,7 +197,7 @@ and a short description. The machine-readable companion (with all columns) is | `--sf-color-info-source-dark` | PUBLIC | knob | color | `oklch(0.71 0.162 235)` | Registered dark counterpart of --sf-color-info. | | `--sf-color-info-source-light` | PUBLIC | knob | color | `oklch(0.48 0.18 235)` | OKLCH lightness source for the info status color. | | `--sf-color-info-strong` | PUBLIC | consumption | color | `light-dark( oklch(from var(--sf-color-info-source-light) calc(l - 0.1) c h), oklch(from var(--sf-color-info) clamp(0.70, calc(l + 0.15), 1) c h) )` | High-contrast info color for hint body text. | -| `--sf-color-info-subtle` | PUBLIC | consumption | color | `oklch(from var(--sf-color-info) l c h / 0.1)` | Light info tint for informational note backgrounds. | +| `--sf-color-info-subtle` | PUBLIC | consumption | color | `oklch(from var(--sf-color-info) l c h / 0.12)` | Light info tint for informational note backgrounds. | | `--sf-color-info-tint` | PUBLIC | consumption | color | `oklch(from var(--sf-color-info) l c h / 0.05)` | Near-transparent info tint (5% alpha) for hover-state washes and the most subtle backgrounds. | | `--sf-color-inset` | PUBLIC | consumption | color | `oklch(from var(--sf-color-base) calc(l - 0.02) c h)` | Slightly inset surface for nested areas — inputs, code blocks, sidebar panels. | | `--sf-color-inverse` | PUBLIC | consumption | color | `oklch(from var(--sf-color-base) calc(1 - l) c h)` | Inverted (dark-on-light / light-on-dark) surface for high-contrast banners or tooltips. | diff --git a/docs/token-index.json b/docs/token-index.json index 401c896f..498f8ff4 100644 --- a/docs/token-index.json +++ b/docs/token-index.json @@ -1451,7 +1451,7 @@ "files": [ "core/tokens.css" ], - "value": "oklch(from var(--sf-color-danger) l c h / 0.1)" + "value": "oklch(from var(--sf-color-danger) l c h / 0.12)" }, "--sf-color-danger-tint": { "tier": "PUBLIC", @@ -1523,7 +1523,7 @@ "files": [ "core/tokens.css" ], - "value": "oklch(from var(--sf-color-info) l c h / 0.1)" + "value": "oklch(from var(--sf-color-info) l c h / 0.12)" }, "--sf-color-info-tint": { "tier": "PUBLIC", diff --git a/docs/token-index.md b/docs/token-index.md index 7cf95e8e..42533b76 100644 --- a/docs/token-index.md +++ b/docs/token-index.md @@ -266,7 +266,7 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-danger-source-dark` | PUBLIC | knob | Core | `oklch(0.71 0.198 12) (registered)` | | `--sf-color-danger-source-light` | PUBLIC | knob | Core | `oklch(0.48 0.22 12)` | | `--sf-color-danger-strong` | PUBLIC | consumption | Core | `light-dark( oklch(from var(--sf-color-danger-source-light) calc(l - 0.1) c h), oklch(from var(--sf-color-danger) clamp(0.70, calc(l + 0.15), 1) c h) )` | -| `--sf-color-danger-subtle` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-danger) l c h / 0.1)` | +| `--sf-color-danger-subtle` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-danger) l c h / 0.12)` | | `--sf-color-danger-tint` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-danger) l c h / 0.05)` | | `--sf-color-dim` | PUBLIC | knob | Core | `oklch(0 0 0 / 0.5)` | | `--sf-color-heading` | PUBLIC | consumption | Core | `light-dark( oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h), oklch(from var(--sf-color-neutral) clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1) c h) )` | @@ -275,7 +275,7 @@ declared value (a value that references `var(--sf-…)` is a derived output): | `--sf-color-info-source-dark` | PUBLIC | knob | Core | `oklch(0.71 0.162 235) (registered)` | | `--sf-color-info-source-light` | PUBLIC | knob | Core | `oklch(0.48 0.18 235)` | | `--sf-color-info-strong` | PUBLIC | consumption | Core | `light-dark( oklch(from var(--sf-color-info-source-light) calc(l - 0.1) c h), oklch(from var(--sf-color-info) clamp(0.70, calc(l + 0.15), 1) c h) )` | -| `--sf-color-info-subtle` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-info) l c h / 0.1)` | +| `--sf-color-info-subtle` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-info) l c h / 0.12)` | | `--sf-color-info-tint` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-info) l c h / 0.05)` | | `--sf-color-inset` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-base) calc(l - 0.02) c h)` | | `--sf-color-inverse` | PUBLIC | consumption | Core | `oklch(from var(--sf-color-base) calc(1 - l) c h)` | diff --git a/docs/tokens.md b/docs/tokens.md index 8fdf67f5..4662992c 100644 --- a/docs/tokens.md +++ b/docs/tokens.md @@ -130,7 +130,7 @@ rebrand workflow. | `--sf-color-danger-source-dark` | `oklch(0.71 0.198 12) *(registered)*` | | `--sf-color-danger-source-light` | `oklch(0.48 0.22 12)` | | `--sf-color-danger-strong` | `light-dark( oklch(from var(--sf-color-danger-source-light) calc(l - 0.1) c h), oklch(from var(--sf-color-danger) clamp(0.70, calc(l + 0.15), 1) c h) )` | -| `--sf-color-danger-subtle` | `oklch(from var(--sf-color-danger) l c h / 0.1)` | +| `--sf-color-danger-subtle` | `oklch(from var(--sf-color-danger) l c h / 0.12)` | | `--sf-color-danger-tint` | `oklch(from var(--sf-color-danger) l c h / 0.05)` | | `--sf-color-dim` | `oklch(0 0 0 / 0.5)` | | `--sf-color-heading` | `light-dark( oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h), oklch(from var(--sf-color-neutral) clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1) c h) )` | @@ -139,7 +139,7 @@ rebrand workflow. | `--sf-color-info-source-dark` | `oklch(0.71 0.162 235) *(registered)*` | | `--sf-color-info-source-light` | `oklch(0.48 0.18 235)` | | `--sf-color-info-strong` | `light-dark( oklch(from var(--sf-color-info-source-light) calc(l - 0.1) c h), oklch(from var(--sf-color-info) clamp(0.70, calc(l + 0.15), 1) c h) )` | -| `--sf-color-info-subtle` | `oklch(from var(--sf-color-info) l c h / 0.1)` | +| `--sf-color-info-subtle` | `oklch(from var(--sf-color-info) l c h / 0.12)` | | `--sf-color-info-tint` | `oklch(from var(--sf-color-info) l c h / 0.05)` | | `--sf-color-inset` | `oklch(from var(--sf-color-base) calc(l - 0.02) c h)` | | `--sf-color-inverse` | `oklch(from var(--sf-color-base) calc(1 - l) c h)` | diff --git a/user-manual/system-kolorow.md b/user-manual/system-kolorow.md index 628bb65e..40c7ee84 100644 --- a/user-manual/system-kolorow.md +++ b/user-manual/system-kolorow.md @@ -422,57 +422,12 @@ Te nadpisania trzymaj w warstwie `slashed.overrides`, żeby przetrwały aktualiz 4. **Użycie `.sf-surface--inverse` na całym ciemnym pasie z kartami i formularzem.** → To zadanie dla `data-theme="dark"`; `.sf-surface--*` jest do pojedynczego klocka (§2). 5. **Rampa numeryczna (`-200`) na elemencie pływającym nad nieznanym tłem.** - → Użyj wariantu alfa (`-subtle` / `-tint`), bo rampa jest liczona pod konkretne tło (§6). + → Użyj wariantu alfa (`-subtle` / `-tint`), bo krok rampy to kolor jednolity i nie wtapia się w nieznane tło (§6). 6. **Ręczne dobieranie czerni/bieli na kolorowym tle.** → `--sf-color-text--on-*` (§7). --- -## 9. Znalezione nieścisłości we frameworku - -Podczas pisania tej instrukcji przejrzałem źródła. Poniżej to, co warto poprawić — -nic krytycznego, ale realne: - -### 9.1. Niespójna alfa w `-subtle` dla statusów *(realna nieścisłość)* - -W `core/tokens.css` (blok „Status triplets”) warianty `-subtle` nie mają jednej alfy: - -```css ---sf-color-success-subtle: … / 0.12; ---sf-color-warning-subtle: … / 0.12; ---sf-color-info-subtle: … / 0.1; /* ← 10%, nie 12% */ ---sf-color-danger-subtle: … / 0.1; /* ← 10%, nie 12% */ -``` - -`success` i `warning` mają 12%, a `info` i `danger` 10% — mimo że siedzą pod tym -samym komentarzem „triplet” i pełnią tę samą rolę (tło alertu). Dokumentacja -(`user-manual/colors.md`) opisuje je zbiorczo jako „~12% alpha”. Efekt: pudełko -alertu błędu (`danger`) będzie odrobinę bledsze niż sukcesu przy tej samej treści. -**Sugestia:** ujednolicić wszystkie cztery do `0.12` (albo świadomie udokumentować -różnicę). `-muted` (0.3) i `-tint` (0.05) są już spójne we wszystkich czterech. - -### 9.2. Kolizja nazwy `-subtle` między marką a statusami *(pułapka, nie błąd)* - -W rampach marki alias `-subtle` = `-a10` = **10%** krycia. W statusach `-subtle` -(dla success/warning) = **12%**. Ta sama końcówka nazwy, inna nieprzezroczystość. -Nie jest to błąd, ale łatwo o pomyłkę, gdy myślisz „subtle to zawsze 10%”. Warte -zdania w dokumentacji. - -### 9.3. Degradacja `.sf-surface--*` na starych silnikach *(świadoma, warto wiedzieć)* - -Auto-kontrast wnętrza powierzchni (przepisanie `--sf-color-heading`, -`--sf-color-link`, obramowań itd. na kolor kontrastowy) siedzi w bloku -`@supports (color: oklch(from red l c h))` w `core/macros.css`. Reguła bazowa -poza tym blokiem ustawia tylko `color` na samej płycie (przez `--sf-color-text--on-*`), -ale **nie** przemapowuje tokenów potomków. Na silnikach bez relatywnego `oklch` -(Chrome < 119, Safari < 16.4, Firefox < 128) nagłówek lub link *wewnątrz* -`.sf-surface--primary` może wziąć ciemne tokeny strony i słabo kontrastować z -kolorowym tłem. To celowa, udokumentowana degradacja — ale jeśli wspierasz stare -przeglądarki i wkładasz nagłówki/linki do kolorowych płyt, przetestuj to albo -przypnij kolory jawnie w `slashed.overrides`. - ---- - -## 10. Ściąga „potrzebuję…” +## 9. Ściąga „potrzebuję…” | Potrzebuję… | Sięgam po | |---|---| From 69acb25bf66c1341ff526ba290c5483abab341f8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Jul 2026 19:12:46 +0000 Subject: [PATCH 7/7] docs(demo): sync danger/info -subtle coverage defaults to 0.12 The status -subtle alpha was unified to 0.12, but the hand-maintained data-cov-default display strings for --sf-color-danger-subtle and --sf-color-info-subtle in the coverage inventory still read 0.1 (PR #627 review). Display-only; all four status -subtle now show 0.12. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012X2fkd5DbmNJywKcNy6NjF --- demo/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/index.html b/demo/index.html index f009242c..429f244c 100644 --- a/demo/index.html +++ b/demo/index.html @@ -4451,7 +4451,7 @@

Design tokens 7
--sf-color-danger-source-dark
--sf-color-danger-source-light
--sf-color-danger-strong
-
--sf-color-danger-subtle
+
--sf-color-danger-subtle
--sf-color-danger-tint
--sf-color-dim
--sf-color-heading
@@ -4460,7 +4460,7 @@

Design tokens 7
--sf-color-info-source-dark
--sf-color-info-source-light
--sf-color-info-strong
-
--sf-color-info-subtle
+
--sf-color-info-subtle
--sf-color-info-tint
--sf-color-inset
--sf-color-inverse