diff --git a/.impeccable/design.json b/.impeccable/design.json new file mode 100644 index 0000000..a29587c --- /dev/null +++ b/.impeccable/design.json @@ -0,0 +1,302 @@ +{ + "schemaVersion": 2, + "generatedAt": "2026-05-24T23:40:30.515Z", + "title": "Design System: Ghost Guild", + "extensions": { + "colorMeta": { + "candle": { + "role": "primary", + "displayName": "Candle Gold", + "canonical": "oklch(0.44 0.085 80)", + "tonalRamp": [ + "oklch(0.18 0.053 80)", + "oklch(0.29 0.069 80)", + "oklch(0.4 0.08 80)", + "oklch(0.51 0.085 80)", + "oklch(0.62 0.084 80)", + "oklch(0.73 0.078 80)", + "oklch(0.84 0.066 80)", + "oklch(0.95 0.048 80)" + ] + }, + "ember": { + "role": "secondary", + "displayName": "Ember Rust", + "canonical": "oklch(0.46 0.11 47)", + "tonalRamp": [ + "oklch(0.18 0.069 47)", + "oklch(0.29 0.09 47)", + "oklch(0.4 0.103 47)", + "oklch(0.51 0.11 47)", + "oklch(0.62 0.109 47)", + "oklch(0.73 0.1 47)", + "oklch(0.84 0.085 47)", + "oklch(0.95 0.062 47)" + ] + }, + "c-community": { + "role": "tertiary", + "displayName": "Community Clay", + "canonical": "oklch(0.44 0.06 40)", + "tonalRamp": [ + "oklch(0.18 0.038 40)", + "oklch(0.29 0.049 40)", + "oklch(0.4 0.056 40)", + "oklch(0.51 0.06 40)", + "oklch(0.62 0.059 40)", + "oklch(0.73 0.055 40)", + "oklch(0.84 0.046 40)", + "oklch(0.95 0.034 40)" + ] + }, + "c-practitioner": { + "role": "tertiary", + "displayName": "Practitioner Slate", + "canonical": "oklch(0.36 0.045 230)", + "tonalRamp": [ + "oklch(0.18 0.028 230)", + "oklch(0.29 0.037 230)", + "oklch(0.4 0.042 230)", + "oklch(0.51 0.045 230)", + "oklch(0.62 0.044 230)", + "oklch(0.73 0.041 230)", + "oklch(0.84 0.035 230)", + "oklch(0.95 0.025 230)" + ] + }, + "green": { + "role": "tertiary", + "displayName": "Guild Green", + "canonical": "oklch(0.5 0.08 135)", + "tonalRamp": [ + "oklch(0.18 0.05 135)", + "oklch(0.29 0.065 135)", + "oklch(0.4 0.075 135)", + "oklch(0.51 0.08 135)", + "oklch(0.62 0.079 135)", + "oklch(0.73 0.073 135)", + "oklch(0.84 0.062 135)", + "oklch(0.95 0.045 135)" + ] + }, + "bg": { + "role": "neutral", + "displayName": "Cream Paper", + "canonical": "oklch(0.95 0.012 90)", + "tonalRamp": [ + "oklch(0.18 0.008 90)", + "oklch(0.29 0.01 90)", + "oklch(0.4 0.011 90)", + "oklch(0.51 0.012 90)", + "oklch(0.62 0.012 90)", + "oklch(0.73 0.011 90)", + "oklch(0.84 0.009 90)", + "oklch(0.95 0.007 90)" + ] + }, + "surface": { + "role": "neutral", + "displayName": "Surface Tan", + "canonical": "oklch(0.9 0.025 88)", + "tonalRamp": [ + "oklch(0.18 0.016 88)", + "oklch(0.29 0.02 88)", + "oklch(0.4 0.023 88)", + "oklch(0.51 0.025 88)", + "oklch(0.62 0.025 88)", + "oklch(0.73 0.023 88)", + "oklch(0.84 0.019 88)", + "oklch(0.95 0.014 88)" + ] + }, + "text": { + "role": "neutral", + "displayName": "Ink", + "canonical": "oklch(0.24 0.02 70)", + "tonalRamp": [ + "oklch(0.18 0.013 70)", + "oklch(0.29 0.016 70)", + "oklch(0.4 0.019 70)", + "oklch(0.51 0.02 70)", + "oklch(0.62 0.02 70)", + "oklch(0.73 0.018 70)", + "oklch(0.84 0.015 70)", + "oklch(0.95 0.011 70)" + ] + } + }, + "typographyMeta": { + "display": { + "displayName": "Display", + "purpose": "Hero proclamations only; one per page, commands the fold." + }, + "headline": { + "displayName": "Headline", + "purpose": "Section and card headings, e.g. the circle metaphors." + }, + "title": { + "displayName": "Title", + "purpose": "Smaller serif headings inside dense blocks." + }, + "body": { + "displayName": "Body", + "purpose": "All prose and UI text; Commit Mono, measure capped 65-75ch." + }, + "label": { + "displayName": "Label", + "purpose": "Uppercase kickers, field labels, badges; the faint structural voice." + } + }, + "shadows": [ + { + "name": "popover-lift", + "value": "0 4px 12px rgba(0,0,0,0.12)", + "purpose": "The only shadow in the system. Floating portaled overlays (select menus, dropdowns) only; never in-page surfaces." + } + ], + "motion": [ + { + "name": "state", + "value": "0.15s ease", + "purpose": "Default button/border state transitions." + }, + { + "name": "reveal", + "value": "0.2s ease", + "purpose": "Hover nudges and lifts (transform only; respects prefers-reduced-motion)." + } + ], + "breakpoints": [ + { + "name": "content", + "value": "768px", + "purpose": "Multi-column content rows collapse to a single column." + }, + { + "name": "page-collapse", + "value": "1024px", + "purpose": "Sidebar navigation collapses to a Menu disclosure (--page-collapse)." + } + ] + }, + "components": [ + { + "name": "Primary Button", + "kind": "button", + "refersTo": "button-primary", + "description": "The single call-to-action treatment; solid candle gold with a solid border.", + "html": "", + "css": ".ds-btn-primary { font-family: \"Commit Mono\", monospace; font-size: 12px; letter-spacing: 0.04em; padding: 7px 18px; background: var(--candle); color: var(--bg); border: 1px solid var(--candle); border-radius: 0; cursor: pointer; transition: background 0.15s, border-color 0.15s; } .ds-btn-primary:hover { background: var(--candle-dim); border-color: var(--candle-dim); } .ds-btn-primary:focus-visible { outline: 2px dashed var(--candle); outline-offset: 3px; }" + }, + { + "name": "Default Button", + "kind": "button", + "refersTo": "button-default", + "description": "Neutral action; dashed border on cream, tonal fill on hover.", + "html": "", + "css": ".ds-btn { font-family: \"Commit Mono\", monospace; font-size: 12px; letter-spacing: 0.04em; padding: 7px 18px; background: var(--bg); color: var(--text); border: 1px dashed var(--border); border-radius: 0; cursor: pointer; transition: background 0.15s, border-color 0.15s; } .ds-btn:hover { background: var(--surface-hover); border-color: var(--border-d); } .ds-btn:focus-visible { outline: 2px dashed var(--candle); outline-offset: 3px; }" + }, + { + "name": "Danger Button", + "kind": "button", + "refersTo": "button-danger", + "description": "Destructive action; ember text and border, inverts to ember fill on hover.", + "html": "", + "css": ".ds-btn-danger { font-family: \"Commit Mono\", monospace; font-size: 12px; letter-spacing: 0.04em; padding: 7px 18px; background: var(--bg); color: var(--ember); border: 1px dashed var(--ember); border-radius: 0; cursor: pointer; transition: background 0.15s, color 0.15s; } .ds-btn-danger:hover { background: var(--ember); color: var(--bg); border-style: solid; }" + }, + { + "name": "Text Field", + "kind": "input", + "refersTo": "input", + "description": "Editable surface; dashed border that goes solid candle on focus.", + "html": "", + "css": ".ds-field span { display: block; font-family: \"Commit Mono\", monospace; font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 3px; } .ds-field input { width: 100%; box-sizing: border-box; font-family: \"Commit Mono\", monospace; font-size: 13px; padding: 5px 8px; color: var(--text-bright); background: var(--input-bg); border: 1px dashed var(--border); border-radius: 0; outline: none; } .ds-field input:focus { border-color: var(--candle); border-style: solid; }" + }, + { + "name": "Circle Badge", + "kind": "chip", + "refersTo": "badge", + "description": "Membership-tier identity tag; dashed border in the circle hue. Not a generic tag.", + "html": "Practitioner", + "css": ".ds-badge { display: inline-block; font-family: \"Commit Mono\", monospace; font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; padding: 2px 8px; color: var(--c-practitioner); border: 1px dashed rgba(42,70,80,0.35); border-radius: 0; }" + }, + { + "name": "Sidebar Nav Item", + "kind": "nav", + "refersTo": "navigation", + "description": "Left-rail navigation entry; tonal fill when active, mono type.", + "html": "", + "css": ".ds-nav { display: flex; flex-direction: column; font-family: \"Commit Mono\", monospace; font-size: 13px; border-right: 1px dashed var(--border); width: 200px; } .ds-nav-item { padding: 6px 12px; color: var(--text); text-decoration: none; transition: background 0.15s, color 0.15s; } .ds-nav-item:hover { background: var(--surface-hover); } .ds-nav-item.is-active { background: var(--surface); color: var(--text-bright); }" + }, + { + "name": "Hero CTA Broadside", + "kind": "custom", + "refersTo": "hero-cta", + "description": "Signature: oversized serif headline with one ember word, a solid primary block, and demoted text links.", + "html": "

Game developers explore cooperative models.

Become a memberRead the wiki
", + "css": ".ds-hero h1 { font-family: \"Brygada 1918\", serif; font-size: clamp(40px, 6.5vw, 80px); font-weight: 600; line-height: 1.04; letter-spacing: -0.022em; color: var(--text-bright); max-width: 16ch; margin: 0 0 28px; } .ds-hero h1 span { color: var(--ember); } .ds-hero-links { display: flex; align-items: center; gap: 24px; } .ds-hero-primary { font-family: \"Commit Mono\", monospace; font-size: 14px; padding: 13px 30px; background: var(--candle); color: var(--bg); border: 1px solid var(--candle); text-decoration: none; transition: background 0.2s, transform 0.2s; } .ds-hero-primary:hover { background: var(--candle-dim); transform: translateY(-2px); } .ds-hero-link { font-family: \"Commit Mono\", monospace; font-size: 14px; color: var(--candle); padding: 4px 0; border-bottom: 1px dashed var(--candle-faint); text-decoration: none; }" + }, + { + "name": "Parchment Inset", + "kind": "card", + "refersTo": null, + "description": "Signature: inverted dark block for a featured passage; pinned to the same values in light and dark mode.", + "html": "", + "css": ".ds-parch { background: #2a2015; color: #ede4d0; padding: 28px 32px; border-radius: 0; } .ds-parch-label { font-family: \"Commit Mono\", monospace; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: #c4a448; margin-bottom: 12px; } .ds-parch h2 { font-family: \"Brygada 1918\", serif; font-size: 22px; font-weight: 500; margin: 0 0 10px; } .ds-parch p { font-family: \"Commit Mono\", monospace; font-size: 13px; line-height: 1.7; color: #b8ae98; margin: 0; }" + } + ], + "narrative": { + "northStar": "The Text Adventure Hall", + "overview": "Ghost Guild is a world built from words: a monospace text adventure rendered on cream paper. Rooms instead of pages, prose instead of chrome, structure drawn in dashed ink rather than boxes and shadows. Two typefaces (Brygada 1918 serif for display, Commit Mono for everything else) do all the work over a warm cream ground with a faint noise texture. Candlelight gold is the single voice of action; ember rust is the rare focal emphasis. Depth is tonal layering, never drop shadows or glass.", + "keyCharacteristics": [ + "Two fonts only: Brygada 1918 (serif display) + Commit Mono (everything else).", + "Cream paper ground with a 2.5% noise overlay; warm, tinted neutrals throughout.", + "Dashed borders for structure, solid borders for inputs and active state.", + "Square corners everywhere (border-radius: 0).", + "Flat by default: depth comes from tonal layering, not shadows.", + "Candle gold is the only call-to-action color; ember rust is the rare accent." + ], + "rules": [ + { + "name": "The Candlelight Rule", + "body": "Candle gold is the only color permitted on a call-to-action. If something is gold, it acts. Nothing decorative wears gold.", + "section": "colors" + }, + { + "name": "The Single Ember Rule", + "body": "Ember rust appears at most once per view as emphasis. Two embers cancel each other out; the rarity is the point.", + "section": "colors" + }, + { + "name": "The Two-Font Rule", + "body": "Brygada 1918 and Commit Mono. That is the entire type system. A third family is forbidden.", + "section": "typography" + }, + { + "name": "The Flat Paper Rule", + "body": "Surfaces sit flat on the page. If you reach for box-shadow on an in-page element, use a dashed border or a tonal surface step instead. Shadows belong only to floating popovers.", + "section": "elevation" + } + ], + "dos": [ + "Do use exactly two typefaces: Brygada 1918 for display/headings, Commit Mono for everything else.", + "Do draw structure with 1px dashed borders, and switch borders to solid only for inputs and active state.", + "Do keep every corner square (border-radius: 0).", + "Do reserve Candle Gold (#7a5a10) for actions and Ember Rust (#8a4420) for a single focal emphasis per view.", + "Do convey depth through tonal layering (cream -> surface -> parchment) and the noise overlay, not shadows.", + "Do keep text contrast at WCAG AA: Ink Dim (#5a5040) and Ink Faint (#665c4b) were tuned to pass on cream.", + "Do use fluid clamp() spacing and type so the layout breathes on large viewports." + ], + "donts": [ + "Don't introduce a third typeface. (The Two-Font Rule.)", + "Don't round corners anywhere.", + "Don't put box-shadow on in-page surfaces; shadows belong only to floating popovers.", + "Don't use a border-left/border-right greater than 1px as a colored accent stripe.", + "Don't use gradient text or background-clip: text; emphasis comes from weight, size, or a single ember word.", + "Don't use purple/blue gradients, glassmorphism, neon-on-dark, or identical icon-title card grids.", + "Don't reach for CSS hacks: no negative margins, no magic numbers, no fragile workarounds.", + "Don't put neutral gray text on the parchment block or any colored surface; use the parchment text tokens.", + "Don't use UToggle; use USwitch (Nuxt UI 4)." + ] + } +} diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 9ee189f..abb9d3c 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -248,6 +248,17 @@ p a, blockquote a { border-color: var(--border); } +/* ---- ACCENT TINT BLOCKS ---- */ +/* Faint accent fill + matching solid border. Replaces inline color-mix styles. */ +.tint-candle { + background: color-mix(in srgb, var(--candle) 15%, transparent); + border: 1px solid var(--candle); +} +.tint-ember { + background: color-mix(in srgb, var(--ember) 15%, transparent); + border: 1px solid var(--ember); +} + /* ---- SEGMENTED CONTROL (flush dashed-border groups) ---- */ /* Negative-margin overlap: every item keeps all 4 borders, siblings overlap by 1px, active item paints on top via z-index. */ diff --git a/app/components/EventSeriesTicketCard.vue b/app/components/EventSeriesTicketCard.vue index 1340f3c..b475430 100644 --- a/app/components/EventSeriesTicketCard.vue +++ b/app/components/EventSeriesTicketCard.vue @@ -63,8 +63,7 @@ class="flex items-start gap-3 p-3" >
{{ index + 1 }}
@@ -86,8 +85,7 @@
@@ -103,8 +101,7 @@
@@ -162,8 +159,7 @@
diff --git a/app/components/SeriesPassPurchase.vue b/app/components/SeriesPassPurchase.vue index fff5fd4..8569ed5 100644 --- a/app/components/SeriesPassPurchase.vue +++ b/app/components/SeriesPassPurchase.vue @@ -100,8 +100,7 @@
{ confirmAction.execute = async () => { confirmAction.running = true try { - for (const event of series.events) { - await $fetch(`/api/admin/events/${event.id}`, { - method: 'PUT', - body: { - ...event, - series: { isSeriesEvent: false, id: '', title: '', description: '', type: 'workshop_series', position: 1, totalEvents: null }, - }, - }) - } + await $fetch(`/api/admin/series/${series.id}`, { method: 'DELETE' }) confirmAction.show = false await refresh() } catch (error) { diff --git a/app/pages/index.vue b/app/pages/index.vue index e4b1487..8343d6a 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -2,7 +2,7 @@
-

Ghost Guild is where game developers explore cooperative models.

+

Ghost Guild is where game developers explore cooperative models.

Resources, events, and a community of people figuring it out. Three circles, pay what you can. @@ -208,51 +208,68 @@ const formatDate = (event) => { diff --git a/app/pages/join.vue b/app/pages/join.vue index df1934b..b8b7b8b 100644 --- a/app/pages/join.vue +++ b/app/pages/join.vue @@ -3,7 +3,7 @@