add ui design ./ui/designs/ecomm-login-and-create-storefront-designs/
Claude Design export for SD-0001 (login + create-storefront surfaces): wf-*/hf-* screens, design-system bundle, offline preview. First artifact in the ui/designs/ collection (ecomm#8). Also ignore .DS_Store. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+378
@@ -0,0 +1,378 @@
|
||||
{
|
||||
"plugins": [
|
||||
"react",
|
||||
"import"
|
||||
],
|
||||
"rules": {
|
||||
"react/forbid-elements": [
|
||||
"warn",
|
||||
{
|
||||
"forbid": []
|
||||
}
|
||||
],
|
||||
"no-restricted-imports": [
|
||||
"warn",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"components/brand/**",
|
||||
"components/cards/**",
|
||||
"components/core/**",
|
||||
"components/navigation/**",
|
||||
"ui_kits/wiggleverse-www/**"
|
||||
],
|
||||
"message": "Import design-system components from 'index.js', not component internals."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-restricted-syntax": [
|
||||
"warn",
|
||||
{
|
||||
"selector": "Literal[value=/#[0-9a-fA-F]{3,8}\\b/]",
|
||||
"message": "Raw hex color — use a design-system color token via var()."
|
||||
},
|
||||
{
|
||||
"selector": "Literal[value=/\\b\\d+px\\b/]",
|
||||
"message": "Raw px value — use a design-system spacing token via var()."
|
||||
},
|
||||
{
|
||||
"selector": "Literal[value=/font-family\\s*:\\s*(?!['\\\"]?(?:Space Grotesk|Inter|Fraunces))/i]",
|
||||
"message": "Font not provided by the design system. Available: Space Grotesk, Inter, Fraunces."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='BrandLockup'] > JSXAttribute > JSXIdentifier[name!=/^(?:variant|size|href|showWordmark|assetBase|key|ref|className|style|children)$/]",
|
||||
"message": "<BrandLockup> doesn't accept that prop. Declared props: variant, size, href, showWordmark, assetBase."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='BrandLockup'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:primary|footer|onLight)$/]",
|
||||
"message": "<BrandLockup> variant must be one of 'primary' | 'footer' | 'onLight'."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='BuildCard'] > JSXAttribute > JSXIdentifier[name!=/^(?:tag|title|children|key|ref|className|style|children)$/]",
|
||||
"message": "<BuildCard> doesn't accept that prop. Declared props: tag, title, children."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|variant|href|onLight|disabled|type|onClick|key|ref|className|style|children)$/]",
|
||||
"message": "<Button> doesn't accept that prop. Declared props: children, variant, href, onLight, disabled, type, onClick."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:primary|ghost)$/]",
|
||||
"message": "<Button> variant must be one of 'primary' | 'ghost'."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute[name.name='type'] > Literal[value!=/^(?:button|submit|reset)$/]",
|
||||
"message": "<Button> type must be one of 'button' | 'submit' | 'reset'."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Callout'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onLight|key|ref|className|style|children)$/]",
|
||||
"message": "<Callout> doesn't accept that prop. Declared props: children, onLight."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Eyebrow'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onLight|as|key|ref|className|style|children)$/]",
|
||||
"message": "<Eyebrow> doesn't accept that prop. Declared props: children, onLight, as."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Notice'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|key|ref|className|style|children)$/]",
|
||||
"message": "<Notice> doesn't accept that prop. Declared props: children."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='PathCard'] > JSXAttribute > JSXIdentifier[name!=/^(?:icon|title|children|href|first|key|ref|className|style|children)$/]",
|
||||
"message": "<PathCard> doesn't accept that prop. Declared props: icon, title, children, href, first."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='FooterColumn'] > JSXAttribute > JSXIdentifier[name!=/^(?:heading|links|key|ref|className|style|children)$/]",
|
||||
"message": "<FooterColumn> doesn't accept that prop. Declared props: heading, links."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='NavLink'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|href|cta|key|ref|className|style|children)$/]",
|
||||
"message": "<NavLink> doesn't accept that prop. Declared props: label, href, cta."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Soul'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|size|tone|onLight|as|key|ref|className|style|children)$/]",
|
||||
"message": "<Soul> doesn't accept that prop. Declared props: children, size, tone, onLight, as."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Soul'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md|lg)$/]",
|
||||
"message": "<Soul> size must be one of 'sm' | 'md' | 'lg'."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Soul'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:gold|plain|lilac)$/]",
|
||||
"message": "<Soul> tone must be one of 'gold' | 'plain' | 'lilac'."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Tag'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|variant|onLight|key|ref|className|style|children)$/]",
|
||||
"message": "<Tag> doesn't accept that prop. Declared props: children, variant, onLight."
|
||||
},
|
||||
{
|
||||
"selector": "JSXOpeningElement[name.name='Tag'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:live|soon)$/]",
|
||||
"message": "<Tag> variant must be one of 'live' | 'soon'."
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/index.js"
|
||||
],
|
||||
"rules": {
|
||||
"no-restricted-imports": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"x-omelette": {
|
||||
"components": {
|
||||
"BrandLockup": {
|
||||
"replaces": []
|
||||
},
|
||||
"BuildCard": {
|
||||
"replaces": []
|
||||
},
|
||||
"Button": {
|
||||
"replaces": []
|
||||
},
|
||||
"Callout": {
|
||||
"replaces": []
|
||||
},
|
||||
"Eyebrow": {
|
||||
"replaces": []
|
||||
},
|
||||
"Notice": {
|
||||
"replaces": []
|
||||
},
|
||||
"PathCard": {
|
||||
"replaces": []
|
||||
},
|
||||
"FooterColumn": {
|
||||
"replaces": []
|
||||
},
|
||||
"NavLink": {
|
||||
"replaces": []
|
||||
},
|
||||
"Soul": {
|
||||
"replaces": []
|
||||
},
|
||||
"Tag": {
|
||||
"replaces": []
|
||||
}
|
||||
},
|
||||
"tokens": [
|
||||
"--accent",
|
||||
"--accent-on-light",
|
||||
"--border-card",
|
||||
"--border-card-w",
|
||||
"--border-hair",
|
||||
"--border-soft",
|
||||
"--border-strong",
|
||||
"--btn-border-w",
|
||||
"--cta",
|
||||
"--cta-hover",
|
||||
"--cta-text",
|
||||
"--dur-fast",
|
||||
"--dur-mid",
|
||||
"--ease",
|
||||
"--focus-ring",
|
||||
"--font-body",
|
||||
"--font-display",
|
||||
"--font-soul",
|
||||
"--glass-blur",
|
||||
"--glass-sky",
|
||||
"--leading-body",
|
||||
"--leading-tight",
|
||||
"--lift-1",
|
||||
"--lift-3",
|
||||
"--measure-lead",
|
||||
"--measure-prose",
|
||||
"--page-hero-pad",
|
||||
"--radius-card",
|
||||
"--radius-mark",
|
||||
"--radius-panel",
|
||||
"--radius-pill",
|
||||
"--radius-sm",
|
||||
"--section-pad",
|
||||
"--shadow-none",
|
||||
"--shadow-soft",
|
||||
"--space-0",
|
||||
"--space-1",
|
||||
"--space-10",
|
||||
"--space-12",
|
||||
"--space-2",
|
||||
"--space-3",
|
||||
"--space-4",
|
||||
"--space-5",
|
||||
"--space-6",
|
||||
"--space-8",
|
||||
"--surface-card-light",
|
||||
"--surface-footer",
|
||||
"--surface-paper",
|
||||
"--surface-raised",
|
||||
"--surface-raised-hi",
|
||||
"--surface-sky",
|
||||
"--text-body",
|
||||
"--text-eyebrow",
|
||||
"--text-fine",
|
||||
"--text-h1",
|
||||
"--text-h2",
|
||||
"--text-h3",
|
||||
"--text-lead",
|
||||
"--text-on-dark",
|
||||
"--text-on-dark-mute",
|
||||
"--text-on-dark-soft",
|
||||
"--text-on-light",
|
||||
"--text-on-light-soft",
|
||||
"--text-small",
|
||||
"--text-soul",
|
||||
"--text-tag",
|
||||
"--tracking-display",
|
||||
"--tracking-eyebrow",
|
||||
"--tracking-notice",
|
||||
"--tracking-tag",
|
||||
"--weight-bold",
|
||||
"--weight-medium",
|
||||
"--weight-regular",
|
||||
"--weight-semibold",
|
||||
"--weight-soul",
|
||||
"--wrap-gutter",
|
||||
"--wrap-max",
|
||||
"--wv-font-body",
|
||||
"--wv-font-display",
|
||||
"--wv-font-human",
|
||||
"--wv-gold",
|
||||
"--wv-gold-28",
|
||||
"--wv-gold-40",
|
||||
"--wv-gold-hi",
|
||||
"--wv-gold-ink",
|
||||
"--wv-gold-ink-soft",
|
||||
"--wv-indigo",
|
||||
"--wv-indigo-2",
|
||||
"--wv-ink",
|
||||
"--wv-lilac",
|
||||
"--wv-lilac-08",
|
||||
"--wv-lilac-12",
|
||||
"--wv-lilac-16",
|
||||
"--wv-lilac-18",
|
||||
"--wv-lilac-32",
|
||||
"--wv-midnight",
|
||||
"--wv-night",
|
||||
"--wv-paper",
|
||||
"--wv-starlight",
|
||||
"--wv-starlight-55",
|
||||
"--wv-starlight-60",
|
||||
"--wv-starlight-78",
|
||||
"--wv-starlight-85",
|
||||
"--wv-violet"
|
||||
],
|
||||
"tokenKinds": {
|
||||
"--wv-midnight": "color",
|
||||
"--wv-indigo": "color",
|
||||
"--wv-indigo-2": "color",
|
||||
"--wv-lilac": "color",
|
||||
"--wv-violet": "color",
|
||||
"--wv-gold": "color",
|
||||
"--wv-gold-hi": "color",
|
||||
"--wv-starlight": "color",
|
||||
"--wv-paper": "color",
|
||||
"--wv-ink": "color",
|
||||
"--wv-night": "color",
|
||||
"--wv-gold-ink": "color",
|
||||
"--wv-gold-ink-soft": "color",
|
||||
"--wv-lilac-08": "color",
|
||||
"--wv-lilac-12": "color",
|
||||
"--wv-lilac-16": "color",
|
||||
"--wv-lilac-18": "color",
|
||||
"--wv-lilac-32": "color",
|
||||
"--wv-gold-28": "color",
|
||||
"--wv-gold-40": "color",
|
||||
"--wv-starlight-85": "color",
|
||||
"--wv-starlight-78": "color",
|
||||
"--wv-starlight-60": "color",
|
||||
"--wv-starlight-55": "color",
|
||||
"--surface-sky": "color",
|
||||
"--surface-raised": "color",
|
||||
"--surface-raised-hi": "color",
|
||||
"--surface-paper": "color",
|
||||
"--surface-card-light": "color",
|
||||
"--surface-footer": "color",
|
||||
"--text-on-dark": "font",
|
||||
"--text-on-dark-soft": "font",
|
||||
"--text-on-dark-mute": "font",
|
||||
"--text-on-light": "font",
|
||||
"--text-on-light-soft": "font",
|
||||
"--accent": "color",
|
||||
"--accent-on-light": "color",
|
||||
"--cta": "color",
|
||||
"--cta-hover": "color",
|
||||
"--cta-text": "font",
|
||||
"--border-soft": "color",
|
||||
"--border-card": "color",
|
||||
"--border-strong": "color",
|
||||
"--focus-ring": "color",
|
||||
"--wv-font-display": "font",
|
||||
"--wv-font-body": "font",
|
||||
"--wv-font-human": "font",
|
||||
"--font-display": "font",
|
||||
"--font-body": "font",
|
||||
"--font-soul": "font",
|
||||
"--weight-regular": "font",
|
||||
"--weight-medium": "font",
|
||||
"--weight-semibold": "font",
|
||||
"--weight-bold": "font",
|
||||
"--weight-soul": "font",
|
||||
"--text-h1": "font",
|
||||
"--text-h2": "font",
|
||||
"--text-h3": "font",
|
||||
"--text-lead": "font",
|
||||
"--text-soul": "font",
|
||||
"--text-body": "font",
|
||||
"--text-small": "font",
|
||||
"--text-fine": "font",
|
||||
"--text-eyebrow": "font",
|
||||
"--text-tag": "font",
|
||||
"--leading-tight": "font",
|
||||
"--leading-body": "font",
|
||||
"--tracking-display": "font",
|
||||
"--tracking-eyebrow": "font",
|
||||
"--tracking-tag": "font",
|
||||
"--tracking-notice": "font",
|
||||
"--measure-lead": "spacing",
|
||||
"--measure-prose": "spacing",
|
||||
"--space-0": "spacing",
|
||||
"--space-1": "spacing",
|
||||
"--space-2": "spacing",
|
||||
"--space-3": "spacing",
|
||||
"--space-4": "spacing",
|
||||
"--space-5": "spacing",
|
||||
"--space-6": "spacing",
|
||||
"--space-8": "spacing",
|
||||
"--space-10": "spacing",
|
||||
"--space-12": "spacing",
|
||||
"--section-pad": "spacing",
|
||||
"--page-hero-pad": "spacing",
|
||||
"--wrap-max": "spacing",
|
||||
"--wrap-gutter": "spacing",
|
||||
"--radius-card": "radius",
|
||||
"--radius-panel": "radius",
|
||||
"--radius-sm": "radius",
|
||||
"--radius-pill": "radius",
|
||||
"--radius-mark": "radius",
|
||||
"--border-hair": "spacing",
|
||||
"--border-card-w": "spacing",
|
||||
"--btn-border-w": "spacing",
|
||||
"--shadow-none": "shadow",
|
||||
"--shadow-soft": "shadow",
|
||||
"--lift-1": "other",
|
||||
"--lift-3": "other",
|
||||
"--glass-sky": "color",
|
||||
"--glass-blur": "spacing",
|
||||
"--ease": "other",
|
||||
"--dur-fast": "other",
|
||||
"--dur-mid": "other"
|
||||
},
|
||||
"fontFamilies": [
|
||||
"Fraunces",
|
||||
"Inter",
|
||||
"Space Grotesk"
|
||||
]
|
||||
}
|
||||
}
|
||||
+959
@@ -0,0 +1,959 @@
|
||||
/* @ds-bundle: {"format":3,"namespace":"WiggleverseDesignSystem_94cd80","components":[{"name":"BrandLockup","sourcePath":"components/brand/BrandLockup.jsx"},{"name":"BuildCard","sourcePath":"components/cards/BuildCard.jsx"},{"name":"PathCard","sourcePath":"components/cards/PathCard.jsx"},{"name":"Button","sourcePath":"components/core/Button.jsx"},{"name":"Callout","sourcePath":"components/core/Callout.jsx"},{"name":"Eyebrow","sourcePath":"components/core/Eyebrow.jsx"},{"name":"Notice","sourcePath":"components/core/Notice.jsx"},{"name":"Soul","sourcePath":"components/core/Soul.jsx"},{"name":"Tag","sourcePath":"components/core/Tag.jsx"},{"name":"SiteFooter","sourcePath":"components/navigation/SiteFooter.jsx"},{"name":"SiteHeader","sourcePath":"components/navigation/SiteHeader.jsx"}],"sourceHashes":{"components/brand/BrandLockup.jsx":"70ef76a92b84","components/cards/BuildCard.jsx":"f4588d77bd79","components/cards/PathCard.jsx":"f8779016b751","components/core/Button.jsx":"58601f356762","components/core/Callout.jsx":"4347df19558c","components/core/Eyebrow.jsx":"38c0374f060f","components/core/Notice.jsx":"471101cf1c07","components/core/Soul.jsx":"d1b2ddeea071","components/core/Tag.jsx":"192ca2a7e57d","components/navigation/SiteFooter.jsx":"61fbdd9cf145","components/navigation/SiteHeader.jsx":"6541bfe8e43a","ui_kits/wiggleverse-www/app.jsx":"f0cea1954d57"},"inlinedExternals":[],"unexposedExports":[]} */
|
||||
|
||||
(() => {
|
||||
|
||||
const __ds_ns = (window.WiggleverseDesignSystem_94cd80 = window.WiggleverseDesignSystem_94cd80 || {});
|
||||
|
||||
const __ds_scope = {};
|
||||
|
||||
(__ds_ns.__errors = __ds_ns.__errors || []);
|
||||
|
||||
// components/brand/BrandLockup.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse BrandLockup — the mark + "Wiggleverse" wordmark, linked home.
|
||||
* 'primary' uses the gradient mark on dark; 'footer' uses the mono-gold mark;
|
||||
* 'onLight' uses the ink mark for paper. Wordmark is Space Grotesk 700, never italic.
|
||||
*/
|
||||
function BrandLockup({
|
||||
variant = 'primary',
|
||||
size = 34,
|
||||
href = '/',
|
||||
showWordmark = true,
|
||||
assetBase = '/assets',
|
||||
...rest
|
||||
}) {
|
||||
const marks = {
|
||||
primary: 'wiggleverse-mark.svg',
|
||||
footer: 'mark-mono-gold.svg',
|
||||
onLight: 'mark-on-light.svg'
|
||||
};
|
||||
const wordColor = variant === 'onLight' ? 'var(--wv-ink)' : 'var(--wv-starlight)';
|
||||
// Resolve asset relative to the given base so the lockup works from any depth.
|
||||
const src = `${assetBase}/${marks[variant] || marks.primary}`;
|
||||
return /*#__PURE__*/React.createElement("a", _extends({
|
||||
href: href,
|
||||
"aria-label": "Wiggleverse home",
|
||||
style: {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '.55rem',
|
||||
textDecoration: 'none'
|
||||
}
|
||||
}, rest), /*#__PURE__*/React.createElement("img", {
|
||||
src: src,
|
||||
alt: "",
|
||||
width: size,
|
||||
height: size,
|
||||
style: {
|
||||
width: size,
|
||||
height: size
|
||||
}
|
||||
}), showWordmark && /*#__PURE__*/React.createElement("span", {
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontWeight: 'var(--weight-bold)',
|
||||
fontSize: `${Math.round(size * 0.0338 * 10) / 10}rem`,
|
||||
letterSpacing: 'var(--tracking-display)',
|
||||
color: wordColor
|
||||
}
|
||||
}, "Wiggleverse"));
|
||||
}
|
||||
Object.assign(__ds_scope, { BrandLockup });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/brand/BrandLockup.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/cards/BuildCard.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse BuildCard — a portfolio item on a paper section. White card with
|
||||
* a violet hairline, a status Tag, title, and copy. Built for light backgrounds.
|
||||
*/
|
||||
function BuildCard({
|
||||
tag,
|
||||
title,
|
||||
children,
|
||||
...rest
|
||||
}) {
|
||||
return /*#__PURE__*/React.createElement("div", _extends({
|
||||
style: {
|
||||
padding: '1.4rem',
|
||||
borderRadius: 'var(--radius-card)',
|
||||
border: '1px solid rgba(124,111,224,.3)',
|
||||
background: 'var(--surface-card-light)'
|
||||
}
|
||||
}, rest), tag && /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
marginBottom: '.6rem'
|
||||
}
|
||||
}, tag), /*#__PURE__*/React.createElement("h3", {
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontWeight: 'var(--weight-bold)',
|
||||
fontSize: 'var(--text-h3)',
|
||||
margin: '0 0 .35rem',
|
||||
color: 'var(--wv-ink)',
|
||||
letterSpacing: 'var(--tracking-display)'
|
||||
}
|
||||
}, title), /*#__PURE__*/React.createElement("p", {
|
||||
style: {
|
||||
margin: 0,
|
||||
fontSize: 'var(--text-small)',
|
||||
lineHeight: 1.55,
|
||||
color: 'var(--text-on-light-soft)'
|
||||
}
|
||||
}, children));
|
||||
}
|
||||
Object.assign(__ds_scope, { BuildCard });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/cards/BuildCard.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/cards/PathCard.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse PathCard — the audience-router doorway. A raised indigo card with
|
||||
* a glyph icon, title, and one line of copy. Hover lifts -3px and the border
|
||||
* warms to lilac. 'first' gives it a gold border (the recommended door).
|
||||
*/
|
||||
function PathCard({
|
||||
icon,
|
||||
title,
|
||||
children,
|
||||
href = '#',
|
||||
first = false,
|
||||
...rest
|
||||
}) {
|
||||
const [hover, setHover] = React.useState(false);
|
||||
return /*#__PURE__*/React.createElement("a", _extends({
|
||||
href: href,
|
||||
onMouseEnter: () => setHover(true),
|
||||
onMouseLeave: () => setHover(false),
|
||||
style: {
|
||||
display: 'block',
|
||||
padding: '1.2rem',
|
||||
borderRadius: 'var(--radius-card)',
|
||||
background: hover ? 'var(--surface-raised-hi)' : 'var(--surface-raised)',
|
||||
border: `1px solid ${first ? 'var(--wv-gold)' : hover ? 'var(--wv-lilac)' : 'var(--border-card)'}`,
|
||||
color: 'var(--wv-starlight)',
|
||||
textDecoration: 'none',
|
||||
transform: hover ? 'var(--lift-3)' : 'none',
|
||||
transition: 'transform var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease)'
|
||||
}
|
||||
}, rest), icon && /*#__PURE__*/React.createElement("div", {
|
||||
"aria-hidden": "true",
|
||||
style: {
|
||||
fontSize: '1.5rem'
|
||||
}
|
||||
}, icon), /*#__PURE__*/React.createElement("h3", {
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontWeight: 'var(--weight-bold)',
|
||||
fontSize: 'var(--text-h3)',
|
||||
margin: '.5rem 0 .25rem',
|
||||
color: 'var(--wv-starlight)',
|
||||
letterSpacing: 'var(--tracking-display)'
|
||||
}
|
||||
}, title), /*#__PURE__*/React.createElement("p", {
|
||||
style: {
|
||||
margin: 0,
|
||||
fontSize: 'var(--text-fine)',
|
||||
lineHeight: 1.5,
|
||||
color: 'var(--wv-starlight-78)'
|
||||
}
|
||||
}, children));
|
||||
}
|
||||
Object.assign(__ds_scope, { PathCard });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/cards/PathCard.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/core/Button.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse Button — pill action in the machine register (Space Grotesk 500).
|
||||
* Primary = gold horizon CTA; ghost = lilac-outlined. Hover lifts -1px (never a shadow).
|
||||
*/
|
||||
function Button({
|
||||
children,
|
||||
variant = 'primary',
|
||||
href,
|
||||
onLight = false,
|
||||
disabled = false,
|
||||
type = 'button',
|
||||
onClick,
|
||||
...rest
|
||||
}) {
|
||||
const base = {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '.4em',
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontWeight: 'var(--weight-medium)',
|
||||
fontSize: 'var(--text-body)',
|
||||
lineHeight: 1,
|
||||
padding: '.7rem 1.25rem',
|
||||
borderRadius: 'var(--radius-pill)',
|
||||
border: 'var(--btn-border-w) solid transparent',
|
||||
cursor: disabled ? 'not-allowed' : 'pointer',
|
||||
textDecoration: 'none',
|
||||
opacity: disabled ? 0.5 : 1,
|
||||
transition: 'transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease)'
|
||||
};
|
||||
const variants = {
|
||||
primary: {
|
||||
background: 'var(--cta)',
|
||||
color: 'var(--cta-text)'
|
||||
},
|
||||
ghost: {
|
||||
background: 'transparent',
|
||||
borderColor: onLight ? 'var(--wv-violet)' : 'var(--wv-lilac)',
|
||||
color: onLight ? 'var(--wv-ink)' : 'var(--wv-starlight)'
|
||||
}
|
||||
};
|
||||
const style = {
|
||||
...base,
|
||||
...(variants[variant] || variants.primary)
|
||||
};
|
||||
const handleEnter = e => {
|
||||
if (!disabled) e.currentTarget.style.transform = 'var(--lift-1)';
|
||||
};
|
||||
const handleLeave = e => {
|
||||
e.currentTarget.style.transform = 'none';
|
||||
};
|
||||
const common = {
|
||||
style,
|
||||
onMouseEnter: handleEnter,
|
||||
onMouseLeave: handleLeave,
|
||||
...rest
|
||||
};
|
||||
if (href && !disabled) {
|
||||
return /*#__PURE__*/React.createElement("a", _extends({
|
||||
href: href,
|
||||
onClick: onClick
|
||||
}, common), children);
|
||||
}
|
||||
return /*#__PURE__*/React.createElement("button", _extends({
|
||||
type: type,
|
||||
disabled: disabled,
|
||||
onClick: onClick
|
||||
}, common), children);
|
||||
}
|
||||
Object.assign(__ds_scope, { Button });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/core/Button.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/core/Eyebrow.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse Eyebrow — uppercase, letter-spaced kicker in the machine register
|
||||
* that sits above a section heading. Lilac on dark, violet on paper.
|
||||
*/
|
||||
function Eyebrow({
|
||||
children,
|
||||
onLight = false,
|
||||
as = 'p',
|
||||
...rest
|
||||
}) {
|
||||
const Tag = as;
|
||||
return /*#__PURE__*/React.createElement(Tag, _extends({
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontWeight: 'var(--weight-medium)',
|
||||
fontSize: 'var(--text-eyebrow)',
|
||||
letterSpacing: 'var(--tracking-eyebrow)',
|
||||
textTransform: 'uppercase',
|
||||
color: onLight ? 'var(--wv-violet)' : 'var(--wv-lilac)',
|
||||
margin: '0 0 1rem'
|
||||
}
|
||||
}, rest), children);
|
||||
}
|
||||
Object.assign(__ds_scope, { Eyebrow });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/core/Eyebrow.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/core/Notice.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse Notice — a hollow gold pill set inline beside a heading to mark
|
||||
* roadmap status ("In build", "Coming"). Quieter than a filled Tag.
|
||||
*/
|
||||
function Notice({
|
||||
children,
|
||||
...rest
|
||||
}) {
|
||||
return /*#__PURE__*/React.createElement("span", _extends({
|
||||
style: {
|
||||
display: 'inline-block',
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontSize: '.82rem',
|
||||
fontWeight: 'var(--weight-medium)',
|
||||
letterSpacing: 'var(--tracking-notice)',
|
||||
textTransform: 'uppercase',
|
||||
color: 'var(--wv-gold)',
|
||||
border: '1px solid var(--wv-gold-40)',
|
||||
borderRadius: 'var(--radius-pill)',
|
||||
padding: '.25rem .8rem',
|
||||
verticalAlign: 'middle'
|
||||
}
|
||||
}, rest), children);
|
||||
}
|
||||
Object.assign(__ds_scope, { Notice });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/core/Notice.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/core/Soul.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse Soul — the human register. Fraunces ITALIC ONLY, used sparingly
|
||||
* for the lines that carry conscience (taglines, pull-quotes). Gold by default
|
||||
* (hero/page-hero) or starlight/ink when 'plain'.
|
||||
*/
|
||||
function Soul({
|
||||
children,
|
||||
size = 'md',
|
||||
tone = 'gold',
|
||||
onLight = false,
|
||||
as = 'span',
|
||||
...rest
|
||||
}) {
|
||||
const Tag = as;
|
||||
const sizes = {
|
||||
sm: '1.1rem',
|
||||
md: 'var(--text-soul)',
|
||||
/* clamp(1.2rem, 2.4vw, 1.7rem) */
|
||||
lg: 'clamp(1.4rem, 3vw, 2rem)'
|
||||
};
|
||||
const tones = {
|
||||
gold: 'var(--wv-gold)',
|
||||
plain: onLight ? 'var(--wv-ink)' : 'var(--wv-starlight)',
|
||||
lilac: 'var(--wv-lilac)'
|
||||
};
|
||||
return /*#__PURE__*/React.createElement(Tag, _extends({
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-human)',
|
||||
fontStyle: 'italic',
|
||||
fontWeight: 'var(--weight-soul)',
|
||||
fontSize: sizes[size] || sizes.md,
|
||||
lineHeight: 1.3,
|
||||
color: tones[tone] || tones.gold
|
||||
}
|
||||
}, rest), children);
|
||||
}
|
||||
Object.assign(__ds_scope, { Soul });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/core/Soul.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/core/Callout.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse Callout — a gold left-rule framing a single conscience line.
|
||||
* No box, no fill: just a 3px gold border and a Fraunces italic quote.
|
||||
*/
|
||||
function Callout({
|
||||
children,
|
||||
onLight = false,
|
||||
...rest
|
||||
}) {
|
||||
return /*#__PURE__*/React.createElement("div", _extends({
|
||||
style: {
|
||||
borderLeft: '3px solid var(--wv-gold)',
|
||||
padding: '.4rem 0 .4rem 1.1rem',
|
||||
margin: '1.5rem 0'
|
||||
}
|
||||
}, rest), /*#__PURE__*/React.createElement(__ds_scope.Soul, {
|
||||
size: "lg",
|
||||
tone: "plain",
|
||||
onLight: onLight,
|
||||
as: "p",
|
||||
style: {
|
||||
margin: 0
|
||||
}
|
||||
}, children));
|
||||
}
|
||||
Object.assign(__ds_scope, { Callout });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/core/Callout.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/core/Tag.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
/**
|
||||
* Wiggleverse Tag — small filled pill marking a product's status on cards.
|
||||
* 'live' = lilac tint (first product); 'soon' = gold tint (coming).
|
||||
*/
|
||||
function Tag({
|
||||
children,
|
||||
variant = 'live',
|
||||
onLight = false,
|
||||
...rest
|
||||
}) {
|
||||
const base = {
|
||||
display: 'inline-block',
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontSize: 'var(--text-tag)',
|
||||
fontWeight: 'var(--weight-medium)',
|
||||
letterSpacing: 'var(--tracking-tag)',
|
||||
textTransform: 'uppercase',
|
||||
padding: '.15rem .55rem',
|
||||
borderRadius: 'var(--radius-pill)'
|
||||
};
|
||||
const variants = {
|
||||
live: {
|
||||
background: 'var(--wv-lilac-16)',
|
||||
color: onLight ? 'var(--wv-ink)' : 'var(--wv-starlight)'
|
||||
},
|
||||
soon: {
|
||||
background: 'var(--wv-gold-28)',
|
||||
color: 'var(--wv-gold-ink-soft)'
|
||||
}
|
||||
};
|
||||
return /*#__PURE__*/React.createElement("span", _extends({
|
||||
style: {
|
||||
...base,
|
||||
...(variants[variant] || variants.live)
|
||||
}
|
||||
}, rest), children);
|
||||
}
|
||||
Object.assign(__ds_scope, { Tag });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/core/Tag.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/navigation/SiteFooter.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
const DEFAULT_COLUMNS = [{
|
||||
heading: 'Explore',
|
||||
links: [{
|
||||
label: 'Build',
|
||||
href: '/building/'
|
||||
}, {
|
||||
label: 'Partner',
|
||||
href: '/partner/'
|
||||
}, {
|
||||
label: 'Learn',
|
||||
href: '/learn/'
|
||||
}]
|
||||
}, {
|
||||
heading: 'The org',
|
||||
links: [{
|
||||
label: 'About',
|
||||
href: '/about/'
|
||||
}, {
|
||||
label: 'Give',
|
||||
href: '/give/'
|
||||
}, {
|
||||
label: 'Finances',
|
||||
href: '/finances/'
|
||||
}, {
|
||||
label: 'Code of Conduct',
|
||||
href: '/code-of-conduct/'
|
||||
}]
|
||||
}];
|
||||
const DEFAULT_LEGAL = "Wiggleverse.org, Inc. — a Washington 501(c)(3) nonprofit creating art and software that supports humanity on the path to world peace. Dedicated to Aaron Swartz, who believed knowledge belongs to everyone.";
|
||||
|
||||
/**
|
||||
* Wiggleverse SiteFooter — deepest ground (night). Mono-gold lockup, a lilac
|
||||
* Soul tagline, link columns, and the dedication legal line.
|
||||
*/
|
||||
function SiteFooter({
|
||||
columns = DEFAULT_COLUMNS,
|
||||
tagline = 'We are verbs, not nouns.',
|
||||
legal = DEFAULT_LEGAL,
|
||||
assetBase = '/assets',
|
||||
...rest
|
||||
}) {
|
||||
const wrap = {
|
||||
width: 'min(var(--wrap-max), 92vw)',
|
||||
margin: '0 auto'
|
||||
};
|
||||
return /*#__PURE__*/React.createElement("footer", _extends({
|
||||
style: {
|
||||
background: 'var(--surface-footer)',
|
||||
borderTop: '1px solid var(--border-soft)',
|
||||
padding: '3rem 0 2.5rem',
|
||||
fontSize: '.92rem'
|
||||
}
|
||||
}, rest), /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
...wrap,
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '2rem 3rem',
|
||||
justifyContent: 'space-between'
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
maxWidth: '22rem'
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(__ds_scope.BrandLockup, {
|
||||
variant: "footer",
|
||||
size: 30,
|
||||
assetBase: assetBase
|
||||
}), /*#__PURE__*/React.createElement(__ds_scope.Soul, {
|
||||
size: "sm",
|
||||
tone: "lilac",
|
||||
as: "span",
|
||||
style: {
|
||||
display: 'block',
|
||||
marginTop: '.6rem'
|
||||
}
|
||||
}, tagline)), columns.map(col => /*#__PURE__*/React.createElement("div", {
|
||||
key: col.heading
|
||||
}, /*#__PURE__*/React.createElement("h4", {
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontSize: '.8rem',
|
||||
letterSpacing: '.1em',
|
||||
textTransform: 'uppercase',
|
||||
color: 'var(--wv-lilac)',
|
||||
margin: '0 0 .7rem'
|
||||
}
|
||||
}, col.heading), /*#__PURE__*/React.createElement("ul", {
|
||||
style: {
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0
|
||||
}
|
||||
}, col.links.map(l => /*#__PURE__*/React.createElement("li", {
|
||||
key: l.href,
|
||||
style: {
|
||||
marginBottom: '.45rem'
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement("a", {
|
||||
href: l.href,
|
||||
style: {
|
||||
color: 'var(--wv-starlight-85)',
|
||||
textDecoration: 'none'
|
||||
}
|
||||
}, l.label))))))), /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
...wrap,
|
||||
marginTop: '2.2rem',
|
||||
paddingTop: '1.3rem',
|
||||
borderTop: '1px solid var(--wv-lilac-12)',
|
||||
color: 'var(--wv-starlight-60)',
|
||||
fontSize: '.85rem'
|
||||
}
|
||||
}, legal));
|
||||
}
|
||||
Object.assign(__ds_scope, { SiteFooter });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/navigation/SiteFooter.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// components/navigation/SiteHeader.jsx
|
||||
try { (() => {
|
||||
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
||||
const DEFAULT_LINKS = [{
|
||||
label: 'About',
|
||||
href: '/about/'
|
||||
}, {
|
||||
label: 'Build',
|
||||
href: '/building/'
|
||||
}, {
|
||||
label: 'Partner',
|
||||
href: '/partner/'
|
||||
}, {
|
||||
label: 'Learn',
|
||||
href: '/learn/'
|
||||
}, {
|
||||
label: 'Give',
|
||||
href: '/give/'
|
||||
}];
|
||||
|
||||
/**
|
||||
* Wiggleverse SiteHeader — sticky glass nav: brand lockup + machine-register
|
||||
* links. Translucent midnight with a blur and a lilac hairline underneath.
|
||||
*/
|
||||
function SiteHeader({
|
||||
links = DEFAULT_LINKS,
|
||||
current,
|
||||
assetBase = '/assets',
|
||||
homeHref = '/',
|
||||
...rest
|
||||
}) {
|
||||
return /*#__PURE__*/React.createElement("header", _extends({
|
||||
style: {
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: 50,
|
||||
background: 'var(--glass-sky)',
|
||||
backdropFilter: 'blur(var(--glass-blur))',
|
||||
WebkitBackdropFilter: 'blur(var(--glass-blur))',
|
||||
borderBottom: '1px solid var(--border-soft)'
|
||||
}
|
||||
}, rest), /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
width: 'min(var(--wrap-max), 92vw)',
|
||||
margin: '0 auto',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: '1rem',
|
||||
padding: '.7rem 0'
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(__ds_scope.BrandLockup, {
|
||||
variant: "primary",
|
||||
assetBase: assetBase,
|
||||
href: homeHref
|
||||
}), /*#__PURE__*/React.createElement("nav", null, /*#__PURE__*/React.createElement("ul", {
|
||||
style: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '1.2rem',
|
||||
listStyle: 'none',
|
||||
margin: 0,
|
||||
padding: 0
|
||||
}
|
||||
}, links.map(l => {
|
||||
const isCurrent = current === l.href || current === l.label;
|
||||
return /*#__PURE__*/React.createElement("li", {
|
||||
key: l.href
|
||||
}, /*#__PURE__*/React.createElement("a", {
|
||||
href: l.href,
|
||||
"aria-current": isCurrent ? 'page' : undefined,
|
||||
style: {
|
||||
fontFamily: 'var(--wv-font-display)',
|
||||
fontWeight: 'var(--weight-medium)',
|
||||
fontSize: '.95rem',
|
||||
color: l.cta ? 'var(--wv-gold)' : 'var(--wv-starlight)',
|
||||
textDecoration: isCurrent ? 'underline' : 'none',
|
||||
textUnderlineOffset: '4px',
|
||||
textDecorationColor: 'var(--wv-lilac)'
|
||||
}
|
||||
}, l.label));
|
||||
})))));
|
||||
}
|
||||
Object.assign(__ds_scope, { SiteHeader });
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "components/navigation/SiteHeader.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
// ui_kits/wiggleverse-www/app.jsx
|
||||
try { (() => {
|
||||
/* Wiggleverse marketing-site recreation. Composes the DS components and routes
|
||||
between screens by intercepting in-app anchor clicks. */
|
||||
const {
|
||||
Button,
|
||||
Tag,
|
||||
Notice,
|
||||
Eyebrow,
|
||||
Soul,
|
||||
Callout,
|
||||
PathCard,
|
||||
BuildCard,
|
||||
SiteHeader,
|
||||
SiteFooter
|
||||
} = window.WiggleverseDesignSystem_94cd80;
|
||||
const ASSET_BASE = '../../assets';
|
||||
const NAV = [{
|
||||
label: 'About',
|
||||
href: '#/about'
|
||||
}, {
|
||||
label: 'Build',
|
||||
href: '#/ecomm'
|
||||
}, {
|
||||
label: 'Partner',
|
||||
href: '#/about'
|
||||
}, {
|
||||
label: 'Learn',
|
||||
href: '#/finances'
|
||||
}, {
|
||||
label: 'Give',
|
||||
href: '#/finances',
|
||||
cta: true
|
||||
}];
|
||||
const FOOTER_COLS = [{
|
||||
heading: 'Explore',
|
||||
links: [{
|
||||
label: 'Build',
|
||||
href: '#/ecomm'
|
||||
}, {
|
||||
label: 'Partner',
|
||||
href: '#/about'
|
||||
}, {
|
||||
label: 'Learn',
|
||||
href: '#/finances'
|
||||
}]
|
||||
}, {
|
||||
heading: 'The org',
|
||||
links: [{
|
||||
label: 'About',
|
||||
href: '#/about'
|
||||
}, {
|
||||
label: 'Give',
|
||||
href: '#/finances'
|
||||
}, {
|
||||
label: 'Finances',
|
||||
href: '#/finances'
|
||||
}, {
|
||||
label: 'Code of Conduct',
|
||||
href: '#/about'
|
||||
}]
|
||||
}];
|
||||
|
||||
/* ---------- Home ---------- */
|
||||
function HomeScreen() {
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("section", {
|
||||
className: "hero"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "hero__sky",
|
||||
"aria-hidden": "true"
|
||||
}, /*#__PURE__*/React.createElement("img", {
|
||||
className: "hero__mark",
|
||||
src: ASSET_BASE + '/wiggleverse-mark.svg',
|
||||
alt: ""
|
||||
})), /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "hero__inner"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "A 501(c)(3) nonprofit \xB7 art & software for a world at peace"), /*#__PURE__*/React.createElement("h1", null, "Ethical alternatives to the software that connects you to other humans."), /*#__PURE__*/React.createElement(Soul, {
|
||||
size: "md",
|
||||
as: "span",
|
||||
className: "hero__soul"
|
||||
}, "Treat humans as humans \u2014 everything else follows."), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "A wise world where people and machines build together on one shared set of ethics. Low-cost commerce for small businesses. Tools for moving toward agreement on shared meaning. A place where, if you're learning, you're succeeding."), /*#__PURE__*/React.createElement("div", {
|
||||
className: "hero__cta"
|
||||
}, /*#__PURE__*/React.createElement(Button, {
|
||||
variant: "primary",
|
||||
href: "#/about"
|
||||
}, "Why Wiggleverse \u2192"), /*#__PURE__*/React.createElement(Button, {
|
||||
variant: "ghost",
|
||||
href: "#/ecomm"
|
||||
}, "See what we're building"))))), /*#__PURE__*/React.createElement("section", {
|
||||
className: "section"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "Find your way in"), /*#__PURE__*/React.createElement("h2", null, "I'm here as a\u2026"), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "Wiggleverse is an umbrella. Pick the door that fits \u2014 each leads to its own part of the world."), /*#__PURE__*/React.createElement("div", {
|
||||
className: "router__grid"
|
||||
}, /*#__PURE__*/React.createElement(PathCard, {
|
||||
icon: "\u2727",
|
||||
title: "Curious human",
|
||||
href: "#/about",
|
||||
first: true
|
||||
}, "What is this, and why does it matter? Start with the story."), /*#__PURE__*/React.createElement(PathCard, {
|
||||
icon: "\u25C7",
|
||||
title: "Small business",
|
||||
href: "#/ecomm"
|
||||
}, "People and families who join, sell, and contribute. Near-zero-cost commerce."), /*#__PURE__*/React.createElement(PathCard, {
|
||||
icon: "\u25C8",
|
||||
title: "Builder",
|
||||
href: "#/about"
|
||||
}, "A developer who wants to build ethical software? We'd love your help."), /*#__PURE__*/React.createElement(PathCard, {
|
||||
icon: "\u274D",
|
||||
title: "Funder",
|
||||
href: "#/finances"
|
||||
}, "Donors, foundations, and grantmakers supporting a 501(c)(3) at work.")))), /*#__PURE__*/React.createElement("section", {
|
||||
className: "section section--paper"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, {
|
||||
onLight: true
|
||||
}, "One set of principles, many alternatives"), /*#__PURE__*/React.createElement("h2", null, "What we're building"), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "Ethical alternatives to the platforms people rely on every day \u2014 every one built on the same shared set of principles."), /*#__PURE__*/React.createElement("div", {
|
||||
className: "build__grid"
|
||||
}, /*#__PURE__*/React.createElement(BuildCard, {
|
||||
tag: /*#__PURE__*/React.createElement(Tag, {
|
||||
variant: "live",
|
||||
onLight: true
|
||||
}, "First product"),
|
||||
title: "Ecomm"
|
||||
}, "Shopify-class commerce at near-zero cost, for people and families \u2014 because small businesses are really just people. ", /*#__PURE__*/React.createElement("a", {
|
||||
href: "#/ecomm"
|
||||
}, "Why ecomm first \u2192")), /*#__PURE__*/React.createElement(BuildCard, {
|
||||
tag: /*#__PURE__*/React.createElement(Tag, {
|
||||
variant: "soon"
|
||||
}, "Coming"),
|
||||
title: "Apps"
|
||||
}, "A branded mobile app of their own for every small business \u2014 so they meet their people directly, instead of renting space inside someone else's platform."), /*#__PURE__*/React.createElement(BuildCard, {
|
||||
tag: /*#__PURE__*/React.createElement(Tag, {
|
||||
variant: "soon"
|
||||
}, "Coming"),
|
||||
title: "Learn"
|
||||
}, "A place where anyone \u2014 including small businesses who share our ethics \u2014 can post educational content that's true, right-sized, and actually teaches.")))), /*#__PURE__*/React.createElement("section", {
|
||||
className: "section"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "Open Core \xB7 a partner ecosystem"), /*#__PURE__*/React.createElement("h2", null, "Built on an open core"), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "The platform's core is open \u2014 anyone can inspect it, extend it, and build on it. Because no two businesses run the same way, we don't sell one-size-fits-all \u2014 we grow a partner ecosystem that builds software shaped to the work it's actually for."), /*#__PURE__*/React.createElement("div", {
|
||||
className: "router__grid"
|
||||
}, /*#__PURE__*/React.createElement(PathCard, {
|
||||
icon: "\u25D0",
|
||||
title: "Partner",
|
||||
href: "#/about",
|
||||
first: true
|
||||
}, "Build custom software on an open platform \u2014 value flowing to the builders and the served, never extracted by a platform in the middle. Why custom-on-open is the future \u2192")))));
|
||||
}
|
||||
|
||||
/* ---------- About ---------- */
|
||||
function AboutScreen() {
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("section", {
|
||||
className: "page-hero"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "About"), /*#__PURE__*/React.createElement("h1", null, "The era of infinite alternatives"), /*#__PURE__*/React.createElement(Soul, {
|
||||
size: "md",
|
||||
as: "p",
|
||||
className: "page-hero__soul"
|
||||
}, "Welcome to the Wiggleverse."), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "We've entered an era of alternatives \u2014 infinite alternatives. Wiggleverse exists to build the humane ones: ethical alternatives to the platforms people use every day, kept low-cost and high-value, in service of human flourishing."))), /*#__PURE__*/React.createElement("section", {
|
||||
className: "section"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap prose"
|
||||
}, /*#__PURE__*/React.createElement("h2", null, "Now it's the platforms"), /*#__PURE__*/React.createElement("p", null, "With large language models, we've entered the era where the platforms themselves are being commoditized \u2014 and with them comes a world of infinite alternatives for software. One genuinely skilled developer can now do what would have taken ten of them a year ago. The things everyone assumed were permanent fixtures are suddenly open to alternatives."), /*#__PURE__*/React.createElement("h2", null, "The moats are becoming anchors"), /*#__PURE__*/React.createElement("p", null, "The large platforms have thrived on three moats: the manpower and capital to run software at scale, vendor lock-in, and the network effect. My hypothesis is that the first is turning into an anchor, the second is dissolving as custom migration code gets cheap, and the third is already fragmented."), /*#__PURE__*/React.createElement("h2", null, "What Wiggleverse is for"), /*#__PURE__*/React.createElement("p", null, "None of this is about taking anyone's place. Wiggleverse exists to offer ethical alternatives to platforms like Shopify, YouTube, Facebook, and Instagram \u2014 rooted in ethics, built to give people value rather than to extract it."), /*#__PURE__*/React.createElement(Callout, null, "The intention isn't to take as much as we can from people \u2014 it's to give as much value as we can to everyone."), /*#__PURE__*/React.createElement("p", null, "Welcome to the Wiggleverse, and welcome to the era of infinite alternatives \u2014 even to the platforms everyone assumed were permanent."), /*#__PURE__*/React.createElement(Soul, {
|
||||
size: "sm",
|
||||
tone: "plain",
|
||||
as: "p",
|
||||
style: {
|
||||
marginTop: '1.5rem'
|
||||
}
|
||||
}, "\u2014 Ben Stull, Founder"))));
|
||||
}
|
||||
|
||||
/* ---------- Ecomm ---------- */
|
||||
function EcommScreen() {
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("section", {
|
||||
className: "page-hero"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "The portfolio \xB7 first product"), /*#__PURE__*/React.createElement("h1", null, "Ecomm"), /*#__PURE__*/React.createElement(Soul, {
|
||||
size: "md",
|
||||
as: "p",
|
||||
className: "page-hero__soul"
|
||||
}, "We take only what it takes to run."), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "Shopify-class commerce at near-zero cost, for people and families \u2014 because small businesses are really just people. It's the first product to move from principle into the world, and there's a reason it's first."))), /*#__PURE__*/React.createElement("section", {
|
||||
className: "section"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap prose"
|
||||
}, /*#__PURE__*/React.createElement("h2", null, "Why commerce first"), /*#__PURE__*/React.createElement("p", null, "Running an organization \u2014 and the infrastructure under a platform \u2014 takes money. Commerce is where money moves most, so by building close to commerce we reach a sustainable position quickest. Ecomm is first because it's the fastest honest path to standing on our own feet."), /*#__PURE__*/React.createElement(Callout, null, "Enough to keep the lights on, and no more."), /*#__PURE__*/React.createElement("h2", null, "What we commit to"), /*#__PURE__*/React.createElement("p", null, "The mission for Ecomm is to keep transaction fees and retail-media fees as low as they can possibly go. While we're still in beta, here is what we're committing to:"), /*#__PURE__*/React.createElement("ul", null, /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("b", null, "Retail media, free."), " Earned through platform engagement rather than paid for."), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("b", null, "Marketplace storefronts: low or no transaction fees."), " Selling in the shared marketplace costs little or nothing."), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("b", null, "White-label storefronts: low transaction fees."), " Your own branded storefront stays low-cost to run.")), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(Button, {
|
||||
variant: "ghost",
|
||||
href: "#/finances"
|
||||
}, "See the open book \u2192")))));
|
||||
}
|
||||
|
||||
/* ---------- Finances (open book) ---------- */
|
||||
function FinancesScreen() {
|
||||
const lines = [{
|
||||
item: 'Google Cloud (GCP)',
|
||||
for: 'Servers, databases, and the infrastructure the platform runs on — on startup credits today',
|
||||
current: 32,
|
||||
ant: 75,
|
||||
antFrom: 'July 2026'
|
||||
}, {
|
||||
item: 'Google Workspace',
|
||||
for: 'Email and documents — one seat',
|
||||
current: 7,
|
||||
ant: 14,
|
||||
antFrom: 'Sept 2026'
|
||||
}, {
|
||||
item: 'Anthropic',
|
||||
for: 'Claude — one Max plan, the AI we build alongside every day',
|
||||
current: 100,
|
||||
ant: 100,
|
||||
antFrom: null
|
||||
}];
|
||||
const sumCur = lines.reduce((a, l) => a + l.current, 0);
|
||||
const sumAnt = lines.reduce((a, l) => a + l.ant, 0);
|
||||
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("section", {
|
||||
className: "page-hero"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap"
|
||||
}, /*#__PURE__*/React.createElement(Eyebrow, null, "Radical transparency \xB7 open book"), /*#__PURE__*/React.createElement("h1", null, "Open book"), /*#__PURE__*/React.createElement(Soul, {
|
||||
size: "md",
|
||||
as: "p",
|
||||
className: "page-hero__soul"
|
||||
}, "We show you the receipts."), /*#__PURE__*/React.createElement("p", {
|
||||
className: "lead"
|
||||
}, "We take only what it takes to run this organization and the platform \u2014 and the only way to mean that is to show our work. Here is what it actually costs to run Wiggleverse, line by line."))), /*#__PURE__*/React.createElement("section", {
|
||||
className: "section"
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: "wrap prose"
|
||||
}, /*#__PURE__*/React.createElement("h2", null, "What it costs to run Wiggleverse"), /*#__PURE__*/React.createElement("p", {
|
||||
className: "ledger-stamp"
|
||||
}, "Last updated 8 June 2026 \xB7 hand-kept estimates, refreshed monthly for now."), /*#__PURE__*/React.createElement("table", {
|
||||
className: "ledger"
|
||||
}, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", {
|
||||
scope: "col"
|
||||
}, "Line item"), /*#__PURE__*/React.createElement("th", {
|
||||
scope: "col"
|
||||
}, "What it's for"), /*#__PURE__*/React.createElement("th", {
|
||||
scope: "col",
|
||||
className: "num"
|
||||
}, "Current / mo"), /*#__PURE__*/React.createElement("th", {
|
||||
scope: "col",
|
||||
className: "num"
|
||||
}, "Anticipated / mo"))), /*#__PURE__*/React.createElement("tbody", null, lines.map(l => /*#__PURE__*/React.createElement("tr", {
|
||||
key: l.item
|
||||
}, /*#__PURE__*/React.createElement("td", null, l.item), /*#__PURE__*/React.createElement("td", null, l.for), /*#__PURE__*/React.createElement("td", {
|
||||
className: "num"
|
||||
}, "$", l.current), /*#__PURE__*/React.createElement("td", {
|
||||
className: "num"
|
||||
}, "$", l.ant, l.antFrom && /*#__PURE__*/React.createElement("span", {
|
||||
className: "when"
|
||||
}, "from ", l.antFrom))))), /*#__PURE__*/React.createElement("tfoot", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "Total"), /*#__PURE__*/React.createElement("td", null, "per month, plus tax"), /*#__PURE__*/React.createElement("td", {
|
||||
className: "num"
|
||||
}, "$", sumCur), /*#__PURE__*/React.createElement("td", {
|
||||
className: "num"
|
||||
}, "$", sumAnt, /*#__PURE__*/React.createElement("span", {
|
||||
className: "when"
|
||||
}, "by Sept 2026"))))), /*#__PURE__*/React.createElement("p", null, "Revenue today is ", /*#__PURE__*/React.createElement("strong", null, "$0"), " \u2014 we haven't launched commerce yet. Covering these costs ourselves is the whole point of ", /*#__PURE__*/React.createElement("a", {
|
||||
href: "#/ecomm"
|
||||
}, "building commerce first"), "."), /*#__PURE__*/React.createElement(Callout, null, "Ethics that cannot be checked are just claims."))));
|
||||
}
|
||||
const SCREENS = {
|
||||
'#/': HomeScreen,
|
||||
'#/about': AboutScreen,
|
||||
'#/ecomm': EcommScreen,
|
||||
'#/finances': FinancesScreen
|
||||
};
|
||||
function App() {
|
||||
const [route, setRoute] = React.useState(window.location.hash || '#/');
|
||||
React.useEffect(() => {
|
||||
const onHash = () => {
|
||||
setRoute(window.location.hash || '#/');
|
||||
window.scrollTo(0, 0);
|
||||
};
|
||||
window.addEventListener('hashchange', onHash);
|
||||
return () => window.removeEventListener('hashchange', onHash);
|
||||
}, []);
|
||||
const Screen = SCREENS[route] || HomeScreen;
|
||||
const current = route === '#/about' ? 'About' : route === '#/ecomm' ? 'Build' : route === '#/finances' ? 'Learn' : undefined;
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: "wv-app"
|
||||
}, /*#__PURE__*/React.createElement(SiteHeader, {
|
||||
links: NAV,
|
||||
current: current,
|
||||
assetBase: ASSET_BASE,
|
||||
homeHref: "#/"
|
||||
}), /*#__PURE__*/React.createElement("main", null, /*#__PURE__*/React.createElement(Screen, null)), /*#__PURE__*/React.createElement(SiteFooter, {
|
||||
columns: FOOTER_COLS,
|
||||
assetBase: ASSET_BASE
|
||||
}));
|
||||
}
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(/*#__PURE__*/React.createElement(App, null));
|
||||
})(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/wiggleverse-www/app.jsx", error: String((e && e.message) || e) }); }
|
||||
|
||||
__ds_ns.BrandLockup = __ds_scope.BrandLockup;
|
||||
|
||||
__ds_ns.BuildCard = __ds_scope.BuildCard;
|
||||
|
||||
__ds_ns.PathCard = __ds_scope.PathCard;
|
||||
|
||||
__ds_ns.Button = __ds_scope.Button;
|
||||
|
||||
__ds_ns.Callout = __ds_scope.Callout;
|
||||
|
||||
__ds_ns.Eyebrow = __ds_scope.Eyebrow;
|
||||
|
||||
__ds_ns.Notice = __ds_scope.Notice;
|
||||
|
||||
__ds_ns.Soul = __ds_scope.Soul;
|
||||
|
||||
__ds_ns.Tag = __ds_scope.Tag;
|
||||
|
||||
__ds_ns.SiteFooter = __ds_scope.SiteFooter;
|
||||
|
||||
__ds_ns.SiteHeader = __ds_scope.SiteHeader;
|
||||
|
||||
})();
|
||||
+1
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
/* Space Grotesk — machine register: headings, wordmark */
|
||||
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:500;font-display:swap;src:url('./space-grotesk-v22-latin-500.woff2') format('woff2');}
|
||||
@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:700;font-display:swap;src:url('./space-grotesk-v22-latin-700.woff2') format('woff2');}
|
||||
/* Inter — machine register: body / UI */
|
||||
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url('./inter-v20-latin-regular.woff2') format('woff2');}
|
||||
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url('./inter-v20-latin-500.woff2') format('woff2');}
|
||||
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url('./inter-v20-latin-600.woff2') format('woff2');}
|
||||
/* Fraunces — human register: pull-quotes (italic only) */
|
||||
@font-face{font-family:'Fraunces';font-style:italic;font-weight:400;font-display:swap;src:url('./fraunces-v38-latin-italic.woff2') format('woff2');}
|
||||
@font-face{font-family:'Fraunces';font-style:italic;font-weight:500;font-display:swap;src:url('./fraunces-v38-latin-500italic.woff2') format('woff2');}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+170
@@ -0,0 +1,170 @@
|
||||
# Wiggleverse Design System
|
||||
|
||||
The core design system for **Wiggleverse.org** — a Washington 501(c)(3)
|
||||
nonprofit building art and software for a world at peace, on one shared set of
|
||||
ethics. Its first product is *Ecomm* (Shopify-class commerce at near-zero cost);
|
||||
the portfolio also names *Apps* and *Learn*, all built on an **Open Core**.
|
||||
|
||||
> *Treat humans as humans — everything else follows.*
|
||||
|
||||
This system captures the brand exactly as it ships on the marketing site so that
|
||||
agents and designers can produce on-brand interfaces, decks, and assets.
|
||||
|
||||
## Sources
|
||||
|
||||
Built from the live marketing-site codebase, the source of truth:
|
||||
|
||||
- **Codebase:** `wiggleverse-www/` — static site (plain HTML/CSS/JS, no build
|
||||
step), deployed to Cloudflare Pages. Brand tokens live in
|
||||
`wiggleverse-www/assets/tokens.css`; the design system CSS is
|
||||
`wiggleverse-www/styles.css`.
|
||||
- **Brand source of truth (referenced, not attached):** `wiggleverse-org/corp` →
|
||||
`brand/BRAND.md` (§5–10). The site's `assets/` kit is a vendored copy. The
|
||||
site design spec is `corp/docs/superpowers/specs/2026-06-04-wiggleverse-www-design.md`.
|
||||
- **Fonts** are the real vendored woff2 files (Space Grotesk, Inter, Fraunces),
|
||||
copied into `assets/fonts/`. No substitutions were made.
|
||||
|
||||
---
|
||||
|
||||
## Content fundamentals
|
||||
|
||||
How Wiggleverse writes. The voice is **two registers passing through one
|
||||
review** — the same idea the product is built on.
|
||||
|
||||
- **Machine register (default).** Precise, structural, plain-spoken. Most copy
|
||||
lives here: headings, UI, body prose. Calm and declarative, never hypey.
|
||||
*"We take only what it takes to run."*
|
||||
- **Human register ("the soul").** Warm, literary, used **sparingly** for the
|
||||
lines that carry conscience — taglines and pull-quotes only. Always set in
|
||||
**Fraunces italic**. *"We are verbs, not nouns." · "Ethics that cannot be
|
||||
checked are just claims."*
|
||||
|
||||
Specifics:
|
||||
|
||||
- **Person.** Mostly **we / our** (the org speaking plainly and accountably).
|
||||
Slips to **first-person singular** for the founder's voice in the About essay
|
||||
("I felt that one firsthand… — Ben Stull, Founder"). Addresses the reader as
|
||||
**you** in product/partner copy.
|
||||
- **Tone.** Honest, humble, anti-extractive, quietly ambitious. Leads with
|
||||
*what is enough?* rather than *how much can we get?* Admits limits openly
|
||||
("hand-kept estimates, refreshed monthly for now").
|
||||
- **Casing.** Sentence case everywhere — headings, buttons, nav. **Eyebrows**
|
||||
and small labels are UPPERCASE with wide tracking. Product names are casual
|
||||
and lowercase-ish in prose ("ecomm"), Title Case as proper nouns ("Ecomm").
|
||||
- **Punctuation.** Em dashes for asides. Arrows (`→`) end calls to action
|
||||
("Why Wiggleverse →"). Italic emphasis on the load-bearing question
|
||||
(*what is enough?*). Bold for the load-bearing noun phrases in a list.
|
||||
- **No emoji.** None, anywhere. Status and emphasis come from type and a small
|
||||
set of geometric glyphs (see Iconography).
|
||||
- **Recurring phrases.** "Treat humans as humans." · "We take only what it takes
|
||||
to run." · "Radical transparency / we show you the receipts." · "Build the
|
||||
dictionary first." · "If you're learning, you're succeeding." · "We are verbs,
|
||||
not nouns." · the dedication to Aaron Swartz in every footer.
|
||||
- **The vibe.** A standards document (RFC/IETF) with a conscience — exact where
|
||||
it matters, tender where it counts.
|
||||
|
||||
---
|
||||
|
||||
## Visual foundations
|
||||
|
||||
The whole system answers to one motif: a **Circle of Equals** — one living,
|
||||
wiggling line through six equal points, closed into a ring, with a **deliberately
|
||||
empty center** ("no center, no hub, no sun"). The connecting line *is* the ethic.
|
||||
|
||||
- **Ground.** **Dark "sky" is primary** (`--wv-midnight #0E1230`). Long-reading
|
||||
passages flip to **Paper** (`--wv-paper #F6F4FB`) sections. Most of the system
|
||||
lives on dark.
|
||||
- **Color.** Indigo (`#1C2150`) for raised surfaces; **lilac** (`#9B8CFF`) is the
|
||||
accent — links, nodes, "the bonds between us"; **violet** (`#7C6FE0`) is its
|
||||
on-paper counterpart; **gold** (`#F4C76B`) is warmth / horizon / the single
|
||||
primary CTA color; **starlight** (`#EDEAFF`) is text on dark; **ink**
|
||||
(`#3B2F7A`) is text on paper. A near-black **night** (`#090C22`) grounds the
|
||||
footer.
|
||||
- **Type.** Two machine faces + one human face. **Space Grotesk** 500/700 for
|
||||
display & wordmark (tracked in −0.015em). **Inter** 400/500/600 for body & UI.
|
||||
**Fraunces italic** 400/500 for the soul — *italic only, never upright, never
|
||||
body copy.* Headings use fluid `clamp()` sizes.
|
||||
- **Backgrounds.** No photography in the system. The hero uses a **scattered
|
||||
starfield** (faint multi-radial-gradient nodes, intentionally off-center) and a
|
||||
large, very low-opacity (≈0.14) mark bleeding off the right edge. Otherwise:
|
||||
flat color fields. No big gradients as surfaces (the only gradient is *inside*
|
||||
the mark, lilac→gold).
|
||||
- **Borders & cards.** Depth is carried by **surface color + hairline borders**,
|
||||
not shadows. Cards are indigo (on dark) or white (on paper) with a 1px
|
||||
lilac/violet hairline at low alpha, **14px** radius. The system is
|
||||
**near-shadowless** — a soft shadow token exists but is rarely used.
|
||||
- **Radii.** 14px cards, 12px panels, 4px focus, **999px pills** (buttons, tags,
|
||||
notices), 26px app-tile.
|
||||
- **Animation.** Restrained. Transitions ≈ `.15s ease`. Hover = **translateY
|
||||
lift** (−1px buttons, −3px cards), *not* a shadow or scale. Mobile nav reveals
|
||||
via `max-height .25s`. Everything is killed under
|
||||
`prefers-reduced-motion: reduce`. No bounces, no loops, no parallax.
|
||||
- **Hover / press.** Links underline (3px offset, lilac). Buttons lift and
|
||||
lighten (gold → `#F7D488`). Cards lift and warm their border to lilac, surface
|
||||
to `#232A63`. No color-darkening press states; no shrink.
|
||||
- **Transparency & blur.** The **sticky header** is the one glass surface:
|
||||
`rgba(14,18,48,.82)` + `blur(10px)` + a lilac hairline. Alpha lilac/gold/
|
||||
starlight washes (`.08`–`.40`) do tints, dividers, and focus rings.
|
||||
- **Focus.** Always visible: **3px gold outline**, 2px offset, 4px rounding.
|
||||
Accessibility is load-bearing (skip links, `aria-current`, reduced-motion).
|
||||
- **Imagery vibe.** Cool, dark, cosmic, calm — starlight on midnight, warmed by a
|
||||
single gold horizon. Never busy, never loud.
|
||||
- **Layout.** Content column is `min(1080px, 92vw)`, gutter-aligned (not
|
||||
auto-centered text). Prose blocks cap at a 68ch measure. Sections breathe with
|
||||
fluid `clamp(3rem, 7vw, 5.5rem)` vertical padding.
|
||||
|
||||
---
|
||||
|
||||
## Iconography
|
||||
|
||||
Wiggleverse is **iconography-light by design**. There is **no icon font and no
|
||||
icon set** in the codebase.
|
||||
|
||||
- **The mark** is the one true graphic: the *Circle of Equals*, shipped as SVG in
|
||||
four cuts — `wiggleverse-mark.svg` (lilac→gold gradient line, starlight nodes),
|
||||
`mark-mono-gold.svg` (footer), `mark-on-light.svg` (ink on paper), and
|
||||
`favicon.svg` (gold line + starlight nodes on a rounded-26px midnight tile).
|
||||
Raster favicons (`favicon-32.png`, `favicon-180.png`) are provided for tabs and
|
||||
iOS. All are in `assets/`.
|
||||
- **"Icons" are geometric unicode glyphs.** The audience router uses
|
||||
**✧ ◇ ◈ ❍ ◐** as quiet, abstract door markers — never pictographic icons,
|
||||
never emoji. Treat these as the sanctioned glyph set when a small mark is
|
||||
needed. Arrows are literal `→` characters in link/button text.
|
||||
- **No emoji, ever.** (Reconfirmed under Content fundamentals.)
|
||||
- **If you need UI icons** (e.g. a richer product surface that the marketing site
|
||||
doesn't cover), there is no house set to match — keep them to a thin,
|
||||
geometric, single-weight line style consistent with the mark, and **flag the
|
||||
addition** so it can be folded into the brand properly. Do not hand-draw new
|
||||
brand illustrations.
|
||||
|
||||
---
|
||||
|
||||
## Index / manifest
|
||||
|
||||
Root files:
|
||||
|
||||
- `styles.css` — the global entry point (consumers link this one file). `@import`
|
||||
manifest only.
|
||||
- `tokens/colors.css` · `tokens/typography.css` · `tokens/spacing.css` — CSS
|
||||
custom properties (base values + semantic aliases).
|
||||
- `assets/` — the Circle-of-Equals marks (4 cuts), favicons, and the three
|
||||
vendored webfont families in `assets/fonts/` (+ `fonts.css` `@font-face`).
|
||||
- `guidelines/` — foundation specimen cards (Colors, Type, Spacing, Brand).
|
||||
- `SKILL.md` — Agent-Skills-compatible entry point.
|
||||
|
||||
Components (`window.WiggleverseDesignSystem_*`):
|
||||
|
||||
- **core/** — `Button`, `Tag`, `Notice`, `Eyebrow`, `Soul`, `Callout`
|
||||
- **cards/** — `PathCard`, `BuildCard`
|
||||
- **brand/** — `BrandLockup`
|
||||
- **navigation/** — `SiteHeader`, `SiteFooter`
|
||||
|
||||
UI kits:
|
||||
|
||||
- **ui_kits/wiggleverse-www/** — high-fidelity recreation of the marketing site
|
||||
(Home, About, Ecomm, Finances/open-book), composing the components above.
|
||||
|
||||
Each component directory carries `<Name>.jsx`, `<Name>.d.ts`, `<Name>.prompt.md`,
|
||||
and one `@dsCard` HTML thumbnail. Mount components in card/kit HTML via
|
||||
`const { X } = window.WiggleverseDesignSystem_94cd80` after loading
|
||||
`_ds_bundle.js` (generated automatically — do not edit).
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/* Wiggleverse Design System — global entry point.
|
||||
Consumers link THIS one file. It is an @import manifest only — no rules here.
|
||||
Everything reachable from here ships to consumers (tokens + @font-face webfonts). */
|
||||
|
||||
@import url("./assets/fonts/fonts.css"); /* Space Grotesk · Inter · Fraunces (@font-face) */
|
||||
@import url("./tokens/colors.css"); /* palette + semantic color aliases */
|
||||
@import url("./tokens/typography.css"); /* families, scale, weights, tracking */
|
||||
@import url("./tokens/spacing.css"); /* spacing, radii, borders, motion, layout */
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/* Wiggleverse — Color tokens
|
||||
Source of truth: wiggleverse-www/assets/tokens.css (brand BRAND.md §8–9).
|
||||
Dark "sky" is the primary ground; Paper is for long reading. No-center motif. */
|
||||
|
||||
:root {
|
||||
/* ---- Brand palette (base values) ---- */
|
||||
--wv-midnight: #0E1230; /* sky / ground — primary dark background */
|
||||
--wv-indigo: #1C2150; /* raised surfaces on dark (cards, mobile nav) */
|
||||
--wv-indigo-2: #232A63; /* hover state for raised surfaces */
|
||||
--wv-lilac: #9B8CFF; /* accent — "the bonds between us"; links, nodes */
|
||||
--wv-violet: #7C6FE0; /* secondary links / strokes (on light) */
|
||||
--wv-gold: #F4C76B; /* warmth / horizon / primary CTAs */
|
||||
--wv-gold-hi: #F7D488; /* gold hover */
|
||||
--wv-starlight:#EDEAFF; /* nodes / text on dark */
|
||||
--wv-paper: #F6F4FB; /* light-mode background */
|
||||
--wv-ink: #3B2F7A; /* text on light */
|
||||
--wv-night: #090C22; /* footer / deepest ground */
|
||||
|
||||
/* CTA text-on-gold (very dark gold-brown, not pure black) */
|
||||
--wv-gold-ink: #2A2003;
|
||||
--wv-gold-ink-soft: #6B4E10; /* "soon" tag text on gold tint */
|
||||
|
||||
/* ---- Alpha derivations (lilac / gold / starlight washes) ---- */
|
||||
--wv-lilac-08: rgba(155, 140, 255, .08);
|
||||
--wv-lilac-12: rgba(155, 140, 255, .12);
|
||||
--wv-lilac-16: rgba(155, 140, 255, .16);
|
||||
--wv-lilac-18: rgba(155, 140, 255, .18);
|
||||
--wv-lilac-32: rgba(155, 140, 255, .32);
|
||||
--wv-gold-28: rgba(244, 199, 107, .28);
|
||||
--wv-gold-40: rgba(244, 199, 107, .40);
|
||||
--wv-starlight-85: rgba(237, 234, 255, .85);
|
||||
--wv-starlight-78: rgba(237, 234, 255, .78);
|
||||
--wv-starlight-60: rgba(237, 234, 255, .60);
|
||||
--wv-starlight-55: rgba(237, 234, 255, .55);
|
||||
|
||||
/* ---- Semantic aliases ---- */
|
||||
--surface-sky: var(--wv-midnight); /* page ground (dark) */
|
||||
--surface-raised: var(--wv-indigo); /* cards / panels on dark */
|
||||
--surface-raised-hi: var(--wv-indigo-2); /* raised hover */
|
||||
--surface-paper: var(--wv-paper); /* long-reading light sections */
|
||||
--surface-card-light:#FFFFFF; /* build-cards on paper */
|
||||
--surface-footer: var(--wv-night);
|
||||
|
||||
--text-on-dark: var(--wv-starlight);
|
||||
--text-on-dark-soft: var(--wv-starlight-78);
|
||||
--text-on-dark-mute: var(--wv-starlight-60);
|
||||
--text-on-light: var(--wv-ink);
|
||||
--text-on-light-soft:#4B4170;
|
||||
|
||||
--accent: var(--wv-lilac); /* links + nodes on dark */
|
||||
--accent-on-light: var(--wv-violet); /* links + strokes on light */
|
||||
--cta: var(--wv-gold); /* primary action / horizon */
|
||||
--cta-hover: var(--wv-gold-hi);
|
||||
--cta-text: var(--wv-gold-ink);
|
||||
|
||||
--border-soft: var(--wv-lilac-16); /* hairlines on dark */
|
||||
--border-card: var(--wv-lilac-18);
|
||||
--border-strong: var(--wv-lilac-32);
|
||||
--focus-ring: var(--wv-gold);
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/* Wiggleverse — Spacing, radius, shadow, layout & motion tokens
|
||||
Derived from the marketing-site CSS. The brand has almost no shadow system —
|
||||
depth is carried by surface color + hairline borders, not drop shadows. */
|
||||
|
||||
:root {
|
||||
/* ---- Spacing scale (rem) ---- */
|
||||
--space-0: 0;
|
||||
--space-1: .25rem;
|
||||
--space-2: .5rem;
|
||||
--space-3: .7rem;
|
||||
--space-4: 1rem;
|
||||
--space-5: 1.2rem;
|
||||
--space-6: 1.6rem;
|
||||
--space-8: 2rem;
|
||||
--space-10: 2.5rem;
|
||||
--space-12: 3rem;
|
||||
|
||||
/* Section rhythm — fluid vertical padding for page bands */
|
||||
--section-pad: clamp(3rem, 7vw, 5.5rem);
|
||||
--page-hero-pad: clamp(2.8rem, 6vw, 4.5rem);
|
||||
|
||||
/* ---- Layout ---- */
|
||||
--wrap-max: 1080px; /* content column */
|
||||
--wrap-gutter: 92vw; /* width: min(--wrap-max, --wrap-gutter) */
|
||||
--measure-prose: 68ch; /* reading measure for prose blocks */
|
||||
|
||||
/* ---- Radii ---- */
|
||||
--radius-card: 14px; /* path-cards, build-cards */
|
||||
--radius-panel: 12px; /* principle tiles */
|
||||
--radius-sm: 4px; /* focus ring rounding */
|
||||
--radius-pill: 999px; /* buttons, tags, notices */
|
||||
--radius-mark: 26px; /* favicon tile rounding */
|
||||
|
||||
/* ---- Borders ---- */
|
||||
--border-hair: 1px; /* default hairline */
|
||||
--border-card-w: 1px;
|
||||
--btn-border-w: 1.5px; /* ghost button / focus weight */
|
||||
|
||||
/* ---- Elevation ---- *
|
||||
* The system avoids drop shadows. "Lift" on hover is a -1 to -3px translateY,
|
||||
* not a shadow. These tokens exist for the rare card that needs real elevation. */
|
||||
--shadow-none: none;
|
||||
--shadow-soft: 0 8px 24px rgba(9, 12, 34, .28);
|
||||
--lift-1: translateY(-1px); /* @kind other */ /* buttons */
|
||||
--lift-3: translateY(-3px); /* @kind other */ /* cards */
|
||||
|
||||
/* ---- Glass (sticky header) ---- */
|
||||
--glass-sky: rgba(14, 18, 48, .82);
|
||||
--glass-blur: 10px;
|
||||
|
||||
/* ---- Motion ---- */
|
||||
--ease: ease; /* @kind other */
|
||||
--dur-fast: .15s; /* @kind other */ /* hover / press transitions */
|
||||
--dur-mid: .25s; /* @kind other */ /* mobile nav reveal */
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/* Wiggleverse — Typography tokens
|
||||
Two registers, one meaning (BRAND.md):
|
||||
• Machine register — Space Grotesk (display) + Inter (body/UI): precise, structural.
|
||||
• Human register — Fraunces, ITALIC ONLY: warm, literary, used sparingly
|
||||
for the lines that carry conscience ("the soul").
|
||||
@font-face rules live in assets/fonts/fonts.css. */
|
||||
|
||||
:root {
|
||||
/* ---- Families ---- */
|
||||
--wv-font-display: 'Space Grotesk', system-ui, sans-serif; /* headings, wordmark */
|
||||
--wv-font-body: 'Inter', system-ui, sans-serif; /* body / UI */
|
||||
--wv-font-human: 'Fraunces', Georgia, serif; /* pull-quotes — italic only */
|
||||
|
||||
/* semantic aliases */
|
||||
--font-display: var(--wv-font-display);
|
||||
--font-body: var(--wv-font-body);
|
||||
--font-soul: var(--wv-font-human);
|
||||
|
||||
/* ---- Weights ---- */
|
||||
--weight-regular: 400; /* Inter body */
|
||||
--weight-medium: 500; /* nav, eyebrows, buttons, Space Grotesk text */
|
||||
--weight-semibold:600; /* Inter emphasis, ledger totals */
|
||||
--weight-bold: 700; /* Space Grotesk headings, wordmark */
|
||||
--weight-soul: 500; /* Fraunces italic pull-quotes */
|
||||
|
||||
/* ---- Fluid display sizes (clamp: min, vw, max) ---- */
|
||||
--text-h1: clamp(2.1rem, 5.2vw, 3.6rem);
|
||||
--text-h2: clamp(1.6rem, 3.4vw, 2.4rem);
|
||||
--text-h3: 1.2rem;
|
||||
--text-lead: clamp(1.05rem, 1.8vw, 1.3rem); /* intro paragraph */
|
||||
--text-soul: clamp(1.2rem, 2.4vw, 1.7rem); /* hero pull-quote */
|
||||
|
||||
/* ---- Body / UI scale ---- */
|
||||
--text-body: 1rem; /* 16px base */
|
||||
--text-small: .95rem;
|
||||
--text-fine: .92rem;
|
||||
--text-eyebrow: .8rem; /* uppercase label */
|
||||
--text-tag: .72rem; /* pill tags */
|
||||
|
||||
/* ---- Line heights ---- */
|
||||
--leading-tight: 1.12; /* headings */
|
||||
--leading-body: 1.6; /* paragraphs */
|
||||
|
||||
/* ---- Letter spacing ---- */
|
||||
--tracking-display: -0.015em; /* headings + wordmark draw in slightly */
|
||||
--tracking-eyebrow: 0.12em; /* uppercase eyebrows open up */
|
||||
--tracking-tag: 0.08em;
|
||||
--tracking-notice: 0.06em;
|
||||
|
||||
/* ---- Measure ---- */
|
||||
--measure-lead: 60ch;
|
||||
--measure-prose:68ch;
|
||||
}
|
||||
Reference in New Issue
Block a user