actual-css 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/actual.css +1 -0
  3. package/dist/actual.full.css +480 -117
  4. package/dist/actual.full.js +1 -1
  5. package/dist/actual.full.min.css +1 -1
  6. package/dist/actual.min.css +1 -1
  7. package/docs/design-notes/browser-support.md +14 -14
  8. package/docs/design-notes/enhancement-contract.md +30 -13
  9. package/docs/design-notes/forced-colors.md +11 -7
  10. package/docs/design-notes/grid.md +4 -4
  11. package/docs/design-notes/naming.md +15 -9
  12. package/docs/design-notes/platform-alignment.md +9 -0
  13. package/docs/design-notes/references.md +4 -0
  14. package/docs/design-notes/steps.md +748 -0
  15. package/docs/design-notes/widget-primitives.md +32 -15
  16. package/docs/navigation.json +1 -0
  17. package/docs/pages/components/alert.md +13 -8
  18. package/docs/pages/components/aura.md +102 -6
  19. package/docs/pages/components/avatar.md +9 -6
  20. package/docs/pages/components/badge.md +11 -7
  21. package/docs/pages/components/button.md +17 -17
  22. package/docs/pages/components/card.md +15 -8
  23. package/docs/pages/components/chat.md +1 -1
  24. package/docs/pages/components/dialog.md +10 -7
  25. package/docs/pages/components/drawer.md +1 -1
  26. package/docs/pages/components/fab.md +12 -10
  27. package/docs/pages/components/indicator.md +6 -6
  28. package/docs/pages/components/list.md +11 -2
  29. package/docs/pages/components/navbar.md +1 -1
  30. package/docs/pages/components/pagination.md +1 -1
  31. package/docs/pages/components/rating.md +4 -4
  32. package/docs/pages/components/skeleton.md +1 -1
  33. package/docs/pages/components/spinner.md +1 -1
  34. package/docs/pages/components/steps.md +376 -52
  35. package/docs/pages/components/table.md +5 -5
  36. package/docs/pages/enhancements/flyout.md +12 -10
  37. package/docs/pages/enhancements/overview.md +2 -2
  38. package/docs/pages/enhancements/scrollspy.md +1 -1
  39. package/docs/pages/enhancements/tabs.md +1 -1
  40. package/docs/pages/examples/overview.md +2 -0
  41. package/docs/pages/forms/choice-cards.md +4 -4
  42. package/docs/pages/forms/combobox.md +87 -0
  43. package/docs/pages/forms/floating-field.md +5 -3
  44. package/docs/pages/forms/joined-controls.md +4 -4
  45. package/docs/pages/forms/labels.md +8 -5
  46. package/docs/pages/forms/overview.md +25 -18
  47. package/docs/pages/forms/password.md +3 -2
  48. package/docs/pages/forms/range.md +13 -2
  49. package/docs/pages/forms/states-and-sizes.md +6 -4
  50. package/docs/pages/forms/validation.md +13 -9
  51. package/docs/pages/foundations/tokens.md +9 -6
  52. package/docs/pages/foundations/typography.md +1 -1
  53. package/docs/pages/guides/bootstrap.md +3 -3
  54. package/docs/pages/guides/introduction.md +1 -1
  55. package/docs/pages/guides/modular-import.md +21 -10
  56. package/docs/pages/guides/progressive-enhancement.md +75 -54
  57. package/docs/pages/guides/tailwind.md +2 -2
  58. package/docs/pages/layout/app-shell.md +4 -4
  59. package/docs/pages/layout/choosing.md +10 -6
  60. package/docs/pages/layout/grid.md +11 -10
  61. package/docs/pages/layout/stack.md +10 -6
  62. package/docs/pages/patterns/structured-lists.md +7 -7
  63. package/docs/pages/utilities/accessibility.md +1 -1
  64. package/docs/pages/utilities/flex.md +20 -13
  65. package/docs/pages/utilities/links.md +1 -1
  66. package/docs/pages/utilities/list.md +1 -1
  67. package/docs/pages/utilities/overflow.md +14 -7
  68. package/docs/pages/utilities/overview.md +22 -0
  69. package/docs/pages/utilities/shape.md +1 -1
  70. package/docs/pages/utilities/sizing-wrapping.md +10 -8
  71. package/docs/pages/utilities/spacing.md +26 -19
  72. package/docs/pages/utilities/text.md +1 -1
  73. package/llms.txt +27 -4
  74. package/package.json +3 -2
  75. package/scripts/reserved-classes.json +4 -1
  76. package/src/css/components/fab.css +44 -8
  77. package/src/css/components/list.css +3 -1
  78. package/src/css/components/steps.css +277 -69
  79. package/src/css/core/tokens.css +1 -0
  80. package/src/css/effects/aura.css +101 -11
  81. package/src/css/forms/custom-select.css +1 -1
  82. package/src/css/forms/floating-field.css +8 -6
  83. package/src/css/layout/container-query.css +37 -13
  84. package/src/css/layout/grid.css +7 -7
  85. package/src/css/layout/index.css +1 -1
  86. package/src/js/password.js +1 -1
