Files
mono/shared/sx/style_dict.py
giles 19d59f5f4b Implement CSSX Phase 2: native SX style primitives
Replace Tailwind class strings with native SX expressions:
(css :flex :gap-4 :hover:bg-sky-200) instead of :class "flex gap-4 ..."

- Add style_dict.py: 516 atoms, variants, breakpoints, keyframes, patterns
- Add style_resolver.py: memoized resolver with variant splitting
- Add StyleValue type to types.py (frozen dataclass with class_name, declarations, etc.)
- Add css and merge-styles primitives to primitives.py
- Add defstyle and defkeyframes special forms to evaluator.py and async_eval.py
- Integrate StyleValue into html.py and async_eval.py render paths
- Add register_generated_rule() to css_registry.py, fix media query selector
- Add style dict JSON delivery with localStorage caching to helpers.py
- Add client-side css primitive, resolver, and style injection to sx.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:47:51 +00:00

736 lines
37 KiB
Python

"""
Style dictionary — maps keyword atoms to CSS declarations.
Pure data. Each key is a Tailwind-compatible class name (used as an sx keyword
atom in ``(css :flex :gap-4 :p-2)``), and each value is the CSS declaration(s)
that class produces. Declarations are self-contained — no ``--tw-*`` custom
properties needed.
Generated from the codebase's tw.css via ``css_registry.py`` then simplified
to remove Tailwind v3 variable indirection.
Used by:
- ``style_resolver.py`` (server) — resolves ``(css ...)`` to StyleValue
- ``sx.js`` (client) — same resolution, cached in localStorage
"""
from __future__ import annotations
# ═══════════════════════════════════════════════════════════════════════════
# Base atoms — keyword → CSS declarations
# ═══════════════════════════════════════════════════════════════════════════
#
# ~466 atoms covering all utilities used across the codebase.
# Variants (hover:*, sm:*, focus:*, etc.) are NOT stored here — the
# resolver splits "hover:bg-sky-200" into variant="hover" + atom="bg-sky-200"
# and wraps the declaration in the appropriate pseudo/media rule.
STYLE_ATOMS: dict[str, str] = {
# ── Display ──────────────────────────────────────────────────────────
"block": "display:block",
"inline-block": "display:inline-block",
"inline": "display:inline",
"flex": "display:flex",
"inline-flex": "display:inline-flex",
"table": "display:table",
"grid": "display:grid",
"contents": "display:contents",
"hidden": "display:none",
# ── Position ─────────────────────────────────────────────────────────
"static": "position:static",
"fixed": "position:fixed",
"absolute": "position:absolute",
"relative": "position:relative",
"inset-0": "inset:0",
"top-0": "top:0",
"top-1/2": "top:50%",
"top-2": "top:.5rem",
"top-20": "top:5rem",
"top-[8px]": "top:8px",
"top-full": "top:100%",
"right-2": "right:.5rem",
"right-[8px]": "right:8px",
"bottom-full": "bottom:100%",
"left-1/2": "left:50%",
"left-2": "left:.5rem",
"-right-2": "right:-.5rem",
"-right-3": "right:-.75rem",
"-top-1.5": "top:-.375rem",
"-top-2": "top:-.5rem",
# ── Z-Index ──────────────────────────────────────────────────────────
"z-10": "z-index:10",
"z-40": "z-index:40",
"z-50": "z-index:50",
# ── Grid ─────────────────────────────────────────────────────────────
"grid-cols-1": "grid-template-columns:repeat(1,minmax(0,1fr))",
"grid-cols-2": "grid-template-columns:repeat(2,minmax(0,1fr))",
"grid-cols-3": "grid-template-columns:repeat(3,minmax(0,1fr))",
"grid-cols-4": "grid-template-columns:repeat(4,minmax(0,1fr))",
"grid-cols-5": "grid-template-columns:repeat(5,minmax(0,1fr))",
"grid-cols-6": "grid-template-columns:repeat(6,minmax(0,1fr))",
"grid-cols-7": "grid-template-columns:repeat(7,minmax(0,1fr))",
"grid-cols-12": "grid-template-columns:repeat(12,minmax(0,1fr))",
"col-span-2": "grid-column:span 2/span 2",
"col-span-3": "grid-column:span 3/span 3",
"col-span-4": "grid-column:span 4/span 4",
"col-span-5": "grid-column:span 5/span 5",
"col-span-12": "grid-column:span 12/span 12",
"col-span-full": "grid-column:1/-1",
# ── Flexbox ──────────────────────────────────────────────────────────
"flex-row": "flex-direction:row",
"flex-col": "flex-direction:column",
"flex-wrap": "flex-wrap:wrap",
"flex-1": "flex:1 1 0%",
"flex-shrink-0": "flex-shrink:0",
"shrink-0": "flex-shrink:0",
"flex-shrink": "flex-shrink:1",
# ── Alignment ────────────────────────────────────────────────────────
"items-start": "align-items:flex-start",
"items-end": "align-items:flex-end",
"items-center": "align-items:center",
"items-baseline": "align-items:baseline",
"justify-start": "justify-content:flex-start",
"justify-end": "justify-content:flex-end",
"justify-center": "justify-content:center",
"justify-between": "justify-content:space-between",
"self-start": "align-self:flex-start",
"self-center": "align-self:center",
"place-items-center": "place-items:center",
# ── Gap ───────────────────────────────────────────────────────────────
"gap-px": "gap:1px",
"gap-0.5": "gap:.125rem",
"gap-1": "gap:.25rem",
"gap-1.5": "gap:.375rem",
"gap-2": "gap:.5rem",
"gap-3": "gap:.75rem",
"gap-4": "gap:1rem",
"gap-5": "gap:1.25rem",
"gap-6": "gap:1.5rem",
"gap-8": "gap:2rem",
"gap-[4px]": "gap:4px",
"gap-[8px]": "gap:8px",
"gap-[16px]": "gap:16px",
"gap-x-3": "column-gap:.75rem",
"gap-y-1": "row-gap:.25rem",
# ── Margin ───────────────────────────────────────────────────────────
"m-0": "margin:0",
"m-2": "margin:.5rem",
"mx-1": "margin-left:.25rem;margin-right:.25rem",
"mx-2": "margin-left:.5rem;margin-right:.5rem",
"mx-4": "margin-left:1rem;margin-right:1rem",
"mx-auto": "margin-left:auto;margin-right:auto",
"my-3": "margin-top:.75rem;margin-bottom:.75rem",
"-mb-px": "margin-bottom:-1px",
"mb-1": "margin-bottom:.25rem",
"mb-2": "margin-bottom:.5rem",
"mb-3": "margin-bottom:.75rem",
"mb-4": "margin-bottom:1rem",
"mb-6": "margin-bottom:1.5rem",
"mb-8": "margin-bottom:2rem",
"mb-12": "margin-bottom:3rem",
"mb-[8px]": "margin-bottom:8px",
"mb-[24px]": "margin-bottom:24px",
"ml-1": "margin-left:.25rem",
"ml-2": "margin-left:.5rem",
"ml-4": "margin-left:1rem",
"ml-auto": "margin-left:auto",
"mr-1": "margin-right:.25rem",
"mr-2": "margin-right:.5rem",
"mr-3": "margin-right:.75rem",
"mt-0.5": "margin-top:.125rem",
"mt-1": "margin-top:.25rem",
"mt-2": "margin-top:.5rem",
"mt-3": "margin-top:.75rem",
"mt-4": "margin-top:1rem",
"mt-6": "margin-top:1.5rem",
"mt-8": "margin-top:2rem",
"mt-[8px]": "margin-top:8px",
"mt-[16px]": "margin-top:16px",
"mt-[32px]": "margin-top:32px",
# ── Padding ──────────────────────────────────────────────────────────
"p-0": "padding:0",
"p-1": "padding:.25rem",
"p-1.5": "padding:.375rem",
"p-2": "padding:.5rem",
"p-3": "padding:.75rem",
"p-4": "padding:1rem",
"p-5": "padding:1.25rem",
"p-6": "padding:1.5rem",
"p-8": "padding:2rem",
"px-1": "padding-left:.25rem;padding-right:.25rem",
"px-1.5": "padding-left:.375rem;padding-right:.375rem",
"px-2": "padding-left:.5rem;padding-right:.5rem",
"px-2.5": "padding-left:.625rem;padding-right:.625rem",
"px-3": "padding-left:.75rem;padding-right:.75rem",
"px-4": "padding-left:1rem;padding-right:1rem",
"px-6": "padding-left:1.5rem;padding-right:1.5rem",
"px-[8px]": "padding-left:8px;padding-right:8px",
"px-[12px]": "padding-left:12px;padding-right:12px",
"px-[16px]": "padding-left:16px;padding-right:16px",
"px-[20px]": "padding-left:20px;padding-right:20px",
"py-0.5": "padding-top:.125rem;padding-bottom:.125rem",
"py-1": "padding-top:.25rem;padding-bottom:.25rem",
"py-1.5": "padding-top:.375rem;padding-bottom:.375rem",
"py-2": "padding-top:.5rem;padding-bottom:.5rem",
"py-3": "padding-top:.75rem;padding-bottom:.75rem",
"py-4": "padding-top:1rem;padding-bottom:1rem",
"py-6": "padding-top:1.5rem;padding-bottom:1.5rem",
"py-8": "padding-top:2rem;padding-bottom:2rem",
"py-12": "padding-top:3rem;padding-bottom:3rem",
"py-16": "padding-top:4rem;padding-bottom:4rem",
"py-[6px]": "padding-top:6px;padding-bottom:6px",
"py-[12px]": "padding-top:12px;padding-bottom:12px",
"pb-1": "padding-bottom:.25rem",
"pb-2": "padding-bottom:.5rem",
"pb-3": "padding-bottom:.75rem",
"pb-4": "padding-bottom:1rem",
"pb-6": "padding-bottom:1.5rem",
"pb-8": "padding-bottom:2rem",
"pb-[48px]": "padding-bottom:48px",
"pl-2": "padding-left:.5rem",
"pl-5": "padding-left:1.25rem",
"pl-6": "padding-left:1.5rem",
"pr-1": "padding-right:.25rem",
"pr-2": "padding-right:.5rem",
"pr-4": "padding-right:1rem",
"pt-2": "padding-top:.5rem",
"pt-3": "padding-top:.75rem",
"pt-4": "padding-top:1rem",
"pt-[16px]": "padding-top:16px",
# ── Width ────────────────────────────────────────────────────────────
"w-1": "width:.25rem",
"w-2": "width:.5rem",
"w-4": "width:1rem",
"w-5": "width:1.25rem",
"w-6": "width:1.5rem",
"w-8": "width:2rem",
"w-10": "width:2.5rem",
"w-11": "width:2.75rem",
"w-12": "width:3rem",
"w-16": "width:4rem",
"w-20": "width:5rem",
"w-24": "width:6rem",
"w-28": "width:7rem",
"w-48": "width:12rem",
"w-1/2": "width:50%",
"w-1/3": "width:33.333333%",
"w-1/4": "width:25%",
"w-1/6": "width:16.666667%",
"w-2/6": "width:33.333333%",
"w-3/4": "width:75%",
"w-full": "width:100%",
"w-auto": "width:auto",
"w-[1em]": "width:1em",
"w-[32px]": "width:32px",
# ── Height ───────────────────────────────────────────────────────────
"h-2": "height:.5rem",
"h-4": "height:1rem",
"h-5": "height:1.25rem",
"h-6": "height:1.5rem",
"h-8": "height:2rem",
"h-10": "height:2.5rem",
"h-12": "height:3rem",
"h-14": "height:3.5rem",
"h-16": "height:4rem",
"h-24": "height:6rem",
"h-28": "height:7rem",
"h-48": "height:12rem",
"h-64": "height:16rem",
"h-full": "height:100%",
"h-[1em]": "height:1em",
"h-[30vh]": "height:30vh",
"h-[32px]": "height:32px",
"h-[60vh]": "height:60vh",
# ── Min/Max Dimensions ───────────────────────────────────────────────
"min-w-0": "min-width:0",
"min-w-full": "min-width:100%",
"min-w-[1.25rem]": "min-width:1.25rem",
"min-w-[180px]": "min-width:180px",
"min-h-0": "min-height:0",
"min-h-20": "min-height:5rem",
"min-h-[3rem]": "min-height:3rem",
"min-h-[50vh]": "min-height:50vh",
"max-w-xs": "max-width:20rem",
"max-w-md": "max-width:28rem",
"max-w-lg": "max-width:32rem",
"max-w-2xl": "max-width:42rem",
"max-w-3xl": "max-width:48rem",
"max-w-4xl": "max-width:56rem",
"max-w-full": "max-width:100%",
"max-w-none": "max-width:none",
"max-w-screen-2xl": "max-width:1536px",
"max-w-[360px]": "max-width:360px",
"max-w-[768px]": "max-width:768px",
"max-h-64": "max-height:16rem",
"max-h-96": "max-height:24rem",
"max-h-none": "max-height:none",
"max-h-[448px]": "max-height:448px",
"max-h-[50vh]": "max-height:50vh",
# ── Typography ───────────────────────────────────────────────────────
"text-xs": "font-size:.75rem;line-height:1rem",
"text-sm": "font-size:.875rem;line-height:1.25rem",
"text-base": "font-size:1rem;line-height:1.5rem",
"text-lg": "font-size:1.125rem;line-height:1.75rem",
"text-xl": "font-size:1.25rem;line-height:1.75rem",
"text-2xl": "font-size:1.5rem;line-height:2rem",
"text-3xl": "font-size:1.875rem;line-height:2.25rem",
"text-4xl": "font-size:2.25rem;line-height:2.5rem",
"text-5xl": "font-size:3rem;line-height:1",
"text-6xl": "font-size:3.75rem;line-height:1",
"text-8xl": "font-size:6rem;line-height:1",
"text-[8px]": "font-size:8px",
"text-[9px]": "font-size:9px",
"text-[10px]": "font-size:10px",
"text-[11px]": "font-size:11px",
"text-[13px]": "font-size:13px",
"text-[14px]": "font-size:14px",
"text-[16px]": "font-size:16px",
"text-[18px]": "font-size:18px",
"text-[36px]": "font-size:36px",
"text-[40px]": "font-size:40px",
"text-[0.6rem]": "font-size:.6rem",
"text-[0.65rem]": "font-size:.65rem",
"text-[0.7rem]": "font-size:.7rem",
"font-normal": "font-weight:400",
"font-medium": "font-weight:500",
"font-semibold": "font-weight:600",
"font-bold": "font-weight:700",
"font-mono": "font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace",
"italic": "font-style:italic",
"uppercase": "text-transform:uppercase",
"capitalize": "text-transform:capitalize",
"tabular-nums": "font-variant-numeric:tabular-nums",
"leading-none": "line-height:1",
"leading-tight": "line-height:1.25",
"leading-snug": "line-height:1.375",
"leading-relaxed": "line-height:1.625",
"tracking-tight": "letter-spacing:-.025em",
"tracking-wide": "letter-spacing:.025em",
"tracking-widest": "letter-spacing:.1em",
"text-left": "text-align:left",
"text-center": "text-align:center",
"text-right": "text-align:right",
"align-top": "vertical-align:top",
# ── Text Colors ──────────────────────────────────────────────────────
"text-white": "color:rgb(255 255 255)",
"text-white/80": "color:rgba(255,255,255,.8)",
"text-black": "color:rgb(0 0 0)",
"text-stone-300": "color:rgb(214 211 209)",
"text-stone-400": "color:rgb(168 162 158)",
"text-stone-500": "color:rgb(120 113 108)",
"text-stone-600": "color:rgb(87 83 78)",
"text-stone-700": "color:rgb(68 64 60)",
"text-stone-800": "color:rgb(41 37 36)",
"text-stone-900": "color:rgb(28 25 23)",
"text-slate-400": "color:rgb(148 163 184)",
"text-gray-500": "color:rgb(107 114 128)",
"text-gray-600": "color:rgb(75 85 99)",
"text-red-500": "color:rgb(239 68 68)",
"text-red-600": "color:rgb(220 38 38)",
"text-red-700": "color:rgb(185 28 28)",
"text-red-800": "color:rgb(153 27 27)",
"text-rose-500": "color:rgb(244 63 94)",
"text-rose-600": "color:rgb(225 29 72)",
"text-rose-700": "color:rgb(190 18 60)",
"text-rose-800/80": "color:rgba(159,18,57,.8)",
"text-rose-900": "color:rgb(136 19 55)",
"text-orange-600": "color:rgb(234 88 12)",
"text-amber-500": "color:rgb(245 158 11)",
"text-amber-600": "color:rgb(217 119 6)",
"text-amber-700": "color:rgb(180 83 9)",
"text-amber-800": "color:rgb(146 64 14)",
"text-yellow-700": "color:rgb(161 98 7)",
"text-green-600": "color:rgb(22 163 74)",
"text-green-800": "color:rgb(22 101 52)",
"text-emerald-500": "color:rgb(16 185 129)",
"text-emerald-600": "color:rgb(5 150 105)",
"text-emerald-700": "color:rgb(4 120 87)",
"text-emerald-800": "color:rgb(6 95 70)",
"text-emerald-900": "color:rgb(6 78 59)",
"text-sky-600": "color:rgb(2 132 199)",
"text-sky-700": "color:rgb(3 105 161)",
"text-sky-800": "color:rgb(7 89 133)",
"text-blue-500": "color:rgb(59 130 246)",
"text-blue-600": "color:rgb(37 99 235)",
"text-blue-700": "color:rgb(29 78 216)",
"text-blue-800": "color:rgb(30 64 175)",
"text-purple-600": "color:rgb(147 51 234)",
"text-violet-600": "color:rgb(124 58 237)",
"text-violet-700": "color:rgb(109 40 217)",
"text-violet-800": "color:rgb(91 33 182)",
# ── Background Colors ────────────────────────────────────────────────
"bg-transparent": "background-color:transparent",
"bg-white": "background-color:rgb(255 255 255)",
"bg-white/60": "background-color:rgba(255,255,255,.6)",
"bg-white/70": "background-color:rgba(255,255,255,.7)",
"bg-white/80": "background-color:rgba(255,255,255,.8)",
"bg-white/90": "background-color:rgba(255,255,255,.9)",
"bg-black": "background-color:rgb(0 0 0)",
"bg-black/50": "background-color:rgba(0,0,0,.5)",
"bg-stone-50": "background-color:rgb(250 250 249)",
"bg-stone-100": "background-color:rgb(245 245 244)",
"bg-stone-200": "background-color:rgb(231 229 228)",
"bg-stone-300": "background-color:rgb(214 211 209)",
"bg-stone-400": "background-color:rgb(168 162 158)",
"bg-stone-500": "background-color:rgb(120 113 108)",
"bg-stone-600": "background-color:rgb(87 83 78)",
"bg-stone-700": "background-color:rgb(68 64 60)",
"bg-stone-800": "background-color:rgb(41 37 36)",
"bg-stone-900": "background-color:rgb(28 25 23)",
"bg-slate-100": "background-color:rgb(241 245 249)",
"bg-slate-200": "background-color:rgb(226 232 240)",
"bg-gray-100": "background-color:rgb(243 244 246)",
"bg-red-50": "background-color:rgb(254 242 242)",
"bg-red-100": "background-color:rgb(254 226 226)",
"bg-red-200": "background-color:rgb(254 202 202)",
"bg-red-500": "background-color:rgb(239 68 68)",
"bg-red-600": "background-color:rgb(220 38 38)",
"bg-rose-50": "background-color:rgb(255 241 242)",
"bg-rose-50/80": "background-color:rgba(255,241,242,.8)",
"bg-orange-100": "background-color:rgb(255 237 213)",
"bg-amber-50": "background-color:rgb(255 251 235)",
"bg-amber-50/60": "background-color:rgba(255,251,235,.6)",
"bg-amber-100": "background-color:rgb(254 243 199)",
"bg-amber-500": "background-color:rgb(245 158 11)",
"bg-amber-600": "background-color:rgb(217 119 6)",
"bg-yellow-50": "background-color:rgb(254 252 232)",
"bg-yellow-100": "background-color:rgb(254 249 195)",
"bg-yellow-200": "background-color:rgb(254 240 138)",
"bg-yellow-300": "background-color:rgb(253 224 71)",
"bg-green-50": "background-color:rgb(240 253 244)",
"bg-green-100": "background-color:rgb(220 252 231)",
"bg-emerald-50": "background-color:rgb(236 253 245)",
"bg-emerald-50/80": "background-color:rgba(236,253,245,.8)",
"bg-emerald-100": "background-color:rgb(209 250 229)",
"bg-emerald-200": "background-color:rgb(167 243 208)",
"bg-emerald-500": "background-color:rgb(16 185 129)",
"bg-emerald-600": "background-color:rgb(5 150 105)",
"bg-sky-100": "background-color:rgb(224 242 254)",
"bg-sky-200": "background-color:rgb(186 230 253)",
"bg-sky-300": "background-color:rgb(125 211 252)",
"bg-sky-400": "background-color:rgb(56 189 248)",
"bg-sky-500": "background-color:rgb(14 165 233)",
"bg-blue-50": "background-color:rgb(239 246 255)",
"bg-blue-100": "background-color:rgb(219 234 254)",
"bg-blue-600": "background-color:rgb(37 99 235)",
"bg-purple-600": "background-color:rgb(147 51 234)",
"bg-violet-50": "background-color:rgb(245 243 255)",
"bg-violet-100": "background-color:rgb(237 233 254)",
"bg-violet-200": "background-color:rgb(221 214 254)",
"bg-violet-300": "background-color:rgb(196 181 253)",
"bg-violet-400": "background-color:rgb(167 139 250)",
"bg-violet-500": "background-color:rgb(139 92 246)",
"bg-violet-600": "background-color:rgb(124 58 237)",
# ── Border ───────────────────────────────────────────────────────────
"border": "border-width:1px",
"border-2": "border-width:2px",
"border-4": "border-width:4px",
"border-t": "border-top-width:1px",
"border-t-0": "border-top-width:0",
"border-b": "border-bottom-width:1px",
"border-b-2": "border-bottom-width:2px",
"border-r": "border-right-width:1px",
"border-l-4": "border-left-width:4px",
"border-dashed": "border-style:dashed",
"border-none": "border-style:none",
"border-transparent": "border-color:transparent",
"border-white": "border-color:rgb(255 255 255)",
"border-white/30": "border-color:rgba(255,255,255,.3)",
"border-stone-100": "border-color:rgb(245 245 244)",
"border-stone-200": "border-color:rgb(231 229 228)",
"border-stone-300": "border-color:rgb(214 211 209)",
"border-stone-700": "border-color:rgb(68 64 60)",
"border-red-200": "border-color:rgb(254 202 202)",
"border-red-300": "border-color:rgb(252 165 165)",
"border-rose-200": "border-color:rgb(254 205 211)",
"border-rose-300": "border-color:rgb(253 164 175)",
"border-amber-200": "border-color:rgb(253 230 138)",
"border-amber-300": "border-color:rgb(252 211 77)",
"border-yellow-200": "border-color:rgb(254 240 138)",
"border-green-300": "border-color:rgb(134 239 172)",
"border-emerald-100": "border-color:rgb(209 250 229)",
"border-emerald-200": "border-color:rgb(167 243 208)",
"border-emerald-300": "border-color:rgb(110 231 183)",
"border-emerald-600": "border-color:rgb(5 150 105)",
"border-blue-200": "border-color:rgb(191 219 254)",
"border-blue-300": "border-color:rgb(147 197 253)",
"border-violet-200": "border-color:rgb(221 214 254)",
"border-violet-300": "border-color:rgb(196 181 253)",
"border-violet-400": "border-color:rgb(167 139 250)",
"border-t-white": "border-top-color:rgb(255 255 255)",
"border-t-stone-600": "border-top-color:rgb(87 83 78)",
"border-l-stone-400": "border-left-color:rgb(168 162 158)",
# ── Border Radius ────────────────────────────────────────────────────
"rounded": "border-radius:.25rem",
"rounded-md": "border-radius:.375rem",
"rounded-lg": "border-radius:.5rem",
"rounded-xl": "border-radius:.75rem",
"rounded-2xl": "border-radius:1rem",
"rounded-full": "border-radius:9999px",
"rounded-t": "border-top-left-radius:.25rem;border-top-right-radius:.25rem",
"rounded-b": "border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem",
"rounded-[4px]": "border-radius:4px",
"rounded-[8px]": "border-radius:8px",
# ── Shadow ───────────────────────────────────────────────────────────
"shadow-sm": "box-shadow:0 1px 2px 0 rgba(0,0,0,.05)",
"shadow": "box-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1)",
"shadow-md": "box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)",
"shadow-lg": "box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1)",
"shadow-xl": "box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1)",
# ── Opacity ──────────────────────────────────────────────────────────
"opacity-0": "opacity:0",
"opacity-40": "opacity:.4",
"opacity-50": "opacity:.5",
"opacity-100": "opacity:1",
# ── Ring / Outline ───────────────────────────────────────────────────
"outline-none": "outline:2px solid transparent;outline-offset:2px",
"ring-2": "box-shadow:0 0 0 2px var(--tw-ring-color,rgb(59 130 246))",
"ring-offset-2": "box-shadow:0 0 0 2px rgb(255 255 255),0 0 0 4px var(--tw-ring-color,rgb(59 130 246))",
# ── Overflow ─────────────────────────────────────────────────────────
"overflow-hidden": "overflow:hidden",
"overflow-x-auto": "overflow-x:auto",
"overflow-y-auto": "overflow-y:auto",
"overscroll-contain": "overscroll-behavior:contain",
# ── Text Decoration ──────────────────────────────────────────────────
"underline": "text-decoration-line:underline",
"line-through": "text-decoration-line:line-through",
"no-underline": "text-decoration-line:none",
# ── Text Overflow ────────────────────────────────────────────────────
"truncate": "overflow:hidden;text-overflow:ellipsis;white-space:nowrap",
"line-clamp-2": "display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden",
"line-clamp-3": "display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden",
# ── Whitespace / Word Break ──────────────────────────────────────────
"whitespace-normal": "white-space:normal",
"whitespace-nowrap": "white-space:nowrap",
"whitespace-pre-line": "white-space:pre-line",
"whitespace-pre-wrap": "white-space:pre-wrap",
"break-words": "overflow-wrap:break-word",
"break-all": "word-break:break-all",
# ── Transform ────────────────────────────────────────────────────────
"rotate-180": "transform:rotate(180deg)",
"-translate-x-1/2": "transform:translateX(-50%)",
"-translate-y-1/2": "transform:translateY(-50%)",
# ── Transition ───────────────────────────────────────────────────────
"transition": "transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s",
"transition-all": "transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s",
"transition-colors": "transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s",
"transition-opacity": "transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s",
"transition-transform": "transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s",
"duration-75": "transition-duration:75ms",
"duration-100": "transition-duration:100ms",
"duration-150": "transition-duration:150ms",
"duration-200": "transition-duration:200ms",
"duration-300": "transition-duration:300ms",
"duration-500": "transition-duration:500ms",
"duration-700": "transition-duration:700ms",
# ── Animation ────────────────────────────────────────────────────────
"animate-spin": "animation:spin 1s linear infinite",
"animate-ping": "animation:ping 1s cubic-bezier(0,0,0.2,1) infinite",
"animate-pulse": "animation:pulse 2s cubic-bezier(0.4,0,0.6,1) infinite",
"animate-bounce": "animation:bounce 1s infinite",
"animate-none": "animation:none",
# ── Aspect Ratio ─────────────────────────────────────────────────────
"aspect-square": "aspect-ratio:1/1",
"aspect-video": "aspect-ratio:16/9",
# ── Object Fit / Position ────────────────────────────────────────────
"object-contain": "object-fit:contain",
"object-cover": "object-fit:cover",
"object-center": "object-position:center",
"object-top": "object-position:top",
# ── Cursor ───────────────────────────────────────────────────────────
"cursor-pointer": "cursor:pointer",
"cursor-move": "cursor:move",
# ── User Select ──────────────────────────────────────────────────────
"select-none": "user-select:none",
"select-all": "user-select:all",
# ── Pointer Events ───────────────────────────────────────────────────
"pointer-events-none": "pointer-events:none",
# ── Resize ───────────────────────────────────────────────────────────
"resize": "resize:both",
"resize-none": "resize:none",
# ── Scroll Snap ──────────────────────────────────────────────────────
"snap-y": "scroll-snap-type:y mandatory",
"snap-start": "scroll-snap-align:start",
"snap-mandatory": "scroll-snap-type:y mandatory",
# ── List Style ───────────────────────────────────────────────────────
"list-disc": "list-style-type:disc",
"list-decimal": "list-style-type:decimal",
"list-inside": "list-style-position:inside",
# ── Table ────────────────────────────────────────────────────────────
"table-fixed": "table-layout:fixed",
# ── Backdrop ─────────────────────────────────────────────────────────
"backdrop-blur": "backdrop-filter:blur(8px)",
"backdrop-blur-sm": "backdrop-filter:blur(4px)",
"backdrop-blur-md": "backdrop-filter:blur(12px)",
# ── Filter ───────────────────────────────────────────────────────────
"saturate-0": "filter:saturate(0)",
# ── Space Between (child selector atoms) ─────────────────────────────
# These generate `.atom > :not(:first-child)` rules
"space-y-0": "margin-top:0",
"space-y-0.5": "margin-top:.125rem",
"space-y-1": "margin-top:.25rem",
"space-y-2": "margin-top:.5rem",
"space-y-3": "margin-top:.75rem",
"space-y-4": "margin-top:1rem",
"space-y-6": "margin-top:1.5rem",
"space-y-8": "margin-top:2rem",
"space-y-10": "margin-top:2.5rem",
"space-x-1": "margin-left:.25rem",
"space-x-2": "margin-left:.5rem",
# ── Divide (child selector atoms) ────────────────────────────────────
# These generate `.atom > :not(:first-child)` rules
"divide-y": "border-top-width:1px",
"divide-stone-100": "border-color:rgb(245 245 244)",
"divide-stone-200": "border-color:rgb(231 229 228)",
# ── Important modifiers ──────────────────────────────────────────────
"!bg-stone-500": "background-color:rgb(120 113 108)!important",
"!text-white": "color:rgb(255 255 255)!important",
}
# Atoms that need a child selector: `.atom > :not(:first-child)` instead of `.atom`
CHILD_SELECTOR_ATOMS: frozenset[str] = frozenset({
k for k in STYLE_ATOMS
if k.startswith(("space-x-", "space-y-", "divide-y", "divide-x"))
and not k.startswith("divide-stone")
})
# ═══════════════════════════════════════════════════════════════════════════
# Pseudo-class / pseudo-element variants
# ═══════════════════════════════════════════════════════════════════════════
PSEUDO_VARIANTS: dict[str, str] = {
"hover": ":hover",
"focus": ":focus",
"focus-within": ":focus-within",
"focus-visible": ":focus-visible",
"active": ":active",
"disabled": ":disabled",
"first": ":first-child",
"last": ":last-child",
"odd": ":nth-child(odd)",
"even": ":nth-child(even)",
"empty": ":empty",
"open": "[open]",
"placeholder": "::placeholder",
"file": "::file-selector-button",
"aria-selected": "[aria-selected=true]",
"group-hover": ":is(.group:hover) &",
"group-open": ":is(.group[open]) &",
}
# ═══════════════════════════════════════════════════════════════════════════
# Responsive breakpoints
# ═══════════════════════════════════════════════════════════════════════════
RESPONSIVE_BREAKPOINTS: dict[str, str] = {
"sm": "(min-width:640px)",
"md": "(min-width:768px)",
"lg": "(min-width:1024px)",
"xl": "(min-width:1280px)",
"2xl": "(min-width:1536px)",
}
# ═══════════════════════════════════════════════════════════════════════════
# Keyframes — built-in animation definitions
# ═══════════════════════════════════════════════════════════════════════════
KEYFRAMES: dict[str, str] = {
"spin": "@keyframes spin{to{transform:rotate(360deg)}}",
"ping": "@keyframes ping{75%,100%{transform:scale(2);opacity:0}}",
"pulse": "@keyframes pulse{50%{opacity:.5}}",
"bounce": "@keyframes bounce{0%,100%{transform:translateY(-25%);animation-timing-function:cubic-bezier(0.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,0.2,1)}}",
}
# ═══════════════════════════════════════════════════════════════════════════
# Arbitrary value patterns — fallback when atom not in STYLE_ATOMS
# ═══════════════════════════════════════════════════════════════════════════
#
# Each tuple is (regex_pattern, css_template).
# The regex captures value groups; the template uses {0}, {1}, etc.
ARBITRARY_PATTERNS: list[tuple[str, str]] = [
# Width / Height
(r"w-\[(.+)\]", "width:{0}"),
(r"h-\[(.+)\]", "height:{0}"),
(r"min-w-\[(.+)\]", "min-width:{0}"),
(r"min-h-\[(.+)\]", "min-height:{0}"),
(r"max-w-\[(.+)\]", "max-width:{0}"),
(r"max-h-\[(.+)\]", "max-height:{0}"),
# Spacing
(r"p-\[(.+)\]", "padding:{0}"),
(r"px-\[(.+)\]", "padding-left:{0};padding-right:{0}"),
(r"py-\[(.+)\]", "padding-top:{0};padding-bottom:{0}"),
(r"pt-\[(.+)\]", "padding-top:{0}"),
(r"pb-\[(.+)\]", "padding-bottom:{0}"),
(r"pl-\[(.+)\]", "padding-left:{0}"),
(r"pr-\[(.+)\]", "padding-right:{0}"),
(r"m-\[(.+)\]", "margin:{0}"),
(r"mx-\[(.+)\]", "margin-left:{0};margin-right:{0}"),
(r"my-\[(.+)\]", "margin-top:{0};margin-bottom:{0}"),
(r"mt-\[(.+)\]", "margin-top:{0}"),
(r"mb-\[(.+)\]", "margin-bottom:{0}"),
(r"ml-\[(.+)\]", "margin-left:{0}"),
(r"mr-\[(.+)\]", "margin-right:{0}"),
# Gap
(r"gap-\[(.+)\]", "gap:{0}"),
(r"gap-x-\[(.+)\]", "column-gap:{0}"),
(r"gap-y-\[(.+)\]", "row-gap:{0}"),
# Position
(r"top-\[(.+)\]", "top:{0}"),
(r"right-\[(.+)\]", "right:{0}"),
(r"bottom-\[(.+)\]", "bottom:{0}"),
(r"left-\[(.+)\]", "left:{0}"),
# Border radius
(r"rounded-\[(.+)\]", "border-radius:{0}"),
# Background / Text color
(r"bg-\[(.+)\]", "background-color:{0}"),
(r"text-\[(.+)\]", "font-size:{0}"),
# Grid
(r"grid-cols-\[(.+)\]", "grid-template-columns:{0}"),
(r"col-span-(\d+)", "grid-column:span {0}/span {0}"),
]