@master/internal-site 0.2.4 → 0.2.6

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 (46) hide show
  1. package/dist/astro.mjs +1842 -5
  2. package/dist/{localization-LfIbIysE.mjs → localization-IeZXkrNw.mjs} +11 -2
  3. package/dist/localization.mjs +1 -1
  4. package/package.json +9 -8
  5. package/src/astro/image-variants.ts +96 -0
  6. package/src/astro/index.ts +12 -3
  7. package/src/astro/site-translations.ts +31 -0
  8. package/src/astro/svelte-client.ts +13 -0
  9. package/src/demo/specimens/background-attachment.json +3 -3
  10. package/src/demo/specimens/background-origin.json +9 -9
  11. package/src/demo/specimens/clip-path.json +3 -3
  12. package/src/demo/specimens/counter-set.json +8 -8
  13. package/src/demo/specimens/filter.json +6 -6
  14. package/src/demo/specimens/grid-auto-flow.json +3 -3
  15. package/src/demo/specimens/grid-template-areas.json +5 -5
  16. package/src/demo/specimens/grid-template-columns.json +6 -6
  17. package/src/demo/specimens/justify-content.json +8 -8
  18. package/src/demo/specimens/mask-image.json +3 -3
  19. package/src/demo/specimens/object-position.json +6 -6
  20. package/src/demo/specimens/place-content.json +4 -4
  21. package/src/demo/specimens/scroll-snap-stop.json +3 -3
  22. package/src/demo/specimens/shape-margin.json +5 -5
  23. package/src/demo/specimens/shape-outside.json +3 -3
  24. package/src/demo/specimens/transform-origin.json +3 -3
  25. package/src/docs-shell/components/Image.svelte +7 -4
  26. package/src/docs-shell/components/SearchButton.svelte +5 -3
  27. package/src/docs-shell/components/SearchDialog.svelte +47 -161
  28. package/src/docs-shell/components/SearchDialogPanel.svelte +182 -0
  29. package/src/docs-shell/contexts/search.ts +8 -0
  30. package/src/docs-shell/contexts/theme-mode.svelte.ts +6 -1
  31. package/src/docs-shell/scripts/code.ts +9 -4
  32. package/src/docs-shell/site-dictionary.ts +36 -0
  33. package/src/docs-shell/types/StaticImage.ts +2 -0
  34. package/src/examples/components/ArticleTransitionScene.svelte +16 -14
  35. package/src/home/home-lamp.ts +35 -13
  36. package/src/home/icons/artwork/render-prerender-dark.webp +0 -0
  37. package/src/home/icons/artwork/render-prerender-light.webp +0 -0
  38. package/src/home/icons/artwork/source.json +6 -0
  39. package/src/home/icons/artwork.ts +3 -0
  40. package/src/home/icons/catalog.ts +9 -1
  41. package/src/home/icons/render-prerender.svg +12 -0
  42. package/src/layouts/Document.astro +24 -9
  43. package/src/scripts/atomic-class-authoring.ts +4 -1
  44. package/src/scripts/localization.ts +13 -4
  45. package/src/styles/blog-article.css +5 -4
  46. package/src/styles/system/DESIGN.md +1 -1
