{"_id":"@316software/brand","_rev":"7-ea445250dba23c86645de4383fae578c","name":"@316software/brand","dist-tags":{"latest":"1.3.1"},"versions":{"1.0.0":{"name":"@316software/brand","version":"1.0.0","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","_id":"@316software/brand@1.0.0","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"homepage":"https://316software.com/design-system","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"dist":{"shasum":"48c030906548a049d5832be2140f2286ddde666e","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.0.0.tgz","fileCount":26,"integrity":"sha512-g6GYF2gXGftsb3eqVLv5ZeZ50+wN6fCJlPXBUKvOmt21qkIByXP4QVTauoDD1S5GNxb0Rfpb61HY88bkDb/Osg==","signatures":[{"sig":"MEYCIQC1+RzjhUmEJl5PID8VViUHSTElRCjLTkcR4pdwkK4/tgIhAIhWirNePORvUBUEytGyG4+KUxgVD6iRhQlfrbrsZaMn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":163597},"type":"module","engines":{"node":">=20.10"},"exports":{".":"./src/brand.mjs","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./theme.js":"./dist/theme.js","./tokens.css":"./dist/tokens.css","./tokens.json":"./tokens.json","./tailwind.css":"./dist/tailwind.css","./components.css":"./src/components.css","./fonts/sora.woff2":"./fonts/sora.woff2","./tokens-light.css":"./dist/tokens-light.css"},"gitHead":"58a97b75ff48d3e310597f2d5128bd00f5d95b3c","scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"url":"git+https://github.com/cpenarrieta/316-brand.git","type":"git"},"_npmVersion":"12.0.2","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.2.8","typescript":"^5.9.0","@types/react":"^19.2.18","@base-ui/react":"^1.7.0"},"peerDependencies":{"react":">=18","@base-ui/react":">=1"},"peerDependenciesMeta":{"react":{"optional":true},"@base-ui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/brand_1.0.0_1786577208306_0.14698540440973895","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@316software/brand","version":"1.1.0","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","_id":"@316software/brand@1.1.0","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"homepage":"https://316software.com/design-system","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"bin":{"brand-assets":"bin/brand-assets.mjs"},"dist":{"shasum":"b6978716a8dfc568a9dd3882cb21bd89383be2b3","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.1.0.tgz","fileCount":30,"integrity":"sha512-w7DJONJAqMo2fwemy+xt0ituOg8Hcxz4RPsrC/edqEChXHZ3bM20oG+7SwyVymRK0ULHYAFPYzWX/qU+jGcyjw==","signatures":[{"sig":"MEQCIHppPiH5T2IRhTdHdzPIYax2cfvcNQ+sYyFWrmiZePysAiBKPaR2iX/eustuY9+yUC8kp914XHGVQCtuO9vgfId+ug==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":177407},"type":"module","engines":{"node":">=20.10"},"exports":{".":"./src/brand.mjs","./astro":"./bin/astro.mjs","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./assets":"./bin/assets.mjs","./fonts/*":"./fonts/*","./theme.js":"./dist/theme.js","./tokens.css":"./dist/tokens.css","./tokens.json":"./tokens.json","./tailwind.css":"./dist/tailwind.css","./components.css":"./src/components.css","./fonts/sora.woff2":"./fonts/sora.woff2","./tokens-light.css":"./dist/tokens-light.css"},"gitHead":"58a97b75ff48d3e310597f2d5128bd00f5d95b3c","scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","prepublishOnly":"npm run build && node scripts/verify-publish.mjs"},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"url":"git+https://github.com/cpenarrieta/316-brand.git","type":"git"},"_npmVersion":"12.0.2","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.2.8","typescript":"^5.9.0","@types/react":"^19.2.18","@base-ui/react":"^1.7.0"},"peerDependencies":{"react":">=18","@base-ui/react":">=1"},"peerDependenciesMeta":{"react":{"optional":true},"@base-ui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/brand_1.1.0_1786664239576_0.5728375080759811","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@316software/brand","version":"1.2.0","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","_id":"@316software/brand@1.2.0","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"homepage":"https://316software.com/design-system","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"bin":{"brand-assets":"bin/brand-assets.mjs"},"dist":{"shasum":"a09ba41c4d7aa562d6352da88c46d4f56cf57c5c","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.2.0.tgz","fileCount":71,"integrity":"sha512-Otv5FhGsj8T9L3vlvJx4WmUivb4dcIKHe+CC3dp0wkJ+Ywx2WCH2KahsQjE55SGdJzuyjNo4cG/x3bkbECk+Bg==","signatures":[{"sig":"MEUCIQCjhnV0qGvCOH4ozYH5Dr7PykgzgO7ZIOuaIT2Y4osBkQIgYaNeZfCYlqUGG434Kp4UoNbz88ngLP15dGCMz3C4198=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":361125},"type":"module","engines":{"node":">=20.10"},"exports":{".":"./src/brand.mjs","./astro":"./bin/astro.mjs","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./app.js":"./src/app.js","./assets":"./bin/assets.mjs","./fonts/*":"./fonts/*","./mask.mjs":"./src/mask.mjs","./theme.js":"./dist/theme.js","./tokens.css":"./dist/tokens.css","./tokens.json":"./tokens.json","./tailwind.css":"./dist/tailwind.css","./components.css":"./src/components.css","./fonts/sora.woff2":"./fonts/sora.woff2","./tokens-light.css":"./dist/tokens-light.css"},"gitHead":"224bd7de0ea938a8a2ebc471f35710cdc5964864","scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","preview":"node scripts/preview.mjs","prepublishOnly":"npm run build && node scripts/verify-publish.mjs"},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"url":"git+https://github.com/cpenarrieta/316-brand.git","type":"git"},"_npmVersion":"12.0.2","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.2.8","esbuild":"^0.28.0","react-dom":"^19.2.8","typescript":"^5.9.0","@types/react":"^19.2.18","@base-ui/react":"^1.7.0"},"peerDependencies":{"react":">=18","@base-ui/react":">=1"},"peerDependenciesMeta":{"react":{"optional":true},"@base-ui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/brand_1.2.0_1787304516155_0.391968800442422","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@316software/brand","version":"1.2.1","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","_id":"@316software/brand@1.2.1","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"homepage":"https://316software.com/design-system","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"bin":{"brand-assets":"bin/brand-assets.mjs"},"dist":{"shasum":"37eca3e2b95f332ed052a41b7686f7ab7ad4478b","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.2.1.tgz","fileCount":71,"integrity":"sha512-gpW9OeV3lG/wiYJiWRdguutpg6810jAiYqP/J9E+Pee+NHWNcd8KMxMXMO9/UzulG9u/uk3jPtDMMA05IkR85Q==","signatures":[{"sig":"MEYCIQDNkeMr3U46K0BZIAXx5OwBGZzXk7YJ7iVr9ur9xfEhfwIhAI0pU2E96y4/4Iq07I7/Gl5F4v7gfeco/T/4FFpZ8jd7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":361946},"type":"module","engines":{"node":">=20.10"},"exports":{".":"./src/brand.mjs","./astro":"./bin/astro.mjs","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./app.js":"./src/app.js","./assets":"./bin/assets.mjs","./fonts/*":"./fonts/*","./mask.mjs":"./src/mask.mjs","./theme.js":"./dist/theme.js","./tokens.css":"./dist/tokens.css","./tokens.json":"./tokens.json","./tailwind.css":"./dist/tailwind.css","./components.css":"./src/components.css","./fonts/sora.woff2":"./fonts/sora.woff2","./tokens-light.css":"./dist/tokens-light.css"},"gitHead":"10aa51bcc43a25e42aa50b59091d0dcd6a41f4d7","scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","preview":"node scripts/preview.mjs","prepublishOnly":"npm run build && node scripts/verify-publish.mjs"},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"url":"git+https://github.com/cpenarrieta/316-brand.git","type":"git"},"_npmVersion":"12.0.2","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.2.8","esbuild":"^0.28.0","react-dom":"^19.2.8","typescript":"^5.9.0","@types/react":"^19.2.18","@base-ui/react":"^1.7.0"},"peerDependencies":{"react":">=18","@base-ui/react":">=1"},"peerDependenciesMeta":{"react":{"optional":true},"@base-ui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/brand_1.2.1_1787322664059_0.6541739347062898","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@316software/brand","version":"1.2.2","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","_id":"@316software/brand@1.2.2","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"homepage":"https://316software.com/design-system","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"bin":{"brand-assets":"bin/brand-assets.mjs"},"dist":{"shasum":"51afb47da0c543291798efa4eff74a73ec695776","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.2.2.tgz","fileCount":70,"integrity":"sha512-yddZZ9so57b/SitLk43DCKngUhj1Xnx1OikvQqoDe0onX0AtZBPtx66kO/udmEsKo3PIlbfRvXL3syl2Nmb8pQ==","signatures":[{"sig":"MEUCIQDAbWHBchggMjwqWmO0wsgI39o+fuZNfwuElqC/HSGL0QIgNHPOKvlkeuCdz/a1pivHSSJAuRgQ9kGla8QTFMQgKCs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":360660},"type":"module","engines":{"node":">=20.10"},"exports":{".":"./src/brand.mjs","./astro":"./bin/astro.mjs","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./app.js":"./src/app.js","./assets":"./bin/assets.mjs","./fonts/*":"./fonts/*","./mask.mjs":"./src/mask.mjs","./theme.js":"./dist/theme.js","./tokens.css":"./dist/tokens.css","./tokens.json":"./tokens.json","./tailwind.css":"./dist/tailwind.css","./components.css":"./src/components.css","./fonts/sora.woff2":"./fonts/sora.woff2","./tokens-light.css":"./dist/tokens-light.css"},"gitHead":"0d25de77a113e9f95fda385c7dd32802eb489e5d","scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","preview":"node scripts/preview.mjs","preview:build":"npm run build && node scripts/preview-build.mjs","prepublishOnly":"npm run build && node scripts/verify-publish.mjs"},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"url":"git+https://github.com/cpenarrieta/316-brand.git","type":"git"},"_npmVersion":"12.0.2","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.2.8","esbuild":"^0.28.0","react-dom":"^19.2.8","typescript":"^5.9.0","@types/react":"^19.2.18","@base-ui/react":"^1.7.0"},"peerDependencies":{"react":">=18","@base-ui/react":">=1"},"peerDependenciesMeta":{"react":{"optional":true},"@base-ui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/brand_1.2.2_1787348268662_0.3059097646030635","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@316software/brand","version":"1.3.0","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","_id":"@316software/brand@1.3.0","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"homepage":"https://316-brand.pages.dev","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"bin":{"brand-assets":"bin/brand-assets.mjs"},"dist":{"shasum":"937003961e4647f4c240db00f8e9b71e7286f6d1","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.3.0.tgz","fileCount":75,"integrity":"sha512-BJ/U4dWw4gFuYUhVNDZxrrMnYkLzLrVy1MSPYCe1HwfjT/BLn1r/DI1NMfke6nq5D43uR+Up6pN8bF30OOjWLQ==","signatures":[{"sig":"MEQCIF6+/t8+gMG8iZ+YU98utYdqdxvc3Y0tcPAW60J0YlmBAiBxMWKko9GTuSvH9Vk0gON+O6qdaAZpW8h8XkuvomBSQg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":390949},"type":"module","engines":{"node":">=20.10"},"exports":{".":"./src/brand.mjs","./astro":"./bin/astro.mjs","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./app.js":"./src/app.js","./assets":"./bin/assets.mjs","./fonts/*":"./fonts/*","./mask.mjs":"./src/mask.mjs","./theme.js":"./dist/theme.js","./tokens.css":"./dist/tokens.css","./tokens.json":"./tokens.json","./tailwind.css":"./dist/tailwind.css","./components.css":"./src/components.css","./refs/tokens.md":"./dist/refs/tokens.md","./refs/imagery.md":"./dist/refs/imagery.md","./fonts/sora.woff2":"./fonts/sora.woff2","./refs/diagrams.md":"./dist/refs/diagrams.md","./tokens-light.css":"./dist/tokens-light.css","./refs/documents.md":"./dist/refs/documents.md"},"gitHead":"0d25de77a113e9f95fda385c7dd32802eb489e5d","scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","preview":"node scripts/preview.mjs","preview:build":"npm run build && node scripts/preview-build.mjs","prepublishOnly":"npm run build && node scripts/verify-publish.mjs"},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"url":"git+https://github.com/cpenarrieta/316-brand.git","type":"git"},"_npmVersion":"12.0.2","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"^19.2.8","esbuild":"^0.28.0","react-dom":"^19.2.8","typescript":"^5.9.0","@types/react":"^19.2.18","@base-ui/react":"^1.7.0","node-html-parser":"^9.0.1"},"peerDependencies":{"react":">=18","@base-ui/react":">=1"},"peerDependenciesMeta":{"react":{"optional":true},"@base-ui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/brand_1.3.0_1787375910425_0.5285398357731002","host":"s3://npm-registry-packages-npm-production"}},"1.3.1":{"name":"@316software/brand","version":"1.3.1","description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","type":"module","license":"SEE LICENSE IN LICENSE.md","author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"repository":{"type":"git","url":"git+https://github.com/cpenarrieta/316-brand.git"},"homepage":"https://brand.316software.com","exports":{".":"./src/brand.mjs","./tokens.json":"./tokens.json","./tokens.css":"./dist/tokens.css","./tokens-light.css":"./dist/tokens-light.css","./components.css":"./src/components.css","./app.js":"./src/app.js","./mask.mjs":"./src/mask.mjs","./tailwind.css":"./dist/tailwind.css","./theme.js":"./dist/theme.js","./fonts/sora.woff2":"./fonts/sora.woff2","./refs/imagery.md":"./dist/refs/imagery.md","./refs/diagrams.md":"./dist/refs/diagrams.md","./refs/documents.md":"./dist/refs/documents.md","./refs/tokens.md":"./dist/refs/tokens.md","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./fonts/*":"./fonts/*","./astro":"./bin/astro.mjs","./assets":"./bin/assets.mjs"},"sideEffects":["**/*.css"],"scripts":{"build":"node scripts/build.mjs && tsc -p tsconfig.react.json","prepare":"npm run build","prepublishOnly":"npm run build && node scripts/verify-publish.mjs","preview":"node scripts/preview.mjs","preview:build":"npm run build && node scripts/preview-build.mjs"},"engines":{"node":">=20.10"},"peerDependencies":{"@base-ui/react":">=1","react":">=18"},"peerDependenciesMeta":{"@base-ui/react":{"optional":true},"react":{"optional":true}},"devDependencies":{"@base-ui/react":"^1.7.0","@types/react":"^19.2.18","esbuild":"^0.28.0","node-html-parser":"^9.0.1","react":"^19.2.8","react-dom":"^19.2.8","typescript":"^5.9.0"},"publishConfig":{"access":"public"},"bin":{"brand-assets":"bin/brand-assets.mjs"},"gitHead":"9cc282515941a43095aacdb0534d5f5e86a354d5","_id":"@316software/brand@1.3.1","bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"_nodeVersion":"24.18.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-pO1OLgg4K4z10g4cgmaolS9FbMQKEGUYl5fxekVK7dfEnoZtsoK/0ra99fSP0erlYeflB1LsInEuppRS80S2bQ==","shasum":"d2cda7cf8a39660f944c20b5cdffe431bc57ccca","tarball":"https://registry.npmjs.org/@316software/brand/-/brand-1.3.1.tgz","fileCount":75,"unpackedSize":391307,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDNQjYxBZ35GCZdTj1vdzHtSwmUs9UrHqADaZN+khpMNAiEAjvvmwfPAj3qOiLs60wizJnJZfKW2Yxu3oVEgdVicuF0="}]},"_npmUser":{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"},"directories":{},"maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/brand_1.3.1_1787378713777_0.8214271089837961"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-12T23:26:48.057Z","modified":"2026-08-22T06:05:14.133Z","1.0.0":"2026-08-12T23:26:48.455Z","1.1.0":"2026-08-13T23:37:19.724Z","1.2.0":"2026-08-21T09:28:36.311Z","1.2.1":"2026-08-21T14:31:04.214Z","1.2.2":"2026-08-21T21:37:48.820Z","1.3.0":"2026-08-22T05:18:30.556Z","1.3.1":"2026-08-22T06:05:13.916Z"},"bugs":{"url":"https://github.com/cpenarrieta/316-brand/issues"},"author":{"name":"Cristian Penarrieta","email":"cristian.penarrieta@gmail.com"},"license":"SEE LICENSE IN LICENSE.md","homepage":"https://brand.316software.com","repository":{"type":"git","url":"git+https://github.com/cpenarrieta/316-brand.git"},"description":"316Software design tokens, brand CSS, theme control, and React components. One source of truth for every 316 surface.","maintainers":[{"name":"cpenarrieta","email":"cristian.penarrieta@gmail.com"}],"readme":"# @316software/brand\n\nThe 316Software brand as an installable package: design tokens, the component\nstylesheet, the colour-scheme control, the Sora font, and a React layer. One\nsource of truth; every 316 surface installs it instead of carrying a copy.\n\nThe documentation is published from this repository, three sheets on one\nhost:\n\n| Sheet | What it is |\n| --- | --- |\n| [brand.316software.com](https://brand.316software.com) | **The design system.** Principles, logotype, typeface, colour, spacing, motion, iconography, voice, imagery, technical diagrams, charts, documents and decks, accessibility, and the tokens as copyable CSS and JSON |\n| [/kit](https://brand.316software.com/kit) | The in-app kit: every component in every state, wired by `app.js` |\n| [/react](https://brand.316software.com/react) | The same kit, wired by Base UI |\n\nThey were four pages on two hosts until 2026-08-21 — two of them on\n316software.com — and they disagreed with each other, because a component was\nonly ever added to whichever page happened to be open. The old URLs are gone;\nthis is the whole of it.\n\n`316-brand.pages.dev` is the Pages project's own hostname and still serves the\nsame bytes, but the documented URL is the subdomain. It is the one written\ninto `tokens.json`, into the standing brief on the sheet itself, and into\n316software.com's `llms.txt`, and a custom domain can be repointed at another\nhost without republishing any of them.\n\n## Install\n\n```bash\nnpm i @316software/brand\n```\n\n## What's inside\n\n| Import | What it is |\n| --- | --- |\n| `@316software/brand` | JS API: `tokens`, `byName()`, and the renderers (`renderBlock`, `renderJson`, `renderMarkdown`, ...) |\n| `@316software/brand/tokens.json` | The token source (colour, space, motion, type, chart palettes) |\n| `@316software/brand/tokens.css` | Custom properties, both schemes via `light-dark()` |\n| `@316software/brand/tokens-light.css` | Flat light values (social cards, screenshots) |\n| `@316software/brand/components.css` | The component classes (`.btn`, `.field`, `.alert`, `.appbar`, ...) |\n| `@316software/brand/app.js` | The behaviour layer: data attributes that wire masks, tabs, menus, folds, dialogs, toasts (ESM, no bundler needed) |\n| `@316software/brand/mask.mjs` | The mask engine on its own (`formatPhone`, `maskWithCaret`, `MASKS`), framework free and safe on the server |\n| `@316software/brand/tailwind.css` | Tailwind v4 `@theme` bridge (`bg-paper`, `text-ink`, `text-crit`, ...) |\n| `@316software/brand/theme.js` | The auto/light/dark cycle control (classic script, render-blocking by design) |\n| `@316software/brand/fonts/sora.woff2` | Sora, variable, SIL OFL 1.1 |\n| `@316software/brand/refs/*.md` | The design system's own rules as markdown — `imagery.md`, `diagrams.md`, `documents.md`, `tokens.md`. Generated from the design sheet at build time; what the 316 skill bundles carry |\n\n## Contracts\n\nTwo conventions the CSS assumes; keep them and everything just works:\n\n- **The font is served at `/fonts/sora.woff2`.** `tokens.css` declares the\n  `@font-face` with that absolute URL. Copy the font out of the package into\n  your static dir at build time (see below), or override the `@font-face`.\n- **Theming is `data-theme` on `<html>`.** No attribute follows the system;\n  `\"light\"`/`\"dark\"` pin a scheme. `theme.js` manages it: load it\n  render-blocking in `<head>` (inline, or plain `<script src>` without\n  defer/async) so the stored choice lands before first paint. Any button\n  carrying `data-theme-cycle` becomes the control:\n\n  ```html\n  <button type=\"button\" class=\"theme\" data-theme-cycle><span\n    class=\"theme__swatch\" aria-hidden=\"true\"></span><span\n    class=\"vh\">Colour scheme: </span><span class=\"theme__label\"></span></button>\n  ```\n\n## The two layers\n\n`components.css` draws the kit. Interactive parts need something to move them,\nand there are two ways to get that, sharing one stylesheet and one mask engine:\n\n- **`app.js`** for plain HTML, Astro and Worker-rendered sheets. Data\n  attributes only, no framework, no build step.\n- **`./react`** for React surfaces. Behaviour from [Base UI](https://base-ui.com),\n  the same drawing, reconciled by section 10 of `components.css`.\n\nPick one per surface. A phone number is punctuated identically by either.\n\n### The behaviour layer\n\n```html\n<script type=\"module\" src=\"/app.js\"></script>\n```\n\n```js\nimport \"@316software/brand/app.js\";   // Astro, Vite\n```\n\nIt wires itself on load and `init(root)` is idempotent, so call it again after\nyou inject markup. Each behaviour is announced by one attribute:\n\n| Attribute | What it does |\n| --- | --- |\n| `data-mask=\"phone\"` | Punctuates as you type. Also `card`, `expiry`, `cvc`, `postal`, `zip`, `sin`, `date`, `time`, `digits`, `currency`, or a literal pattern (`#` digit, `A` letter, `*` either) |\n| `data-autogrow` | A textarea that grows into its content |\n| `data-count=\"180\"` | Character counter into the `.count` beside it |\n| `data-reveal=\"pw\"` | The password field's show/hide control |\n| `data-stepper` | The `-`/`+` controls on a `.stepper` |\n| `data-slider=\"%\"` | A range input reporting into `.slider__out`, filling its own rule |\n| `data-drop=\"list-id\"` | A `.drop` that takes a drag and lists what it caught |\n| `data-taginput` | Chips typed into one field |\n| `data-otp` | One-time code across its slots |\n| `data-combo` | A filtering listbox under a text field |\n| `data-tabs` | Roving-tabindex tabs over `.tabpanel` |\n| `data-fold=\"single\"` | A `.folds` accordion; `single` closes the others |\n| `data-menu` | A `.menu` with keyboard, outside-click and escape |\n| `data-dialog-open=\"#x\"` | Opens a `<dialog>`; `data-dialog-close` closes it, animated |\n| `data-copy` | Copies a code block and says so |\n| `data-dismiss` | Takes an `.alert` off the sheet |\n| `data-select-all` | A table header checkbox driving its rows and toolbar |\n| `data-toast=\"Saved\"` | Fires a toast; `data-toast-tone`, `data-toast-action` |\n\n`toast()`, `openDialog()`, `closeDialog()` and `init()` are also exported for\nthe cases an attribute cannot reach.\n\n## Using it\n\n### Astro\n\n```js\n// astro.config.mjs\nimport brand from \"@316software/brand/astro\";\nexport default defineConfig({ integrations: [brand()] });\n```\n\nThe integration copies the fonts into `public/` before dev/build (CSS comes\nin through Vite imports, below) and, after the build, verifies every\nroot-absolute ref in the emitted site resolves and that the lockfile holds no\n`file:`/`link:` brand entries. The copies are build artifacts: gitignore them.\n`brand({ only: [\"css\", \"theme\", \"fonts\"] })` copies the sheets too if you\nserve them as plain files.\n\n```js\nimport \"@316software/brand/tokens.css\";\nimport \"@316software/brand/components.css\";\n```\n\nInline a stylesheet into the page instead with `?raw`:\n\n```js\nimport tokens from \"@316software/brand/tokens.css?raw\";\n```\n\n### Plain HTML (Workers, static hosts)\n\nThe package ships its own copier + verifier, `brand-assets`. Wire it INSIDE\nthe deploy tool, not as an npm pre-hook (hooks sit beside the deploy path;\n`wrangler deploy` invoked directly walks straight past them):\n\n```jsonc\n// wrangler.jsonc\n\"build\": {\n  \"command\": \"npx --no-install brand-assets copy --out public && npx --no-install brand-assets verify --dir public --ignore /api\"\n}\n```\n\nthen\n\n```html\n<link rel=\"stylesheet\" href=\"/tokens.css\" />\n<link rel=\"stylesheet\" href=\"/components.css\" />\n<script src=\"/theme.js\"></script>\n<script type=\"module\" src=\"/app.js\"></script>\n```\n\nThe copier's sets are `css`, `theme`, `app` and `fonts`; `--only` picks among\nthem. `app` copies `app.js` and `mask.mjs` together, because the first imports\nthe second.\n\nThe copies are build artifacts: gitignore them. `verify` fails the build on\nany root-absolute `href`/`src`/`url()` that doesn't resolve to a file\n(`--ignore` skips Worker routes), and on any brand package resolved from\n`file:`/`link:` in the lockfile.\n\n### React (TanStack Start, Next.js)\n\n```tsx\nimport \"@316software/brand/tokens.css\";\nimport \"@316software/brand/components.css\";\nimport { Button, Field, PhoneInput, ToastProvider } from \"@316software/brand/react\";\n\n<Button variant=\"accent\">Publish</Button>\n\n<Field label=\"Phone\" help=\"We only use it if an upload fails overnight.\">\n  <PhoneInput onValueChange={(shown, raw) => save(raw)} />\n</Field>\n```\n\n`<Field>` owns the id and the aria wiring, so any control from the package\ndropped inside it picks both up.\n\nWhat is in there: `Button` `ButtonGroup` `Field` `Input` `TextArea` `Select`\n`Affix` `SearchInput` `PasswordInput` `FieldRow` `MaskedInput` `PhoneInput`\n`CurrencyInput` `Checkbox` `Radio` `RadioGroup` `ChoiceCard` `Switch` `Slider`\n`Stepper` `OTP` `Combobox` `TagInput` `Tabs` `Folds` `Menu` `Dialog` `Drawer`\n`Tooltip` `ToastProvider`/`useToast` `Alert` `Badge` `Tag` `Chip` `Avatar`\n`Person` `Skeleton` `Spinner` `Progress` `Upload` `Empty` `LoadFail`\n`CopyButton` `CodeBlock` `Steps` `Pagination`.\n\nBehaviour comes from [Base UI](https://base-ui.com); the drawing is the same\n`components.css` every other surface uses. `react` and `@base-ui/react` are\noptional peer dependencies: install them only if you import `./react`.\n\n### Tailwind v4\n\n```css\n@import \"tailwindcss\";\n@import \"@316software/brand/tokens.css\";\n@import \"@316software/brand/tailwind.css\";\n```\n\nThe bridge maps tokens into `@theme inline`, so utilities resolve through the\nsame variables and `light-dark()` still decides at paint time.\n\n## Developing\n\n```bash\nnpm install        # also runs the build (prepare)\nnpm run build      # tokens.json -> dist/, then the React layer via tsc\nnpm run preview    # the documentation site, all three sheets, on :4316\n```\n\n`npm run preview` assembles `preview/dist` and serves it on :4316. That\ndirectory is the documentation: `preview/index.html` is the design system,\n`preview/kit.html` the in-app kit, `preview/react.tsx` the React layer. Check\na change on all three before you bump.\n\nThe site is built as a plain-HTML consumer rather than out of some layout of\nits own: `scripts/preview-build.mjs` fills the directory using the package's\nown `brand-assets` copier, so the pages link `/tokens.css`, `/components.css`\nand `/app.js` exactly as documented above, and Sora resolves at the\n`/fonts/sora.woff2` the `@font-face` declares. The copier and the verifier are\ntherefore exercised on every build. Everything the sheets draw with comes out\nof the package; `preview/design.css` and `preview/design.js` hold the only\nexceptions, and they are documentation furniture (swatch cards, the type\nladder, copying a hex off the page) rather than components.\n\nSection 14 of the design sheet prints the tokens as CSS and JSON. Those two\nblocks are `<!--TOKENS_CSS-->` and `<!--TOKENS_JSON-->` in the source, filled\nfrom `tokens.json` at build time — the build fails on a marker it cannot fill,\nbecause an empty token specimen is the one thing that sheet cannot ship.\n\n`npm run preview:build` emits the same directory without serving it; that is\nwhat Cloudflare Pages runs on every push to main. The site carries\n`robots.txt` and an `X-Robots-Tag` header: it is the company's own reference,\nunlisted, as both sheets were on 316software.com. Nothing under `preview/` is\npublished to npm.\n\n### The rules as markdown\n\n`npm run build` also lifts sections 09, 10 and 12 off the design sheet into\n`dist/refs/*.md`, with `tokens.md` beside them from `renderMarkdown()`. The\n316 skill bundles (`316-pdf-creator` and its siblings) copy those four files\nout of `node_modules`, so the rules travel with the tokens and version with\nthem. They used to be scraped out of a page the 316software site had already\nbuilt, which meant deleting that page would have silently taken the skills\nwith it.\n\nEdit `tokens.json` or `src/components.css`, build, bump the version, publish:\n\n```bash\nnpm version minor && npm publish\n```\n\nValues change in consumers when they upgrade, never underneath them.\n\n`prepublishOnly` runs `scripts/verify-publish.mjs`: the pack must satisfy\nevery `exports`/`bin` entry, and removing a `tokens.json` key without a major\nbump is refused. Semver here: remove/rename a token or change a contract\n(the `/fonts/sora.woff2` URL, `data-theme` semantics) = major; additions =\nminor; value tweaks = patch.\n\n### Testing unpublished changes in a consumer\n\n```bash\nnpm pack                                        # here\nnpm i ../316-brand/316software-brand-<v>.tgz --no-save   # in the consumer\n```\n\n`--no-save` installs the packed bytes without touching `package.json` or the\nlockfile, so nothing local can leak into a commit; `npm ci` restores. Never\n`npm i ../316-brand` — the `file:` entry lands in the lockfile, CI has no\nsuch path, and the build dies with `MODULE_NOT_FOUND`. The consumers' verify\nstep fails on such entries for exactly this reason.\n\nAfter publishing, update the consumers (316software, html-uploader):\n`npm update @316software/brand` + commit the lockfile. Dependabot opens a\ngrouped PR in each if you forget.\n","readmeFilename":"README.md"}