@@ -1 +1 @@
1
- *, *::before, *::after { box-sizing: border-box; } html { -webkit-text-size-adjust: 100%; } body { margin: 0; } button, input, textarea, select { font: inherit; } [hidden]:not([hidden="until-found"]) { display: none !important; } :where(img, svg, video) { max-inline-size: 100%; block-size: auto; } @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto !important; } *, *::before, *::after { animation-duration: 0.01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; transition-delay: 0s !important; } } :root { --font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; --line-height: 1.5; --line-height-tight: 1.25; --line-height-relaxed: 1.75; --font-weight: 400; --font-weight-medium: 500; --font-weight-strong: 650; --font-weight-bold: 700; --font-size-xs: 0.8125rem; --font-size-sm: 0.875rem; --font-size-md: 1rem; --font-size-lg: 1.125rem; --gap: 0.75rem; --density-space: var(--space-40); --density-compact-size: 1.5rem; --space-10: 0.25rem; --space-20: 0.5rem; --space-30: 0.75rem; --space-40: 1rem; --space-50: 1.5rem; --space-60: 2rem; --border-width: 1px; --radius-full: 9999px; --shadow: 0 1px 3px rgb(0 0 0 / 0.05), 0 4px 12px rgb(0 0 0 / 0.04); --shadow-popout: 0 0.25rem 0.75rem rgb(0 0 0 / 0.15); --duration: 150ms; --duration-fast: 100ms; --duration-slow: 200ms; --duration-spin: 0.75s; --duration-shimmer: 1.2s; --ease-enter: cubic-bezier(0.2, 0, 0, 1); --ease-exit: cubic-bezier(0.4, 0, 1, 1); --focus-outline-color: currentColor; --focus-outline: calc(var(--border-width) * 2) solid var(--focus-outline-color); --focus-outline-offset: 2px; --focus-ring-width: 3px; --indicator-offset: 14.65%; --backdrop-color: rgb(0 0 0); --backdrop-opacity: 0.45; --backdrop-fill: rgb(0 0 0 / var(--backdrop-opacity)); --bar-height: 0.65rem; --control-size-sm: 2rem; --control-size-md: 2.375rem; --control-size-lg: 2.75rem; --control-size: var(--control-size-md); --control-pad-x: 1em; --control-font-size: var(--font-size-md); --choice-control-size: 1.125em; --disabled-opacity: 0.65; } :root, [data-theme] { --state-selected: var(--primary); --state-selected-fg: var(--primary-fg); --state-disabled: var(--text-subtle); --indicator-ring: var(--surface); } :root { --soft-bg-mix: 88%; --soft-border-mix: 65%; --soft-hover-alpha: 12%; --soft-fg-mix: 100%; --icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238a8594' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); --icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3C/svg%3E"); --viewport-block: 100vh; --viewport-inline: 100vw; --z-sticky: 10; --z-menu: 20; --z-tooltip: 50; --z-status: 60; } @media (forced-colors: active) { :root, [data-theme] { --state-disabled: GrayText; --disabled-opacity: 1; } } @supports (block-size: 100dvh) { :root { --viewport-block: 100dvh; } } @supports (inline-size: 100vi) { :root { --viewport-inline: 100vi; } } @supports (color: color-mix(in oklch, red, white)) { :root, [data-theme] { --shadow: 0 1px 3px color-mix(in oklch, var(--shadow-color) 5%, transparent), 0 4px 12px color-mix(in oklch, var(--shadow-color) 4%, transparent); --shadow-popout: 0 0.25rem 0.75rem color-mix(in oklch, var(--shadow-color) 15%, transparent); } :root { --backdrop-fill: color-mix( in oklch, var(--backdrop-color) calc(var(--backdrop-opacity) * 100%), transparent ); } } :root { color-scheme: light dark; } [data-theme="light"] { color-scheme: light; } [data-theme="dark"] { color-scheme: dark; } @supports not (color: light-dark(red, blue)) { :root, [data-theme="light"], [data-theme="dark"] { color-scheme: light; } } :root, [data-theme="light"] { --primary: hsl(268 32% 33%); --primary-fg: hsl(0 0% 98%); --secondary: hsl(16 38% 38%); --secondary-fg: hsl(0 0% 98%); --success: hsl(150 40% 31%); --success-fg: hsl(0 0% 98%); --warning: hsl(36 68% 34%); --warning-fg: hsl(0 0% 98%); --danger: hsl(5 58% 43%); --danger-fg: hsl(0 0% 98%); --neutral: hsl(258 7% 43%); --neutral-fg: hsl(0 0% 98%); --surface: hsl(0 0% 100%); --surface-raised: hsl(0 0% 100%); --surface-subtle: hsl(262 24% 96%); --surface-solid: hsl(261 16% 13%); --text: hsl(261 20% 13%); --text-muted: hsl(259 9% 42%); --text-subtle: hsl(258 7% 57%); --border: hsl(260 15% 88%); --focus: var(--neutral); --focus-ring: hsl(258 7% 43% / 0.3); --hover-overlay: hsl(260 20% 10% / 0.04); --radius: 0.5rem; --radius-sm: 0.25rem; --radius-lg: 0.75rem; --shadow-color: hsl(260 25% 10%); --hgroup-gap: 0.25em; } :root, [data-theme] { --heading: var(--text); --selection-bg: var(--primary); --selection-fg: var(--primary-fg); --focus-ring-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring); } :root, [data-theme] { accent-color: var(--primary); } [data-tone="dark"] { --tone-fg: white; } [data-tone="light"] { --tone-fg: var(--text); } @supports (color: color-mix(in oklch, red, white)) { :root, [data-theme] { --focus-ring: color-mix(in oklch, var(--focus) 30%, transparent); } } @supports (color: light-dark(red, blue)) { :root, [data-theme="light"] { --primary: light-dark(hsl(268 32% 33%), hsl(268 42% 76%)); --primary-fg: light-dark(hsl(0 0% 98%), hsl(268 30% 12%)); --secondary: light-dark(hsl(16 38% 38%), hsl(18 45% 72%)); --secondary-fg: light-dark(hsl(0 0% 98%), hsl(18 32% 11%)); --success: light-dark(hsl(150 40% 31%), hsl(150 38% 62%)); --success-fg: light-dark(hsl(0 0% 98%), hsl(150 35% 8%)); --warning: light-dark(hsl(36 68% 34%), hsl(40 62% 64%)); --warning-fg: light-dark(hsl(0 0% 98%), hsl(38 35% 10%)); --danger: light-dark(hsl(5 58% 43%), hsl(4 60% 70%)); --danger-fg: light-dark(hsl(0 0% 98%), hsl(4 35% 10%)); --neutral: light-dark(hsl(258 7% 43%), hsl(258 10% 72%)); --neutral-fg: light-dark(hsl(0 0% 98%), hsl(260 18% 10%)); --surface: light-dark(hsl(0 0% 100%), hsl(263 17% 9%)); --surface-raised: light-dark(hsl(0 0% 100%), hsl(263 15% 12%)); --surface-subtle: light-dark(hsl(262 24% 96%), hsl(263 13% 16%)); --surface-solid: light-dark(hsl(261 16% 13%), hsl(0 0% 96%)); --text: light-dark(hsl(261 20% 13%), hsl(260 12% 95%)); --text-muted: light-dark(hsl(259 9% 42%), hsl(259 9% 67%)); --text-subtle: light-dark(hsl(258 7% 57%), hsl(258 7% 54%)); --border: light-dark(hsl(260 15% 88%), hsl(262 12% 24%)); --focus-ring: light-dark(hsl(258 7% 43% / 0.3), hsl(258 10% 72% / 0.28)); --hover-overlay: light-dark(hsl(260 20% 10% / 0.04), hsl(0 0% 100% / 0.06)); --shadow-color: light-dark(hsl(260 25% 10%), hsl(262 40% 2%)); } } @supports (color: color-mix(in oklch, red, white)) and (color: light-dark(red, blue)) { :root, [data-theme] { --focus-ring: light-dark( color-mix(in oklch, var(--focus) 30%, transparent), color-mix(in oklch, var(--focus) 28%, transparent) ); } } @media (prefers-contrast: more) { :root, [data-theme][data-theme] { --border-width: 2px; --focus-outline-offset: 3px; --focus-ring-width: 4px; --text-muted: var(--text); --text-subtle: var(--text); } } body { background: var(--surface); color: var(--text); font-family: var(--font-sans); line-height: var(--line-height); } a { color: var(--link, inherit); text-underline-offset: 0.18em; } a:hover { text-decoration-thickness: 0.12em; } :where(h1, h2, h3, h4, h5, h6) { color: var(--heading, inherit); line-height: var(--line-height-tight); text-wrap: balance; } hgroup { display: grid; gap: var(--hgroup-gap); } hgroup > * { margin-block: 0; } hr { border: 0; border-block-start: var(--border-width) solid var(--border); margin-block: var(--space-60); } code, kbd, samp, pre { font-family: var(--font-mono); } small { font-size: 0.875em; } ::selection { background: var(--selection-bg, var(--primary)); color: var(--selection-fg, var(--primary-fg)); } .primary { --intent: var(--primary); --intent-fg: var(--primary-fg); } .secondary { --intent: var(--secondary); --intent-fg: var(--secondary-fg); } .success { --intent: var(--success); --intent-fg: var(--success-fg); } .warning { --intent: var(--warning); --intent-fg: var(--warning-fg); } .danger { --intent: var(--danger); --intent-fg: var(--danger-fg); } .neutral { --intent: var(--neutral); --intent-fg: var(--neutral-fg); } .intent-color { color: var(--intent); } .solid { --ui-bg: var(--intent, var(--neutral)); --ui-fg: var(--intent-fg, var(--neutral-fg)); --ui-border: transparent; } .soft { --ui-bg: var(--surface-subtle); --ui-border: var(--border); --ui-fg: var(--intent, var(--text)); } .outline { --ui-bg: transparent; --ui-fg: var(--intent, currentColor); --ui-border: var(--intent, currentColor); } .surface { --ui-bg: var(--surface); --ui-fg: var(--intent, var(--text)); --ui-border: var(--border); } .inverted { --ui-bg: var(--surface-solid); --ui-fg: var(--surface); --ui-border: transparent; --ui-hover-bg: var(--surface-solid); --heading: var(--surface); --busy-overlay-bg: var(--surface-solid); background: var(--ui-bg); color: var(--ui-fg); border-color: var(--ui-border); } .sm { --gap: var(--space-20); --density-space: var(--space-20); --control-size: var(--control-size-sm); --density-compact-size: 1.25rem; } .lg { --gap: var(--space-50); --density-space: var(--space-50); --control-size: var(--control-size-lg); --density-compact-size: 1.875rem; } @supports (color: color-mix(in oklch, red, white)) { .soft { --ui-bg: color-mix(in oklab, var(--surface) var(--soft-bg-mix), var(--intent, var(--neutral))); --ui-border: color-mix( in oklab, var(--surface) var(--soft-border-mix), var(--intent, var(--neutral)) ); --ui-fg: color-mix(in oklab, var(--text), var(--intent, var(--text)) var(--soft-fg-mix)); } .inverted { --ui-hover-bg: color-mix(in oklch, var(--surface-solid) 88%, black); } } :focus { outline: var(--focus-outline); outline-offset: var(--focus-outline-offset); } @supports selector(:focus-visible) { :focus:not(:focus-visible) { outline: none; } } @media print { :root, body { color-scheme: light; background: #fff; color: #000; } h1, h2, h3, h4, h5, h6 { break-after: avoid; } }
1
+ *, *::before, *::after { box-sizing: border-box; } html { -webkit-text-size-adjust: 100%; } body { margin: 0; } button, input, textarea, select { font: inherit; } [hidden]:not([hidden="until-found"]) { display: none !important; } :where(img, svg, video) { max-inline-size: 100%; block-size: auto; } @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto !important; } *, *::before, *::after { animation-duration: 0.01ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; transition-delay: 0s !important; } } :root { --font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; --line-height: 1.5; --line-height-tight: 1.25; --line-height-relaxed: 1.75; --font-weight: 400; --font-weight-medium: 500; --font-weight-strong: 650; --font-weight-bold: 700; --font-size-xs: 0.8125rem; --font-size-sm: 0.875rem; --font-size-md: 1rem; --font-size-lg: 1.125rem; --gap: 0.75rem; --density-space: var(--space-40); --density-compact-size: 1.5rem; --space-10: 0.25rem; --space-20: 0.5rem; --space-30: 0.75rem; --space-40: 1rem; --space-50: 1.5rem; --space-60: 2rem; --border-width: 1px; --radius-full: 9999px; --shadow: 0 1px 3px rgb(0 0 0 / 0.05), 0 4px 12px rgb(0 0 0 / 0.04); --shadow-popout: 0 0.25rem 0.75rem rgb(0 0 0 / 0.15); --duration: 150ms; --duration-fast: 100ms; --duration-slow: 200ms; --duration-spin: 0.75s; --duration-shimmer: 1.2s; --ease-enter: cubic-bezier(0.2, 0, 0, 1); --ease-exit: cubic-bezier(0.4, 0, 1, 1); --focus-outline-color: currentColor; --focus-outline: calc(var(--border-width) * 2) solid var(--focus-outline-color); --focus-outline-offset: 2px; --focus-ring-width: 3px; --indicator-offset: 14.65%; --backdrop-color: rgb(0 0 0); --backdrop-opacity: 0.45; --backdrop-fill: rgb(0 0 0 / var(--backdrop-opacity)); --bar-height: 0.65rem; --control-size-sm: 2rem; --control-size-md: 2.375rem; --control-size-lg: 2.75rem; --control-size: var(--control-size-md); --control-pad-x: 1em; --control-font-size: var(--font-size-md); --choice-control-size: 1.125em; --disabled-opacity: 0.65; } :root, [data-theme] { --state-selected: var(--primary); --state-selected-fg: var(--primary-fg); --state-disabled: var(--text-subtle); --indicator-ring: var(--surface); } :root { --soft-bg-mix: 88%; --soft-border-mix: 65%; --soft-hover-alpha: 12%; --soft-fg-mix: 100%; --icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238a8594' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E"); --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); --icon-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3C/svg%3E"); --icon-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E"); --viewport-block: 100vh; --viewport-inline: 100vw; --z-sticky: 10; --z-menu: 20; --z-tooltip: 50; --z-status: 60; } @media (forced-colors: active) { :root, [data-theme] { --state-disabled: GrayText; --disabled-opacity: 1; } } @supports (block-size: 100dvh) { :root { --viewport-block: 100dvh; } } @supports (inline-size: 100vi) { :root { --viewport-inline: 100vi; } } @supports (color: color-mix(in oklch, red, white)) { :root, [data-theme] { --shadow: 0 1px 3px color-mix(in oklch, var(--shadow-color) 5%, transparent), 0 4px 12px color-mix(in oklch, var(--shadow-color) 4%, transparent); --shadow-popout: 0 0.25rem 0.75rem color-mix(in oklch, var(--shadow-color) 15%, transparent); } :root { --backdrop-fill: color-mix( in oklch, var(--backdrop-color) calc(var(--backdrop-opacity) * 100%), transparent ); } } :root { color-scheme: light dark; } [data-theme="light"] { color-scheme: light; } [data-theme="dark"] { color-scheme: dark; } @supports not (color: light-dark(red, blue)) { :root, [data-theme="light"], [data-theme="dark"] { color-scheme: light; } } :root, [data-theme="light"] { --primary: hsl(268 32% 33%); --primary-fg: hsl(0 0% 98%); --secondary: hsl(16 38% 38%); --secondary-fg: hsl(0 0% 98%); --success: hsl(150 40% 31%); --success-fg: hsl(0 0% 98%); --warning: hsl(36 68% 34%); --warning-fg: hsl(0 0% 98%); --danger: hsl(5 58% 43%); --danger-fg: hsl(0 0% 98%); --neutral: hsl(258 7% 43%); --neutral-fg: hsl(0 0% 98%); --surface: hsl(0 0% 100%); --surface-raised: hsl(0 0% 100%); --surface-subtle: hsl(262 24% 96%); --surface-solid: hsl(261 16% 13%); --text: hsl(261 20% 13%); --text-muted: hsl(259 9% 42%); --text-subtle: hsl(258 7% 57%); --border: hsl(260 15% 88%); --focus: var(--neutral); --focus-ring: hsl(258 7% 43% / 0.3); --hover-overlay: hsl(260 20% 10% / 0.04); --radius: 0.5rem; --radius-sm: 0.25rem; --radius-lg: 0.75rem; --shadow-color: hsl(260 25% 10%); --hgroup-gap: 0.25em; } :root, [data-theme] { --heading: var(--text); --selection-bg: var(--primary); --selection-fg: var(--primary-fg); --focus-ring-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring); } :root, [data-theme] { accent-color: var(--primary); } [data-tone="dark"] { --tone-fg: white; } [data-tone="light"] { --tone-fg: var(--text); } @supports (color: color-mix(in oklch, red, white)) { :root, [data-theme] { --focus-ring: color-mix(in oklch, var(--focus) 30%, transparent); } } @supports (color: light-dark(red, blue)) { :root, [data-theme="light"] { --primary: light-dark(hsl(268 32% 33%), hsl(268 42% 76%)); --primary-fg: light-dark(hsl(0 0% 98%), hsl(268 30% 12%)); --secondary: light-dark(hsl(16 38% 38%), hsl(18 45% 72%)); --secondary-fg: light-dark(hsl(0 0% 98%), hsl(18 32% 11%)); --success: light-dark(hsl(150 40% 31%), hsl(150 38% 62%)); --success-fg: light-dark(hsl(0 0% 98%), hsl(150 35% 8%)); --warning: light-dark(hsl(36 68% 34%), hsl(40 62% 64%)); --warning-fg: light-dark(hsl(0 0% 98%), hsl(38 35% 10%)); --danger: light-dark(hsl(5 58% 43%), hsl(4 60% 70%)); --danger-fg: light-dark(hsl(0 0% 98%), hsl(4 35% 10%)); --neutral: light-dark(hsl(258 7% 43%), hsl(258 10% 72%)); --neutral-fg: light-dark(hsl(0 0% 98%), hsl(260 18% 10%)); --surface: light-dark(hsl(0 0% 100%), hsl(263 17% 9%)); --surface-raised: light-dark(hsl(0 0% 100%), hsl(263 15% 12%)); --surface-subtle: light-dark(hsl(262 24% 96%), hsl(263 13% 16%)); --surface-solid: light-dark(hsl(261 16% 13%), hsl(0 0% 96%)); --text: light-dark(hsl(261 20% 13%), hsl(260 12% 95%)); --text-muted: light-dark(hsl(259 9% 42%), hsl(259 9% 67%)); --text-subtle: light-dark(hsl(258 7% 57%), hsl(258 7% 54%)); --border: light-dark(hsl(260 15% 88%), hsl(262 12% 24%)); --focus-ring: light-dark(hsl(258 7% 43% / 0.3), hsl(258 10% 72% / 0.28)); --hover-overlay: light-dark(hsl(260 20% 10% / 0.04), hsl(0 0% 100% / 0.06)); --shadow-color: light-dark(hsl(260 25% 10%), hsl(262 40% 2%)); } } @supports (color: color-mix(in oklch, red, white)) and (color: light-dark(red, blue)) { :root, [data-theme] { --focus-ring: light-dark( color-mix(in oklch, var(--focus) 30%, transparent), color-mix(in oklch, var(--focus) 28%, transparent) ); } } @media (prefers-contrast: more) { :root, [data-theme][data-theme] { --border-width: 2px; --focus-outline-offset: 3px; --focus-ring-width: 4px; --text-muted: var(--text); --text-subtle: var(--text); } } body { background: var(--surface); color: var(--text); font-family: var(--font-sans); line-height: var(--line-height); } a { color: var(--link, inherit); text-underline-offset: 0.18em; } a:hover { text-decoration-thickness: 0.12em; } :where(h1, h2, h3, h4, h5, h6) { color: var(--heading, inherit); line-height: var(--line-height-tight); text-wrap: balance; } hgroup { display: grid; gap: var(--hgroup-gap); } hgroup > * { margin-block: 0; } hr { border: 0; border-block-start: var(--border-width) solid var(--border); margin-block: var(--space-60); } code, kbd, samp, pre { font-family: var(--font-mono); } small { font-size: 0.875em; } ::selection { background: var(--selection-bg, var(--primary)); color: var(--selection-fg, var(--primary-fg)); } .primary { --intent: var(--primary); --intent-fg: var(--primary-fg); } .secondary { --intent: var(--secondary); --intent-fg: var(--secondary-fg); } .success { --intent: var(--success); --intent-fg: var(--success-fg); } .warning { --intent: var(--warning); --intent-fg: var(--warning-fg); } .danger { --intent: var(--danger); --intent-fg: var(--danger-fg); } .neutral { --intent: var(--neutral); --intent-fg: var(--neutral-fg); } .intent-color { color: var(--intent); } .solid { --ui-bg: var(--intent, var(--neutral)); --ui-fg: var(--intent-fg, var(--neutral-fg)); --ui-border: transparent; } .soft { --ui-bg: var(--surface-subtle); --ui-border: var(--border); --ui-fg: var(--intent, var(--text)); } .outline { --ui-bg: transparent; --ui-fg: var(--intent, currentColor); --ui-border: var(--intent, currentColor); } .surface { --ui-bg: var(--surface); --ui-fg: var(--intent, var(--text)); --ui-border: var(--border); } .inverted { --ui-bg: var(--surface-solid); --ui-fg: var(--surface); --ui-border: transparent; --ui-hover-bg: var(--surface-solid); --heading: var(--surface); --busy-overlay-bg: var(--surface-solid); background: var(--ui-bg); color: var(--ui-fg); border-color: var(--ui-border); } .sm { --gap: var(--space-20); --density-space: var(--space-20); --control-size: var(--control-size-sm); --density-compact-size: 1.25rem; } .lg { --gap: var(--space-50); --density-space: var(--space-50); --control-size: var(--control-size-lg); --density-compact-size: 1.875rem; } @supports (color: color-mix(in oklch, red, white)) { .soft { --ui-bg: color-mix(in oklab, var(--surface) var(--soft-bg-mix), var(--intent, var(--neutral))); --ui-border: color-mix( in oklab, var(--surface) var(--soft-border-mix), var(--intent, var(--neutral)) ); --ui-fg: color-mix(in oklab, var(--text), var(--intent, var(--text)) var(--soft-fg-mix)); } .inverted { --ui-hover-bg: color-mix(in oklch, var(--surface-solid) 88%, black); } } :focus { outline: var(--focus-outline); outline-offset: var(--focus-outline-offset); } @supports selector(:focus-visible) { :focus:not(:focus-visible) { outline: none; } } @media print { :root, body { color-scheme: light; background: #fff; color: #000; } h1, h2, h3, h4, h5, h6 { break-after: avoid; } }
@@ -83,20 +83,20 @@ The tiers above are Actual's own contract. The table below tracks the Web
83
83
  Platform Baseline of the individual CSS features the framework uses; it is a
84
84
  different notion from an Actual tier.
85
85
 
86
- | Feature area | Baseline | Progressive enhancement |
87
- |------------------|-------------|-------------------------------|
88
- | Layout (flex, grid, position) | Baseline 2023 | — |
89
- | CSS custom properties | Baseline 2023 | — |
90
- | `:has()` | Baseline 2023 | — |
91
- | `<dialog>` element | Baseline 2023 | — |
92
- | `color-mix()` | Baseline 2023 | Fallback flat color |
93
- | `light-dark()` | 2024+ | Manual theme override |
94
- | `:user-invalid` | 2024+ | `[aria-invalid]` attribute |
95
- | `transition-behavior: allow-discrete` | 2024+ | Native dialog open/close |
96
- | `appearance: base-select` | 2024+ | Native `<select>` |
97
- | `@starting-style` | 2024+ | Instant appearance |
98
- | View Transition API | 2024+ | Dialog open/close transition |
99
- | CSS Anchor Positioning | Future | JS positioning (`floating.js`) |
86
+ | Feature area | Baseline | Progressive enhancement |
87
+ | ------------------------------------- | ------------- | ------------------------------ |
88
+ | Layout (flex, grid, position) | Baseline 2023 | — |
89
+ | CSS custom properties | Baseline 2023 | — |
90
+ | `:has()` | Baseline 2023 | — |
91
+ | `<dialog>` element | Baseline 2023 | — |
92
+ | `color-mix()` | Baseline 2023 | Fallback flat color |
93
+ | `light-dark()` | 2024+ | Manual theme override |
94
+ | `:user-invalid` | 2024+ | `[aria-invalid]` attribute |
95
+ | `transition-behavior: allow-discrete` | 2024+ | Native dialog open/close |
96
+ | `appearance: base-select` | 2024+ | Native `<select>` |
97
+ | `@starting-style` | 2024+ | Instant appearance |
98
+ | View Transition API | 2024+ | Dialog open/close transition |
99
+ | CSS Anchor Positioning | Future | JS positioning (`floating.js`) |
100
100
 
101
101
  Core layout and visual tokens work on all Baseline 2023 browsers. Features marked
102
102
  2024+ are gated with `@supports` or degrade gracefully through fallback values.
@@ -105,22 +105,39 @@ defeating the split.
105
105
 
106
106
  ## Design decisions recorded
107
107
 
108
- | # | Decision | Rationale |
109
- |---|----------|-----------|
110
- | D2 | `selectors.js` drops its 5 discovery entries, keeps 11 write-side state entries | The file's job changes from *CSS↔init bridge* to *state vocabulary the runtime writes*. It stays the single file to alias for another CSS framework. |
111
- | D4 | `status.js` uses `[data-status][role="status"]` — no class, no token | The markup already carries `role="status"` everywhere. Semantics alone scope the document-wide lookup. |
112
- | D5 | `<dialog>` gets no token | `<dialog>` is its own opt-in: semantic, native, CSS-agnostic. |
113
- | D6 | `validation.js` accepts `[data-field-error]` as an alias for `.field-error` and keeps `.field` / `.danger` as an optional, degrading presentation adapter | Validation is the one module with intentional, optional CSS coupling. The adapter degrades to a no-op under foreign CSS while `aria-invalid`, focus management, custom rules, and server errors all keep working. |
114
- | D7 | Context-menu reuses `surface`, not `flyout` | The panel gets no token; `menuFor()` validates semantically (`menu, [role="menu"]`). A context menu may legitimately want the flyout *look* without the flyout *behavior*. |
115
- | D9 | Orphaned mounted surfaces closed from the origin's disconnect handler | A `fix:`, not part of the contract itself. Landed independently. |
108
+ **D2 — `selectors.js` drops its 5 discovery entries and keeps 11 write-side
109
+ state entries.** The file's job changes from *CSS↔init bridge* to *state
110
+ vocabulary the runtime writes*. It stays the single file to alias for another
111
+ CSS framework.
112
+
113
+ **D4 — `status.js` uses `[data-status][role="status"]`, with no class and no
114
+ token.** The markup already carries `role="status"` everywhere, so semantics
115
+ alone scope the document-wide lookup.
116
+
117
+ **D5 — `<dialog>` gets no token.** It is its own opt-in: semantic, native,
118
+ CSS-agnostic.
119
+
120
+ **D6 — `validation.js` accepts `[data-field-error]` as an alias for
121
+ `.field-error`, and keeps `.field` / `.danger` as an optional, degrading
122
+ presentation adapter.** Validation is the one module with intentional, optional
123
+ CSS coupling. The adapter degrades to a no-op under foreign CSS, while
124
+ `aria-invalid`, focus management, custom rules and server errors all keep
125
+ working.
126
+
127
+ **D7 — Context-menu reuses `surface`, not `flyout`.** The panel gets no token;
128
+ `menuFor()` validates semantically (`menu, [role="menu"]`). A context menu may
129
+ legitimately want the flyout *look* without the flyout *behavior*.
130
+
131
+ **D9 — Orphaned mounted surfaces are closed from the origin's disconnect
132
+ handler.** A `fix:`, not part of the contract itself. Landed independently.
116
133
 
117
134
  ## Token vocabulary
118
135
 
119
- | Token | Behavior | Existing class |
120
- |-------|----------|---------------|
121
- | `tabs` | Tab panel switching, arrow-key navigation | `.tabs` |
122
- | `flyout` | Trigger → panel positioning, open/close | `.flyout` |
123
- | `scrollspy` | Scroll-driven nav highlighting | `.scrollspy` |
136
+ | Token | Behavior | Existing class |
137
+ | ------------ | ------------------------------------------------ | ------------------- |
138
+ | `tabs` | Tab panel switching, arrow-key navigation | `.tabs` |
139
+ | `flyout` | Trigger → panel positioning, open/close | `.flyout` |
140
+ | `scrollspy` | Scroll-driven nav highlighting | `.scrollspy` |
124
141
  | `validation` | Form validation, focus management, server errors | `.needs-validation` |
125
142
 
126
143
  Four tokens. Everything else stays self-describing.
@@ -53,13 +53,17 @@ an essential shape, state, or affordance.
53
53
 
54
54
  ## Color system keywords by role
55
55
 
56
- | Context | Color | Why |
57
- |---|---|---|
58
- | Disclosure / accordion marker | `CanvasText` | Summary is on Canvas, not a button |
59
- | Button, switch, checkbox | `ButtonText` / `ButtonFace` / `Highlight` / `HighlightText` | Interactive controls |
60
- | Selected / current state | `Highlight` / `HighlightText` | Matches OS selection |
61
- | Disabled state | `GrayText` | Standard disabled system color |
62
- | Hover indicator | `ButtonText` outline or `CanvasText` underline | Avoids blocked backgrounds |
56
+ | Context | Color | Why |
57
+ | ------------------------ | --------------------- | ---------------------------------- |
58
+ | Disclosure marker | `CanvasText` | Summary is on Canvas, not a button |
59
+ | Button, switch, checkbox | the `Button*` pair | Interactive controls |
60
+ | Selected / current state | the `Highlight*` pair | Matches OS selection |
61
+ | Disabled state | `GrayText` | Standard disabled system color |
62
+ | Hover indicator | outline or underline | Avoids blocked backgrounds |
63
+
64
+ Controls use `ButtonText` / `ButtonFace`, and `Highlight` / `HighlightText` for
65
+ their selected state. A hover indicator is a `ButtonText` outline or a
66
+ `CanvasText` underline.
63
67
 
64
68
  Prefer `CanvasText` for non-interactive mark-up content. `CanvasText` and
65
69
  `ButtonText` are **not guaranteed identical** — custom HCM palettes can set
@@ -254,7 +254,7 @@ asks.
254
254
  It is nevertheless the right **baseline**. Bounded at N, using `auto-fill`, it
255
255
  is responsive, overflow-safe, and equal-width at every state, and it needs
256
256
  nothing above Actual's Minimal floor. Adopting it as the unenhanced behavior of
257
- `.grid-N` is what makes the actual-grid container a precision enhancement rather than
257
+ `.grid-N` is what makes the actual-container container a precision enhancement rather than
258
258
  a prerequisite for responsiveness. This is the single most important difference
259
259
  from 0.3.1, where a preset used without a wrapper stayed frozen at N columns
260
260
  and was a genuine trap.
@@ -391,7 +391,7 @@ The extra ancestor is therefore not accidental ceremony.
391
391
 
392
392
  It represents a real boundary imposed by the CSS containment model.
393
393
 
394
- Actual should not hide that boundary if hiding it requires changing the sizing semantics of the grid. Balanced subdivision keys off a container **named** `actual-grid` rather than any anonymous query container, so an incidental `container-type: inline-size` region never changes the grid by accident; `.container-query` is the convenience helper that establishes that named context.
394
+ Actual should not hide that boundary if hiding it requires changing the sizing semantics of the grid. Balanced subdivision keys off a container **named** `actual-container` rather than any anonymous query container, so an incidental `container-type: inline-size` region never changes the grid by accident; `.container-query` is the convenience helper that establishes that named context. The name is generic rather than grid-specific: it means "here is the width you were allocated", and other size-aware components (`.steps` and its label collapse) read the same context. The grid does not own it — it is one consumer.
395
395
 
396
396
  ## Out of scope: explicit per-region placement
397
397
 
@@ -520,7 +520,7 @@ viewport
520
520
  |
521
521
  named query container
522
522
  |
523
- actual-grid
523
+ actual-container
524
524
  |
525
525
  2 / 3 / 4 / 6 stages
526
526
  ```
@@ -620,7 +620,7 @@ inside a query container.
620
620
  .grid space-driven, auto-fit, --grid-min
621
621
  .grid-N count-driven baseline, auto-fill bounded at N,
622
622
  may pass through non-divisor column counts
623
- actual-grid .grid-N balanced subdivision, N -> divisors of N -> 1
623
+ actual-container .grid-N balanced subdivision, N -> divisors of N -> 1
624
624
  ```
625
625
 
626
626
  The whole enhancement lives inside `@supports (container-type: inline-size)`.
@@ -40,15 +40,21 @@ Actual CSS is intended for new projects. Existing projects with class collisions
40
40
 
41
41
  ## Utilities
42
42
 
43
- Utilities ship in two layers that follow the same class grammar.
43
+ Utilities ship in two modules that follow the same class grammar. Both are
44
+ imported by `utilities/index.css`, so the split is about naming and curation,
45
+ never about opting in.
44
46
 
45
- - **Base utilities** are a curated set of common ergonomic shortcuts
46
- (`.overflow-auto`, `.gap-none`, `.text-nowrap`, `.px`, `.py`).
47
- - **Optional utilities** use explicit property/value names
47
+ - **Base** (`utilities/base.css`) is a curated set of common ergonomic
48
+ shortcuts (`.overflow-auto`, `.gap-none`, `.text-nowrap`, `.px`, `.py`).
49
+ - **Extra** (`utilities/extra.css`) uses explicit property/value names
48
50
  (`.overflow-hidden`, `.gap-sm`, `.white-space-normal`).
49
51
 
50
- Base utilities may use compact names for a small set of frequent operations
51
- (`.px`, `.py`, `.mbs`, `.mbe`). Extra utilities use explicit property/value
52
- names and must not duplicate an operation already provided by base. The two
53
- sets may cover the same CSS property, but must not expose competing names for
54
- the same declaration.
52
+ Call them base and extra, after the files. "Optional" is the wrong word for
53
+ either: it reads as a layer an author has to opt into, which is true of every
54
+ module outside `core/` and therefore says nothing about these two.
55
+
56
+ Base may use compact names for a small set of frequent operations (`.px`,
57
+ `.py`, `.mbs`, `.mbe`). Extra uses explicit property/value names and must not
58
+ duplicate an operation already provided by base. The two sets may cover the
59
+ same CSS property, but must not expose competing names for the same
60
+ declaration.
@@ -287,6 +287,15 @@ Avoid building a large custom range abstraction around browser-specific pseudo-e
287
287
 
288
288
  Prefer native controls and progressive styling.
289
289
 
290
+ The concrete signal to watch is `appearance: base-slider` with `::slider-track`, `::slider-fill`, and `::slider-thumb`. Checked on Chrome 152: `CSS.supports('appearance', 'base-slider')` and `CSS.supports('selector(::slider-fill)')` are both false, so there is nothing to enhance against yet.
291
+
292
+ Until then, `.range` intentionally omits filled tracks and tick marks. Both are reachable today only through techniques Actual should not take on:
293
+
294
+ - The Chromium filled-track trick needs `overflow: hidden` on the runnable track plus a large `box-shadow` on the thumb. It collides twice with `range.css`: the thumb is wider than the track and would be clipped, and the focus ring already owns the thumb's `box-shadow`.
295
+ - CSS-only tick marks need a step count duplicated out of `min`/`max`/`step` into a custom property, so markup carries the same contract twice and the two can diverge. `datalist` cannot carry it either: its native ticks are part of the appearance that `appearance: none` removes, and no engine renders `<option label>` for a range.
296
+
297
+ When the base-slider parts become interoperable, this becomes a `@supports` enhancement in the shape of `custom-select.css` — less engine-specific CSS, not more.
298
+
290
299
  ### Navigation
291
300
 
292
301
  Native navigation proposals may eventually provide richer semantics and interaction behavior for complex navigation structures.
@@ -330,3 +330,7 @@ Prior Actual CSS libraries:
330
330
  - https://getbootstrap.com/docs/5.3/components/scrollspy/
331
331
  - https://una.im/scroll-target-group/
332
332
  - https://www.sarasoueidan.com/blog/css-scrollspy/
333
+
334
+ ### @container
335
+
336
+ - https://ishadeed.com/article/css-container-query-guide/