@@ -255,6 +255,15 @@ async function sharedInterfaceKeys(sourceRoot = join(dirname(fileURLToPath(impor
255
255
  await visit(sourceRoot);
256
256
  return [...keys].sort();
257
257
  }
258
+ /**
259
+ * Shared copy and data modules can hold reader-facing prose that a translation mirrors.
260
+ * Shared components and compiled tooling cannot: their interface strings are reviewed
261
+ * through the localized dictionaries, so a rendering change must not mark every
262
+ * document that uses them as changed English source.
263
+ */
264
+ function isSharedSourceModule(path) {
265
+ return !/^dist\//.test(path) && !/\.(?:astro|svelte)$/.test(path) && !/\/common\/(?:translations|locales)\.[jt]s$/.test(path);
266
+ }
258
267
  /** Follow local prose/data modules without executing them or importing product compiler code. */
259
268
  async function collectSourceDependencies(files, { siteRoot }) {
260
269
  const root = resolve(siteRoot);
@@ -264,13 +273,13 @@ async function collectSourceDependencies(files, { siteRoot }) {
264
273
  const visit = async (file) => {
265
274
  file = resolve(file).replace(/\.(tw|ja|ko|cn)\.mdx$/, ".mdx");
266
275
  if (!file.startsWith(root + sep) && !file.startsWith(sharedRoot + sep) || seen.has(file)) return;
267
- if (file.startsWith(sharedRoot + sep) && /\/common\/(?:translations|locales)\.[jt]s$/.test(file.replaceAll("\\", "/"))) return;
276
+ if (file.startsWith(sharedRoot + sep) && !isSharedSourceModule(relative(sharedRoot, file).replaceAll("\\", "/"))) return;
268
277
  seen.add(file);
269
278
  const source = await readFile(file, "utf8").catch(() => void 0);
270
279
  if (source === void 0) return;
271
280
  const key = file.startsWith(sharedRoot + sep) ? `@master/internal-site/${relative(sharedRoot, file)}` : relative(root, file);
272
281
  collected[key.replaceAll("\\", "/")] = source;
273
- const imports = source.matchAll(/(?:\bfrom\s*|\bimport\s*(?:\(\s*)?)(['"])([^'"\n]+)\1/g);
282
+ const imports = source.replace(/\b(?:import|export)\s+type\b[^'";]*?\bfrom\s*(['"])[^'"\n]+\1/g, "").matchAll(/(?:\bfrom\s*|\bimport\s*(?:\(\s*)?)(['"])([^'"\n]+)\1/g);
274
283
  for (const [, , specifier] of imports) {
275
284
  if (!specifier.startsWith(".") && !specifier.startsWith("~/site/") && !specifier.startsWith("@master/internal-site/")) continue;
276
285
  let target;
@@ -1 +1 @@
1
- export { t as assertTranslations, n as auditTranslations, r as collectSourceDependencies, i as discoverDocumentResources, a as emptyReviews, o as headingAnchors, p as localizedMetadata, s as readLocalizedDocument, c as reviewTranslation, l as sharedInterfaceKeys, u as stabilizeHeadingAnchors, d as validateSiteTranslations } from "./localization-LfIbIysE.mjs";
1
+ export { t as assertTranslations, n as auditTranslations, r as collectSourceDependencies, i as discoverDocumentResources, a as emptyReviews, o as headingAnchors, p as localizedMetadata, s as readLocalizedDocument, c as reviewTranslation, l as sharedInterfaceKeys, u as stabilizeHeadingAnchors, d as validateSiteTranslations } from "./localization-IeZXkrNw.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@master/internal-site",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "type": "module",
5
5
  "description": "First-party Astro and Svelte website framework for Master sites.",
6
6
  "engines": {
@@ -308,14 +308,14 @@
308
308
  "peerDependencies": {
309
309
  "astro": "7.4.2",
310
310
  "svelte": "5.57.2",
311
- "@master/css": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0",
312
- "@master/css-astro": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0",
311
+ "@master/css": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.1.0",
312
+ "@master/css-astro": "^2.1.0",
313
313
  "vite": "8.3.5",
314
- "@master/css-compiler": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0",
315
- "@master/css-tooling": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0",
316
- "@master/css-schema": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0",
317
- "@master/css-preset": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0",
318
- "@master/css-language-service": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.0.0"
314
+ "@master/css-compiler": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.1.0",
315
+ "@master/css-tooling": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.1.0",
316
+ "@master/css-schema": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.1.0",
317
+ "@master/css-preset": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.1.0",
318
+ "@master/css-language-service": "0.0.0 || >=0.0.0-site.1793646900.gdf48b35846c1 <0.0.1 || ^2.1.0"
319
319
  },
320
320
  "dependencies": {
321
321
  "@astrojs/svelte": "^9.1.2",
@@ -349,6 +349,7 @@
349
349
  "@astrojs/markdown-remark": "^7.3.4",
350
350
  "@resvg/resvg-js": "2.6.2",
351
351
  "satori": "0.63.2",
352
+ "sharp": "0.35.5",
352
353
  "mdast-util-mdx-jsx": "^3.2.0",
353
354
  "micromark-extension-mdx-jsx": "^3.0.2"
354
355
  },
@@ -0,0 +1,96 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { mkdir, readFile, writeFile } from 'node:fs/promises'
3
+ import { basename, extname, join } from 'node:path'
4
+ import sharp from 'sharp'
5
+ import type { Plugin } from 'vite'
6
+ import { cleanId } from './module-id'
7
+
8
+ /** Widths a bitmap is also delivered at, when they are clearly smaller than its own. */
9
+ export const variantWidths = [256, 640, 960, 1280, 1920, 2560]
10
+ export const avifOptions = { quality: 60, effort: 3 } as const
11
+ // libaom splits its work by the configured thread count, so the encoded bytes depend on it.
12
+ // A fixed count keeps every builder's output identical regardless of its CPU count.
13
+ const encoderThreads = 4
14
+ const bitmap = /\.(?:png|jpe?g|webp)$/i
15
+ const marker = '?master-image'
16
+
17
+ export interface ImageVariants {
18
+ /** Files to write into the build output, keyed by their output-relative path. */
19
+ readonly files: Map<string, Uint8Array>
20
+ plugin(): Plugin
21
+ write(outDir: string): Promise<void>
22
+ }
23
+
24
+ /** Delivered widths for a bitmap of the given intrinsic width, smallest first. */
25
+ export function deliveredWidths(width: number) {
26
+ return [...variantWidths.filter(candidate => candidate <= width * 0.8), width]
27
+ }
28
+
29
+ /**
30
+ * Build-time responsive images for bitmap imports.
31
+ *
32
+ * An imported PNG, JPEG or WebP resolves to `{ src, width, height, srcset }`, where every
33
+ * candidate is an AVIF encoded during the build. The module is plain data, so the server
34
+ * render and a hydrating island read the same `srcset`. Encoding is deterministic for a
35
+ * given sharp version; outputs are content-hashed under the assets directory.
36
+ * Development keeps Astro's own image modules so the dev server starts without encoding.
37
+ */
38
+ export function imageVariants({ base, assetsDir }: { base: string; assetsDir: string }): ImageVariants {
39
+ const files = new Map<string, Uint8Array>()
40
+ const modules = new Map<string, Promise<string | undefined>>()
41
+ const directory = assetsDir.replace(/^\/|\/$/g, '')
42
+ const root = base.replace(/\/?$/, '/')
43
+
44
+ async function encode(source: Buffer, stem: string, width: number, intrinsic: number) {
45
+ const pipeline = sharp(source)
46
+ if (width !== intrinsic) pipeline.resize({ width })
47
+ const bytes = await pipeline.avif(avifOptions).toBuffer()
48
+ const hash = createHash('sha256').update(bytes).digest('base64url').slice(0, 8)
49
+ const name = `${directory}/${stem}-${width}.${hash}.avif`
50
+ files.set(name, bytes)
51
+ return { url: root + name, width }
52
+ }
53
+
54
+ async function load(file: string) {
55
+ const source = await readFile(file)
56
+ const { width, height, pages } = await sharp(source).metadata()
57
+ // Animated sources keep their original file.
58
+ if (!width || !height || (pages ?? 1) > 1) return
59
+ const stem = basename(file, extname(file)).replace(/[^\w-]+/g, '-')
60
+ const variants = await Promise.all(deliveredWidths(width).map(size => encode(source, stem, size, width)))
61
+ const image = { src: variants.at(-1)!.url, width, height, format: 'avif', srcset: variants.map(variant => `${variant.url} ${variant.width}w`).join(', ') }
62
+ return `export default ${JSON.stringify(image)}`
63
+ }
64
+
65
+ return {
66
+ files,
67
+ plugin: () => ({
68
+ name: '@master/internal-site:image-variants',
69
+ // Before Vite's asset handling and alongside Astro's image modules, which
70
+ // leave queried image ids to other plugins.
71
+ enforce: 'pre',
72
+ apply: 'build',
73
+ buildStart() { sharp.concurrency(encoderThreads) },
74
+ async resolveId(source, importer, options) {
75
+ if (!importer || importer.endsWith(marker) || source.includes('?') || !bitmap.test(source)) return
76
+ const resolved = await this.resolve(source, importer, { ...options, skipSelf: true })
77
+ if (!resolved || resolved.external || resolved.id.includes('?') || !bitmap.test(resolved.id)) return
78
+ return resolved.id + marker
79
+ },
80
+ async load(id) {
81
+ if (!id.endsWith(marker)) return
82
+ const file = cleanId(id)
83
+ this.addWatchFile(file)
84
+ if (!modules.has(file)) modules.set(file, load(file))
85
+ return await modules.get(file) ?? `export { default } from ${JSON.stringify(file)}`
86
+ }
87
+ }),
88
+ async write(outDir) {
89
+ for (const [name, bytes] of [...files].sort(([a], [b]) => a < b ? -1 : 1)) {
90
+ const target = join(outDir, name)
91
+ await mkdir(join(target, '..'), { recursive: true })
92
+ await writeFile(target, bytes)
93
+ }
94
+ }
95
+ }
96
+ }
@@ -15,8 +15,10 @@ import { prepareContentPages } from './content-pages'
15
15
  import { validateSiteTranslations } from '../scripts/localization'
16
16
  import serverStyles from './server-styles'
17
17
  import svgMarkup from './svg-markup'
18
+ import { imageVariants, type ImageVariants } from './image-variants'
18
19
  import localizedMdx from './localized-mdx'
19
20
  import { compactStyleAssets } from './style-assets'
21
+ import { writeTranslationAssets } from './site-translations'
20
22
  import { hoistIslandScripts } from './island-scripts'
21
23
  import remarkSlugAndTOC from '../docs-shell/remark/slug-and-toc.js'
22
24
  import remarkMarkdownComponents from '../docs-shell/remark/markdown-components.js'
@@ -29,6 +31,7 @@ const propagated = (url: URL) => `() => import(${JSON.stringify(fsImport(url) +
29
31
 
30
32
  export default function masterSite(site: SiteConfig): AstroIntegration {
31
33
  let output: URL
34
+ let images: ImageVariants | undefined
32
35
  return {
33
36
  name: '@master/internal-site',
34
37
  hooks: {
@@ -103,10 +106,12 @@ export default function masterSite(site: SiteConfig): AstroIntegration {
103
106
  })
104
107
  }
105
108
  }
109
+ images = command === 'build' ? imageVariants({ base: config.base, assetsDir: config.build.assets }) : undefined
106
110
  addRenderer({
107
111
  name: '@master/internal-site:svelte',
108
112
  serverEntrypoint: fileURLToPath(new URL('./svelte-renderer.ts', import.meta.url)),
109
- clientEntrypoint: '@astrojs/svelte/client.js'
113
+ // Built pages deliver the island dictionary as a cached file; hydration waits for it.
114
+ clientEntrypoint: fileURLToPath(new URL('./svelte-client.ts', import.meta.url))
110
115
  })
111
116
  injectRoute({ pattern: '/[...path]', entrypoint: new URL('./Page.astro', import.meta.url), prerender: true })
112
117
  updateConfig({
@@ -115,8 +120,10 @@ export default function masterSite(site: SiteConfig): AstroIntegration {
115
120
  build: { format: 'file' },
116
121
  markdown: { processor: unified({ remarkPlugins: [remarkSlugAndTOC, remarkMarkdownComponents], gfm: true, smartypants: false }), syntaxHighlight: false },
117
122
  experimental: { svgOptimizer: svgoOptimizer(svgoConfig as Parameters<typeof svgoOptimizer>[0]) },
118
- vite: { plugins: [plugin, localizedMdx(site.i18n), sourceURL(), serverStyles([root, packageSource]), svgMarkup()], resolve: { dedupe: ['svelte'] }, server: { fs: { allow: [searchForWorkspaceRoot(root), packageSource] } } },
119
- integrations: [svelte(), mdx(), masterCSS({ mode: 'progressive' })]
123
+ vite: { plugins: [plugin, localizedMdx(site.i18n), sourceURL(), serverStyles([root, packageSource]), svgMarkup(), ...images ? [images.plugin()] : []], resolve: { dedupe: ['svelte'] }, server: { fs: { allow: [searchForWorkspaceRoot(root), packageSource] } } },
124
+ // Every route is prerendered and its island classes are present in the rendered HTML,
125
+ // so pages ship their Master CSS without a browser runtime or hydration manifest.
126
+ integrations: [svelte(), mdx(), masterCSS({ mode: 'prerender' })]
120
127
  })
121
128
  },
122
129
  'astro:config:done': ({ config }) => { output = config.outDir },
@@ -124,7 +131,9 @@ export default function masterSite(site: SiteConfig): AstroIntegration {
124
131
  const destination = output
125
132
  await mkdir(destination, { recursive: true })
126
133
  await cp(new URL('../public/', import.meta.url), destination, { recursive: true, force: false })
134
+ await images?.write(fileURLToPath(destination))
127
135
  await compactStyleAssets(fileURLToPath(destination), hoistIslandScripts)
136
+ await writeTranslationAssets(fileURLToPath(destination), site.i18n)
128
137
  }
129
138
  }
130
139
  }
@@ -0,0 +1,31 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { mkdir, writeFile } from 'node:fs/promises'
3
+ import { resolve } from 'node:path'
4
+ import sharedTranslations from '../docs-shell/common/translations'
5
+
6
+ type Dictionaries = Record<string, Record<string, string>>
7
+
8
+ /** The island dictionary of one locale: shared interface copy, then the site's own, as `siteContextOf()` merges it. */
9
+ export function translationsOfLocale(siteTranslations: Dictionaries, locale: string): Record<string, string> {
10
+ return { ...sharedTranslations[locale], ...siteTranslations[locale] }
11
+ }
12
+
13
+ /**
14
+ * Built pages deliver the island dictionary as one content-addressed file per locale
15
+ * instead of serializing it into every page: browsers fetch it once and reuse it on
16
+ * every page of that locale. A locale without entries needs no file.
17
+ */
18
+ export function translationAsset(translations: Record<string, string>) {
19
+ if (!Object.keys(translations).length) return
20
+ const json = JSON.stringify(translations)
21
+ const hash = createHash('sha256').update(json).digest('hex').slice(0, 16)
22
+ return { href: `/_astro/site-translations-${hash}.json`, json }
23
+ }
24
+
25
+ /** Write the files that `translationAsset()` names for every locale into the build output. */
26
+ export async function writeTranslationAssets(output: string, i18n: { locales: readonly string[], translations: Dictionaries }) {
27
+ const assets = i18n.locales.map(locale => translationAsset(translationsOfLocale(i18n.translations, locale))).filter(asset => asset !== undefined)
28
+ if (!assets.length) return
29
+ await mkdir(resolve(output, '_astro'), { recursive: true })
30
+ await Promise.all(assets.map(({ href, json }) => writeFile(resolve(output, '.' + href), json)))
31
+ }
@@ -0,0 +1,13 @@
1
+ import hydrateSvelte from '@astrojs/svelte/client.js'
2
+ import { applySiteTranslations } from '../docs-shell/site-dictionary'
3
+
4
+ type Hydrate = ReturnType<typeof hydrateSvelte>
5
+
6
+ /** `@astrojs/svelte` hydration once the page's dictionary has reached the context `getSite()` reads. */
7
+ export default (element: HTMLElement) => {
8
+ const hydrate = hydrateSvelte(element)
9
+ return async (...args: Parameters<Hydrate>) => {
10
+ await applySiteTranslations()
11
+ return hydrate(...args)
12
+ }
13
+ }
@@ -4,7 +4,7 @@
4
4
  "id": "attach-to-scrollable-content",
5
5
  "title": "Attach to scrollable content",
6
6
  "html": [
7
- "<!-- Scrollable content · local attachment -->\n<body class=\"min-h(720)\">\n <section id=\"target\" tabindex=\"0\" aria-label=\"Scrollable background specimen\"\n class=\"overflow-auto h(220) w-xs max-w-full p-md b(1) b-solid b-line-divider\n (background-attachment:local) (background-repeat:repeat-y) (background-position-x:50%) (background-position-y:0px)\n (background-size:320px|200px) (background-image:url(/demo/landscape.svg))\"\n>\n <div class=\"flex flex-col items-start justify-between h(480)\">\n <p class=\"m(0) p-xs bg-surface-base fg-text-body\">Start of content</p>\n <p class=\"m(0) p-xs bg-surface-base fg-text-body\">End of content</p>\n </div>\n </section>\n <p class=\"mt-md font-sm fg-text-muted\">Scroll this page as well as the inner panel.</p>\n</body>"
7
+ "<!-- Scrollable content · local attachment -->\n<body class=\"min-h(720)\">\n <section id=\"target\" tabindex=\"0\" aria-label=\"Scrollable background specimen\"\n class=\"overflow-auto h(220) w-xs max-w-full p-md b(1) b-solid b-line-divider\n (background-attachment:local) (background-repeat:repeat-y) (background-position-x:50%) (background-position-y:0px)\n (background-size:320px_200px) (background-image:url(/demo/landscape.svg))\"\n>\n <div class=\"flex flex-col items-start justify-between h(480)\">\n <p class=\"m(0) p-xs bg-surface-base fg-text-body\">Start of content</p>\n <p class=\"m(0) p-xs bg-surface-base fg-text-body\">End of content</p>\n </div>\n </section>\n <p class=\"mt-md font-sm fg-text-muted\">Scroll this page as well as the inner panel.</p>\n</body>"
8
8
  ],
9
9
  "css": "",
10
10
  "classes": [
@@ -21,7 +21,7 @@
21
21
  "(background-repeat:repeat-y)",
22
22
  "(background-position-x:50%)",
23
23
  "(background-position-y:0px)",
24
- "(background-size:320px|200px)",
24
+ "(background-size:320px_200px)",
25
25
  "(background-image:url(/demo/landscape.svg))",
26
26
  "flex",
27
27
  "flex-col",
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "classLists": [
40
40
  "min-h(720)",
41
- "overflow-auto h(220) w-xs max-w-full p-md b(1) b-solid b-line-divider (background-attachment:local) (background-repeat:repeat-y) (background-position-x:50%) (background-position-y:0px) (background-size:320px|200px) (background-image:url(/demo/landscape.svg))",
41
+ "overflow-auto h(220) w-xs max-w-full p-md b(1) b-solid b-line-divider (background-attachment:local) (background-repeat:repeat-y) (background-position-x:50%) (background-position-y:0px) (background-size:320px_200px) (background-image:url(/demo/landscape.svg))",
42
42
  "flex flex-col items-start justify-between h(480)",
43
43
  "m(0) p-xs bg-surface-base fg-text-body",
44
44
  "m(0) p-xs bg-surface-base fg-text-body",
@@ -4,9 +4,9 @@
4
4
  "id": "choose-the-background-positioning-area",
5
5
  "title": "Choose the background positioning area",
6
6
  "html": [
7
- "<!-- Border origin · x 0, y 0 -->\n<div id=\"target\" role=\"img\" aria-label=\"Geometric landscape\"\n class=\"h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),|transparent))\n (background-clip:border-box) (background-repeat:no-repeat) (background-origin:border-box)\n (background-position:0|0) (background-size:80px|50px)\n (background-image:url(/demo/landscape.svg))\"\n></div>",
8
- "<!-- Padding origin · x 8, y 8 -->\n<div id=\"target\" role=\"img\" aria-label=\"Geometric landscape\"\n class=\"h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),|transparent))\n (background-clip:border-box) (background-repeat:no-repeat) (background-origin:padding-box)\n (background-position:0|0) (background-size:80px|50px)\n (background-image:url(/demo/landscape.svg))\"\n></div>",
9
- "<!-- Content origin · x 32, y 32 -->\n<div id=\"target\" role=\"img\" aria-label=\"Geometric landscape\"\n class=\"h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),|transparent))\n (background-clip:border-box) (background-repeat:no-repeat) (background-origin:content-box)\n (background-position:0|0) (background-size:80px|50px)\n (background-image:url(/demo/landscape.svg))\"\n></div>"
7
+ "<!-- Border origin · x 0, y 0 -->\n<div id=\"target\" role=\"img\" aria-label=\"Geometric landscape\"\n class=\"h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),_transparent))\n (background-clip:border-box) (background-repeat:no-repeat) (background-origin:border-box)\n (background-position:0_0) (background-size:80px_50px)\n (background-image:url(/demo/landscape.svg))\"\n></div>",
8
+ "<!-- Padding origin · x 8, y 8 -->\n<div id=\"target\" role=\"img\" aria-label=\"Geometric landscape\"\n class=\"h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),_transparent))\n (background-clip:border-box) (background-repeat:no-repeat) (background-origin:padding-box)\n (background-position:0_0) (background-size:80px_50px)\n (background-image:url(/demo/landscape.svg))\"\n></div>",
9
+ "<!-- Content origin · x 32, y 32 -->\n<div id=\"target\" role=\"img\" aria-label=\"Geometric landscape\"\n class=\"h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),_transparent))\n (background-clip:border-box) (background-repeat:no-repeat) (background-origin:content-box)\n (background-position:0_0) (background-size:80px_50px)\n (background-image:url(/demo/landscape.svg))\"\n></div>"
10
10
  ],
11
11
  "css": "",
12
12
  "classes": [
@@ -16,20 +16,20 @@
16
16
  "p-lg",
17
17
  "b(8)",
18
18
  "b-dashed",
19
- "(border-color:color-mix(var(--color-violet-50),|transparent))",
19
+ "(border-color:color-mix(var(--color-violet-50),_transparent))",
20
20
  "(background-clip:border-box)",
21
21
  "(background-repeat:no-repeat)",
22
22
  "(background-origin:border-box)",
23
- "(background-position:0|0)",
24
- "(background-size:80px|50px)",
23
+ "(background-position:0_0)",
24
+ "(background-size:80px_50px)",
25
25
  "(background-image:url(/demo/landscape.svg))",
26
26
  "(background-origin:padding-box)",
27
27
  "(background-origin:content-box)"
28
28
  ],
29
29
  "classLists": [
30
- "h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),|transparent)) (background-clip:border-box) (background-repeat:no-repeat) (background-origin:border-box) (background-position:0|0) (background-size:80px|50px) (background-image:url(/demo/landscape.svg))",
31
- "h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),|transparent)) (background-clip:border-box) (background-repeat:no-repeat) (background-origin:padding-box) (background-position:0|0) (background-size:80px|50px) (background-image:url(/demo/landscape.svg))",
32
- "h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),|transparent)) (background-clip:border-box) (background-repeat:no-repeat) (background-origin:content-box) (background-position:0|0) (background-size:80px|50px) (background-image:url(/demo/landscape.svg))"
30
+ "h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),_transparent)) (background-clip:border-box) (background-repeat:no-repeat) (background-origin:border-box) (background-position:0_0) (background-size:80px_50px) (background-image:url(/demo/landscape.svg))",
31
+ "h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),_transparent)) (background-clip:border-box) (background-repeat:no-repeat) (background-origin:padding-box) (background-position:0_0) (background-size:80px_50px) (background-image:url(/demo/landscape.svg))",
32
+ "h(176) w(280) max-w-full p-lg b(8) b-dashed (border-color:color-mix(var(--color-violet-50),_transparent)) (background-clip:border-box) (background-repeat:no-repeat) (background-origin:content-box) (background-position:0_0) (background-size:80px_50px) (background-image:url(/demo/landscape.svg))"
33
33
  ],
34
34
  "highlighted": []
35
35
  }
@@ -5,7 +5,7 @@
5
5
  "title": "Clip with an inset",
6
6
  "html": [
7
7
  "<!-- Unclipped · original border -->\n<div\n class=\"h(120) w(240) max-w-full\n outline(1) outline-solid outline-line-subtle bg-surface-base\">\n <div id=\"target\"\n class=\"grid (place-items:center) h(120) w(240)\n max-w-full b(2) b-solid b-blue-60 font-md\n bg-blue-10 fg-blue-80 (clip-path:none)\">\n Clipped panel\n </div>\n</div>",
8
- "<!-- Inset · rounded paint boundary -->\n<div\n class=\"h(120) w(240) max-w-full\n outline(1) outline-solid outline-line-subtle bg-surface-base\">\n <div id=\"target\"\n class=\"grid (place-items:center) h(120) w(240)\n max-w-full b(2) b-solid b-blue-60 font-md\n bg-blue-10 fg-blue-80\n (clip-path:inset(8px|24px|round|12px))\">\n Clipped panel\n </div>\n</div>"
8
+ "<!-- Inset · rounded paint boundary -->\n<div\n class=\"h(120) w(240) max-w-full\n outline(1) outline-solid outline-line-subtle bg-surface-base\">\n <div id=\"target\"\n class=\"grid (place-items:center) h(120) w(240)\n max-w-full b(2) b-solid b-blue-60 font-md\n bg-blue-10 fg-blue-80\n (clip-path:inset(8px_24px_round_12px))\">\n Clipped panel\n </div>\n</div>"
9
9
  ],
10
10
  "css": "",
11
11
  "classes": [
@@ -25,13 +25,13 @@
25
25
  "bg-blue-10",
26
26
  "fg-blue-80",
27
27
  "(clip-path:none)",
28
- "(clip-path:inset(8px|24px|round|12px))"
28
+ "(clip-path:inset(8px_24px_round_12px))"
29
29
  ],
30
30
  "classLists": [
31
31
  "h(120) w(240) max-w-full outline(1) outline-solid outline-line-subtle bg-surface-base",
32
32
  "grid (place-items:center) h(120) w(240) max-w-full b(2) b-solid b-blue-60 font-md bg-blue-10 fg-blue-80 (clip-path:none)",
33
33
  "h(120) w(240) max-w-full outline(1) outline-solid outline-line-subtle bg-surface-base",
34
- "grid (place-items:center) h(120) w(240) max-w-full b(2) b-solid b-blue-60 font-md bg-blue-10 fg-blue-80 (clip-path:inset(8px|24px|round|12px))"
34
+ "grid (place-items:center) h(120) w(240) max-w-full b(2) b-solid b-blue-60 font-md bg-blue-10 fg-blue-80 (clip-path:inset(8px_24px_round_12px))"
35
35
  ],
36
36
  "highlighted": []
37
37
  }
@@ -4,7 +4,7 @@
4
4
  "id": "set-a-counter-on-one-item",
5
5
  "title": "Set a counter on one item",
6
6
  "html": [
7
- "<!-- Sequence · 1, 9, 10 -->\n<ol role=\"list\" class=\"m(0) p(0) font-md leading-lg (list-style:none) (counter-reset:step|0)\">\n <li class=\"mb-2xs (counter-increment:step|1) fg-text-blue::before\n (content:counter(step)'.\\00a0')::before\">Install dependencies</li>\n <li id=\"target\" value=\"9\" class=\"mb-2xs (counter-increment:step|1) (counter-set:step|9)\n fg-text-blue::before (content:counter(step)'.\\00a0')::before\">Deployment checklist</li>\n <li class=\"mb-2xs (counter-increment:step|1) fg-text-blue::before\n (content:counter(step)'.\\00a0')::before\">Verify production</li>\n</ol>"
7
+ "<!-- Sequence · 1, 9, 10 -->\n<ol role=\"list\" class=\"m(0) p(0) font-md leading-lg (list-style:none) (counter-reset:step_0)\">\n <li class=\"mb-2xs (counter-increment:step_1) fg-text-blue::before\n (content:counter(step)'.\\00a0')::before\">Install dependencies</li>\n <li id=\"target\" value=\"9\" class=\"mb-2xs (counter-increment:step_1) (counter-set:step_9)\n fg-text-blue::before (content:counter(step)'.\\00a0')::before\">Deployment checklist</li>\n <li class=\"mb-2xs (counter-increment:step_1) fg-text-blue::before\n (content:counter(step)'.\\00a0')::before\">Verify production</li>\n</ol>"
8
8
  ],
9
9
  "css": "",
10
10
  "classes": [
@@ -13,18 +13,18 @@
13
13
  "font-md",
14
14
  "leading-lg",
15
15
  "(list-style:none)",
16
- "(counter-reset:step|0)",
16
+ "(counter-reset:step_0)",
17
17
  "mb-2xs",
18
- "(counter-increment:step|1)",
18
+ "(counter-increment:step_1)",
19
19
  "fg-text-blue::before",
20
20
  "(content:counter(step)'.\\00a0')::before",
21
- "(counter-set:step|9)"
21
+ "(counter-set:step_9)"
22
22
  ],
23
23
  "classLists": [
24
- "m(0) p(0) font-md leading-lg (list-style:none) (counter-reset:step|0)",
25
- "mb-2xs (counter-increment:step|1) fg-text-blue::before (content:counter(step)'.\\00a0')::before",
26
- "mb-2xs (counter-increment:step|1) (counter-set:step|9) fg-text-blue::before (content:counter(step)'.\\00a0')::before",
27
- "mb-2xs (counter-increment:step|1) fg-text-blue::before (content:counter(step)'.\\00a0')::before"
24
+ "m(0) p(0) font-md leading-lg (list-style:none) (counter-reset:step_0)",
25
+ "mb-2xs (counter-increment:step_1) fg-text-blue::before (content:counter(step)'.\\00a0')::before",
26
+ "mb-2xs (counter-increment:step_1) (counter-set:step_9) fg-text-blue::before (content:counter(step)'.\\00a0')::before",
27
+ "mb-2xs (counter-increment:step_1) fg-text-blue::before (content:counter(step)'.\\00a0')::before"
28
28
  ],
29
29
  "highlighted": []
30
30
  }
@@ -4,19 +4,19 @@
4
4
  "id": "use-drop-shadow-for-transparent-images",
5
5
  "title": "Use drop shadow for transparent images",
6
6
  "html": [
7
- "<!-- Drop shadow · follows the shapes -->\n<svg id=\"target\" role=\"img\"\n aria-label=\"Circle and diamond\"\n width=\"160\" height=\"120\" viewBox=\"0 0 160 120\"\n class=\"block m-md\n (filter:drop-shadow(0|4px|2px|#7c3aed))\">\n <circle cx=\"48\" cy=\"60\" r=\"28\" fill=\"#2563eb\" />\n <path d=\"M100 30 140 60 100 90 60 60Z\" fill=\"#7c3aed\" />\n</svg>",
8
- "<!-- Box shadow · follows the viewport box -->\n<svg id=\"target\" role=\"img\"\n aria-label=\"Circle and diamond\"\n width=\"160\" height=\"120\" viewBox=\"0 0 160 120\"\n class=\"block m-md (box-shadow:0|4px|2px|#7c3aed)\">\n <circle cx=\"48\" cy=\"60\" r=\"28\" fill=\"#2563eb\" />\n <path d=\"M100 30 140 60 100 90 60 60Z\" fill=\"#7c3aed\" />\n</svg>"
7
+ "<!-- Drop shadow · follows the shapes -->\n<svg id=\"target\" role=\"img\"\n aria-label=\"Circle and diamond\"\n width=\"160\" height=\"120\" viewBox=\"0 0 160 120\"\n class=\"block m-md\n (filter:drop-shadow(0_4px_2px_#7c3aed))\">\n <circle cx=\"48\" cy=\"60\" r=\"28\" fill=\"#2563eb\" />\n <path d=\"M100 30 140 60 100 90 60 60Z\" fill=\"#7c3aed\" />\n</svg>",
8
+ "<!-- Box shadow · follows the viewport box -->\n<svg id=\"target\" role=\"img\"\n aria-label=\"Circle and diamond\"\n width=\"160\" height=\"120\" viewBox=\"0 0 160 120\"\n class=\"block m-md (box-shadow:0_4px_2px_#7c3aed)\">\n <circle cx=\"48\" cy=\"60\" r=\"28\" fill=\"#2563eb\" />\n <path d=\"M100 30 140 60 100 90 60 60Z\" fill=\"#7c3aed\" />\n</svg>"
9
9
  ],
10
10
  "css": "",
11
11
  "classes": [
12
12
  "block",
13
13
  "m-md",
14
- "(filter:drop-shadow(0|4px|2px|#7c3aed))",
15
- "(box-shadow:0|4px|2px|#7c3aed)"
14
+ "(filter:drop-shadow(0_4px_2px_#7c3aed))",
15
+ "(box-shadow:0_4px_2px_#7c3aed)"
16
16
  ],
17
17
  "classLists": [
18
- "block m-md (filter:drop-shadow(0|4px|2px|#7c3aed))",
19
- "block m-md (box-shadow:0|4px|2px|#7c3aed)"
18
+ "block m-md (filter:drop-shadow(0_4px_2px_#7c3aed))",
19
+ "block m-md (box-shadow:0_4px_2px_#7c3aed)"
20
20
  ],
21
21
  "highlighted": []
22
22
  }
@@ -5,7 +5,7 @@
5
5
  "title": "Fill gaps densely",
6
6
  "html": [
7
7
  "<div id=\"layout\" class=\"grid grid-cols(3) (grid-auto-flow:row) (grid-auto-rows:48px) gap-md (width:17.5rem) max-w-full\">\n <button id=\"target\" class=\"grid-col-span(2) p-sm\" type=\"button\" tabindex=\"0\">01</button>\n <button id=\"peer\" class=\"grid-col-span(2) p-sm\" type=\"button\" tabindex=\"0\">02</button>\n <button id=\"item-3\" class=\"p-sm\" type=\"button\" tabindex=\"0\">03</button>\n <button id=\"item-4\" class=\"p-sm\" type=\"button\" tabindex=\"0\">04</button>\n</div>",
8
- "<div id=\"layout\" class=\"grid grid-cols(3) (grid-auto-flow:row|dense) (grid-auto-rows:48px) gap-md (width:17.5rem) max-w-full\">\n <button id=\"target\" class=\"grid-col-span(2) p-sm\" type=\"button\" tabindex=\"0\">01</button>\n <button id=\"peer\" class=\"grid-col-span(2) p-sm\" type=\"button\" tabindex=\"0\">02</button>\n <button id=\"item-3\" class=\"p-sm\" type=\"button\" tabindex=\"0\">03</button>\n <button id=\"item-4\" class=\"p-sm\" type=\"button\" tabindex=\"0\">04</button>\n</div>"
8
+ "<div id=\"layout\" class=\"grid grid-cols(3) (grid-auto-flow:row_dense) (grid-auto-rows:48px) gap-md (width:17.5rem) max-w-full\">\n <button id=\"target\" class=\"grid-col-span(2) p-sm\" type=\"button\" tabindex=\"0\">01</button>\n <button id=\"peer\" class=\"grid-col-span(2) p-sm\" type=\"button\" tabindex=\"0\">02</button>\n <button id=\"item-3\" class=\"p-sm\" type=\"button\" tabindex=\"0\">03</button>\n <button id=\"item-4\" class=\"p-sm\" type=\"button\" tabindex=\"0\">04</button>\n</div>"
9
9
  ],
10
10
  "css": "",
11
11
  "classes": [
@@ -18,7 +18,7 @@
18
18
  "max-w-full",
19
19
  "grid-col-span(2)",
20
20
  "p-sm",
21
- "(grid-auto-flow:row|dense)"
21
+ "(grid-auto-flow:row_dense)"
22
22
  ],
23
23
  "classLists": [
24
24
  "grid grid-cols(3) (grid-auto-flow:row) (grid-auto-rows:48px) gap-md (width:17.5rem) max-w-full",
@@ -26,7 +26,7 @@
26
26
  "grid-col-span(2) p-sm",
27
27
  "p-sm",
28
28
  "p-sm",
29
- "grid grid-cols(3) (grid-auto-flow:row|dense) (grid-auto-rows:48px) gap-md (width:17.5rem) max-w-full",
29
+ "grid grid-cols(3) (grid-auto-flow:row_dense) (grid-auto-rows:48px) gap-md (width:17.5rem) max-w-full",
30
30
  "grid-col-span(2) p-sm",
31
31
  "grid-col-span(2) p-sm",
32
32
  "p-sm",
@@ -4,27 +4,27 @@
4
4
  "id": "apply-conditionally",
5
5
  "title": "Apply conditionally",
6
6
  "html": [
7
- "<div id=\"layout\" class=\"grid (grid-template-areas:'head'|'nav'|'main') (grid-template-columns:1fr) (grid-template-rows:48px|48px|96px) gap-md (width:17.5rem) max-w-full (grid-template-areas:'head\\20head'|'nav\\20main')@sm (grid-template-columns:80px|1fr)@sm (grid-template-rows:48px|96px)@sm\">\n <header id=\"target\" class=\"(grid-area:head) p-sm\">Header</header>\n <aside id=\"peer\" class=\"(grid-area:nav) p-sm\">Nav</aside>\n <section id=\"item-3\" class=\"(grid-area:main) p-sm\">Content</section>\n</div>"
7
+ "<div id=\"layout\" class=\"grid (grid-template-areas:'head'|'nav'|'main') (grid-template-columns:1fr) (grid-template-rows:48px_48px_96px) gap-md (width:17.5rem) max-w-full (grid-template-areas:'head\\20head'|'nav\\20main')@sm (grid-template-columns:80px_1fr)@sm (grid-template-rows:48px_96px)@sm\">\n <header id=\"target\" class=\"(grid-area:head) p-sm\">Header</header>\n <aside id=\"peer\" class=\"(grid-area:nav) p-sm\">Nav</aside>\n <section id=\"item-3\" class=\"(grid-area:main) p-sm\">Content</section>\n</div>"
8
8
  ],
9
9
  "css": "",
10
10
  "classes": [
11
11
  "grid",
12
12
  "(grid-template-areas:'head'|'nav'|'main')",
13
13
  "(grid-template-columns:1fr)",
14
- "(grid-template-rows:48px|48px|96px)",
14
+ "(grid-template-rows:48px_48px_96px)",
15
15
  "gap-md",
16
16
  "(width:17.5rem)",
17
17
  "max-w-full",
18
18
  "(grid-template-areas:'head\\20head'|'nav\\20main')@sm",
19
- "(grid-template-columns:80px|1fr)@sm",
20
- "(grid-template-rows:48px|96px)@sm",
19
+ "(grid-template-columns:80px_1fr)@sm",
20
+ "(grid-template-rows:48px_96px)@sm",
21
21
  "(grid-area:head)",
22
22
  "p-sm",
23
23
  "(grid-area:nav)",
24
24
  "(grid-area:main)"
25
25
  ],
26
26
  "classLists": [
27
- "grid (grid-template-areas:'head'|'nav'|'main') (grid-template-columns:1fr) (grid-template-rows:48px|48px|96px) gap-md (width:17.5rem) max-w-full (grid-template-areas:'head\\20head'|'nav\\20main')@sm (grid-template-columns:80px|1fr)@sm (grid-template-rows:48px|96px)@sm",
27
+ "grid (grid-template-areas:'head'|'nav'|'main') (grid-template-columns:1fr) (grid-template-rows:48px_48px_96px) gap-md (width:17.5rem) max-w-full (grid-template-areas:'head\\20head'|'nav\\20main')@sm (grid-template-columns:80px_1fr)@sm (grid-template-rows:48px_96px)@sm",
28
28
  "(grid-area:head) p-sm",
29
29
  "(grid-area:nav) p-sm",
30
30
  "(grid-area:main) p-sm"
@@ -4,14 +4,14 @@
4
4
  "id": "use-minmax",
5
5
  "title": "Control a track’s minimum",
6
6
  "html": [
7
- "<div id=\"layout\" class=\"grid (grid-auto-rows:64px) (grid-template-columns:1fr|2fr) gap-md (width:17.5rem) max-w-full\">\n <div id=\"target\" class=\"overflow-clip p-sm\"><span class=\"block (width:12rem)\">192px content</span></div>\n <div id=\"peer\" class=\"p-sm\">2</div>\n</div>",
8
- "<div id=\"layout\" class=\"grid (grid-auto-rows:64px) (grid-template-columns:minmax(0,1fr)|2fr) gap-md (width:17.5rem) max-w-full\">\n <div id=\"target\" class=\"overflow-clip p-sm\"><span class=\"block (width:12rem)\">192px content</span></div>\n <div id=\"peer\" class=\"p-sm\">2</div>\n</div>"
7
+ "<div id=\"layout\" class=\"grid (grid-auto-rows:64px) (grid-template-columns:1fr_2fr) gap-md (width:17.5rem) max-w-full\">\n <div id=\"target\" class=\"overflow-clip p-sm\"><span class=\"block (width:12rem)\">192px content</span></div>\n <div id=\"peer\" class=\"p-sm\">2</div>\n</div>",
8
+ "<div id=\"layout\" class=\"grid (grid-auto-rows:64px) (grid-template-columns:minmax(0,1fr)_2fr) gap-md (width:17.5rem) max-w-full\">\n <div id=\"target\" class=\"overflow-clip p-sm\"><span class=\"block (width:12rem)\">192px content</span></div>\n <div id=\"peer\" class=\"p-sm\">2</div>\n</div>"
9
9
  ],
10
10
  "css": "",
11
11
  "classes": [
12
12
  "grid",
13
13
  "(grid-auto-rows:64px)",
14
- "(grid-template-columns:1fr|2fr)",
14
+ "(grid-template-columns:1fr_2fr)",
15
15
  "gap-md",
16
16
  "(width:17.5rem)",
17
17
  "max-w-full",
@@ -19,14 +19,14 @@
19
19
  "p-sm",
20
20
  "block",
21
21
  "(width:12rem)",
22
- "(grid-template-columns:minmax(0,1fr)|2fr)"
22
+ "(grid-template-columns:minmax(0,1fr)_2fr)"
23
23
  ],
24
24
  "classLists": [
25
- "grid (grid-auto-rows:64px) (grid-template-columns:1fr|2fr) gap-md (width:17.5rem) max-w-full",
25
+ "grid (grid-auto-rows:64px) (grid-template-columns:1fr_2fr) gap-md (width:17.5rem) max-w-full",
26
26
  "overflow-clip p-sm",
27
27
  "block (width:12rem)",
28
28
  "p-sm",
29
- "grid (grid-auto-rows:64px) (grid-template-columns:minmax(0,1fr)|2fr) gap-md (width:17.5rem) max-w-full",
29
+ "grid (grid-auto-rows:64px) (grid-template-columns:minmax(0,1fr)_2fr) gap-md (width:17.5rem) max-w-full",
30
30
  "overflow-clip p-sm",
31
31
  "block (width:12rem)",
32
32
  "p-sm"
@@ -4,15 +4,15 @@
4
4
  "id": "use-explicit-css-values",
5
5
  "title": "Keep overflowing content reachable",
6
6
  "html": [
7
- "<div id=\"layout\" class=\"flex overflow-auto (justify-content:safe|center) (width:15rem) max-w-full\" tabindex=\"0\" role=\"region\" aria-label=\"Safe centered overflow\">\n <div id=\"target\" class=\"flex (flex:none) justify-between (height:4rem) (width:17.5rem) p-xs\"><span>Start</span><span>End</span></div>\n</div>",
8
- "<div id=\"layout\" class=\"flex overflow-auto (justify-content:unsafe|center) (width:15rem) max-w-full\" tabindex=\"0\" role=\"region\" aria-label=\"Unsafe centered overflow\">\n <div id=\"target\" class=\"flex (flex:none) justify-between (height:4rem) (width:17.5rem) p-xs\"><span>Start</span><span>End</span></div>\n</div>",
9
- "<div id=\"layout\" class=\"flex overflow-auto (justify-content:safe|center) (width:15rem) max-w-full\" tabindex=\"0\" role=\"region\" aria-label=\"Safe centered fitting content\">\n <div id=\"target\" class=\"flex (flex:none) justify-between (height:4rem) (width:12rem) p-xs\"><span>Start</span><span>End</span></div>\n</div>"
7
+ "<div id=\"layout\" class=\"flex overflow-auto (justify-content:safe_center) (width:15rem) max-w-full\" tabindex=\"0\" role=\"region\" aria-label=\"Safe centered overflow\">\n <div id=\"target\" class=\"flex (flex:none) justify-between (height:4rem) (width:17.5rem) p-xs\"><span>Start</span><span>End</span></div>\n</div>",
8
+ "<div id=\"layout\" class=\"flex overflow-auto (justify-content:unsafe_center) (width:15rem) max-w-full\" tabindex=\"0\" role=\"region\" aria-label=\"Unsafe centered overflow\">\n <div id=\"target\" class=\"flex (flex:none) justify-between (height:4rem) (width:17.5rem) p-xs\"><span>Start</span><span>End</span></div>\n</div>",
9
+ "<div id=\"layout\" class=\"flex overflow-auto (justify-content:safe_center) (width:15rem) max-w-full\" tabindex=\"0\" role=\"region\" aria-label=\"Safe centered fitting content\">\n <div id=\"target\" class=\"flex (flex:none) justify-between (height:4rem) (width:12rem) p-xs\"><span>Start</span><span>End</span></div>\n</div>"
10
10
  ],
11
11
  "css": "",
12
12
  "classes": [
13
13
  "flex",
14
14
  "overflow-auto",
15
- "(justify-content:safe|center)",
15
+ "(justify-content:safe_center)",
16
16
  "(width:15rem)",
17
17
  "max-w-full",
18
18
  "(flex:none)",
@@ -20,15 +20,15 @@
20
20
  "(height:4rem)",
21
21
  "(width:17.5rem)",
22
22
  "p-xs",
23
- "(justify-content:unsafe|center)",
23
+ "(justify-content:unsafe_center)",
24
24
  "(width:12rem)"
25
25
  ],
26
26
  "classLists": [
27
- "flex overflow-auto (justify-content:safe|center) (width:15rem) max-w-full",
27
+ "flex overflow-auto (justify-content:safe_center) (width:15rem) max-w-full",
28
28
  "flex (flex:none) justify-between (height:4rem) (width:17.5rem) p-xs",
29
- "flex overflow-auto (justify-content:unsafe|center) (width:15rem) max-w-full",
29
+ "flex overflow-auto (justify-content:unsafe_center) (width:15rem) max-w-full",
30
30
  "flex (flex:none) justify-between (height:4rem) (width:17.5rem) p-xs",
31
- "flex overflow-auto (justify-content:safe|center) (width:15rem) max-w-full",
31
+ "flex overflow-auto (justify-content:safe_center) (width:15rem) max-w-full",
32
32
  "flex (flex:none) justify-between (height:4rem) (width:12rem) p-xs"
33
33
  ],
34
34
  "highlighted": []