Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 859d062059
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR updates theme references to point at the canonical Base realm Theme cards (not app.boxel.ai catalog URLs / in-realm relative theme paths), and removes/realigns Catalog realm “Skill*” card implementations in favor of the packages/base versions.
Changes:
- Update multiple card instances/docs to use
https://cardstack.com/base/Theme/cardstack-brand-guide(and Boxel’s brand guide) as the default theme link. - Remove Catalog realm implementations of
skill-plus,skill-set, andskill-reference(now present underpackages/base). - Refresh theme/theming documentation and update
SkillPlusMarkdownspec metadata.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/software-factory/experiment_1/realms/guidance-tasks/Ticket/ticket-001.json | Update default theme relationship link to Base realm theme. |
| packages/software-factory/experiment_1/realms/guidance-tasks/Project/demo-project.json | Update default theme relationship link to Base realm theme. |
| packages/software-factory/experiment_1/realms/guidance-tasks/KnowledgeArticle/agent-onboarding.json | Update default theme relationship link to Base realm theme. |
| packages/software-factory/experiment_1/.agents/skills/boxel-development/references/dev-theme-design-system.md | Update theme URL + refresh theme docs/examples. |
| packages/software-factory/.agents/skills/boxel-development/references/dev-theme-design-system.md | Same documentation updates as experiment_1 copy. |
| packages/realm-server/scripts/migrate-realm-references.sh | Update comment examples for reference migration script. |
| packages/experiments-realm/ProductCatalog/main.json | Update default theme relationship link to Base realm theme. |
| packages/catalog-realm/skill-set.gts | Remove catalog-realm SkillSet implementation (now in Base). |
| packages/catalog-realm/skill-reference.gts | Remove catalog-realm SkillReference implementation (now in Base). |
| packages/catalog-realm/skill-plus.gts | Remove catalog-realm SkillPlus implementation (now in Base). |
| packages/catalog-realm/ThemeListing/f87667d9-7616-4baf-b2fe-8ce5d393f676.json | Point theme example/theme relationship to Base realm cardstack brand guide. |
| packages/catalog-realm/ThemeListing/d7691256-67a2-48dc-91f6-2d76db7a0941.json | Remove a ThemeListing entry (old Cardstack theme listing). |
| packages/catalog-realm/ThemeListing/4d6390f1-3bae-4e75-a95d-4309010e03e4.json | Point theme example/theme relationship to Base realm boxel brand guide. |
| packages/catalog-realm/Theme/winter-wonderland.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/modern-blue.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/mint-method.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/luxury-auction.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/literary-review.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/kitchen-editorial.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/funkadelic-fever.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/Theme/cardstack.json | Remove old Theme card JSON (replaced by Base realm brand guide). |
| packages/catalog-realm/Theme/cardstack-brand-guide.json | Remove old Brand Guide theme JSON (now under packages/base/Theme/). |
| packages/catalog-realm/Theme/boxel-brand-guide.json | Remove old Brand Guide theme JSON (now under Base realm). |
| packages/catalog-realm/Theme/botanical.json | Remove theme card JSON (catalog realm cleanup). |
| packages/catalog-realm/SubmissionCardPortal/b535d5fb-8eef-44a6-8114-4bce6929b95a.json | Update theme relationship from in-realm theme to Base realm brand guide. |
| packages/catalog-realm/Statement/theming-system.json | Rewrite theming guidance content + adjust cardInfo metadata. |
| packages/catalog-realm/Spec/skill-set.json | Remove catalog-realm SkillSet spec card (exists under packages/base/cards/skill-set.json). |
| packages/base/cards/skill-plus-markdown.json | Update SkillPlusMarkdown spec metadata/module reference. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "name": "[card title here]", | ||
| "summary": "[brief card description here]", | ||
| "cardThumbnailURL": "[card thumbnail url here]" | ||
| }, |
There was a problem hiding this comment.
The json snippet under “cardInfo properties” is not valid JSON: it has a trailing comma after the cardInfo object and is missing the closing } for the attributes object. Since this is meant to be copy/pasteable, please make the example valid JSON (or change the code fence to a format that allows trailing commas).
| }, | |
| } |
| "name": "[card title here]", | ||
| "summary": "[brief card description here]", | ||
| "cardThumbnailURL": "[card thumbnail url here]" | ||
| }, |
There was a problem hiding this comment.
The json snippet under “cardInfo properties” is not valid JSON: it has a trailing comma after the cardInfo object and is missing the closing } for the attributes object. Since this is meant to be copy/pasteable, please make the example valid JSON (or change the code fence to a format that allows trailing commas).
| }, | |
| } |
| "type": "card", | ||
| "attributes": { | ||
| "content": "# Theming System and CSS Variables\n\nBoxel uses CSS custom properties (variables) for theming. When creating fields, use these variables with appropriate fallbacks that match your field's design system.\n\n## Available Theme Variables\n\n### Shadcn Design System Variables\n\n**Colors:**\n- `--foreground`, `--background`\n- `--primary`, `--primary-foreground`\n- `--secondary`, `--secondary-foreground`\n- `--muted`, `--muted-foreground`\n- `--accent`, `--accent-foreground`\n- `--card`, `--card-foreground`\n- `--popover`, `--popover-foreground`\n- `--destructive`, `--destructive-foreground`\n- `--input`, `--ring`, `--border`\n\n**Charts:** `--chart1`, `--chart2`, `--chart3`, `--chart4`, `--chart5`\n\n**Sidebar:**\n- `--sidebar`, `--sidebar-foreground`\n- `--sidebar-primary`, `--sidebar-primary-foreground`\n- `--sidebar-accent`, `--sidebar-accent-foreground`\n- `--sidebar-border`, `--sidebar-ring`\n\n**Typography:** `--font-sans`, `--font-serif`, `--font-mono`, `--tracking-normal`\n\n**Layout:** `--radius`, `--spacing`\n\n**Shadows:** `--shadow2xs`, `--shadow-xs`, `--shadow-sm`, `--shadow`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`, `--shadow2xl`\n\n### Brand Variables\n\n**Brand Colors:**\n- `--brand-primary`, `--brand-secondary`, `--brand-accent`\n- `--brand-neutral`, `--brand-light`, `--brand-dark`\n- `--brand-border`\n\n**Brand Layout:**\n- `--brand-radius`\n- `--brand-spacing`\n\n**Brand Typography:**\n- `--brand-heading-font-family`, `--brand-heading-font-size`, `--brand-heading-font-weight`, `--brand-heading-line-height`\n- `--brand-body-font-family`, `--brand-body-font-size`, `--brand-body-font-weight`, `--brand-body-line-height`\n\n**Brand Logos & Icons:**\n- Primary Mark: `--brand-primary-mark1`, `--brand-primary-mark2`, `--brand-primary-mark-greyscale1`, `--brand-primary-mark-greyscale2`, `--brand-primary-mark-clearance-ratio`, `--brand-primary-mark-min-height`\n- Secondary Mark: `--brand-secondary-mark1`, `--brand-secondary-mark2`, `--brand-secondary-mark-greyscale1`, `--brand-secondary-mark-greyscale2`, `--brand-secondary-mark-clearance-ratio`, `--brand-secondary-mark-min-height`\n- `--brand-social-media-profile-icon`\n\n### Brand to Shadcn Mapping\n\nThe system automatically maps brand variables to shadcn variables:\n\n```css\n--primary: var(--brand-primary);\n--secondary: var(--brand-secondary);\n--muted: var(--brand-neutral);\n--accent: var(--brand-accent);\n--background: var(--brand-light);\n--foreground: var(--brand-dark);\n--border: var(--brand-border);\n--radius: var(--brand-radius);\n--spacing: calc(var(--brand-spacing) / 4);\n```\n\nForeground colors (`--primary-foreground`, `--secondary-foreground`, `--muted-foreground`, `--accent-foreground`) are automatically determined based on contrast using `--brand-light` and `--brand-dark`.\n\n## Usage Pattern\n\n**Always provide fallbacks matching your field's design:**\n\n```gts\nexport class CustomField extends FieldDef {\n static edit = class Edit extends Component<typeof this> {\n <template>\n <input class=\"custom-input\" type=\"text\" />\n \n <style scoped>\n .custom-input {\n /* Theme variable with design-appropriate fallback */\n background: var(--input, #f5f5f5);\n color: var(--foreground, #1a1a1a);\n border: 1px solid var(--border, #e0e0e0);\n border-radius: var(--radius, 0.375rem);\n padding: calc(var(--spacing, 0.25rem) * 2);\n font-family: var(--font-sans, system-ui, sans-serif);\n }\n \n .custom-input:focus {\n outline: 2px solid var(--ring, #3b82f6);\n outline-offset: 2px;\n }\n \n .custom-input::placeholder {\n color: var(--muted-foreground, #9ca3af);\n }\n </style>\n </template>\n };\n}\n```\n\n## State Examples\n\n**Interactive states:**\n```css\n.button {\n background: var(--primary, #3b82f6);\n color: var(--primary-foreground, #ffffff);\n}\n\n.button:hover {\n background: var(--accent, #60a5fa);\n color: var(--accent-foreground, #1e293b);\n}\n\n.button:disabled {\n background: var(--muted, #f1f5f9);\n color: var(--muted-foreground, #94a3b8);\n opacity: 0.6;\n}\n```\n\n**Error states:**\n```css\n.input-error {\n border-color: var(--destructive, #ef4444);\n}\n\n.error-message {\n color: var(--destructive, #ef4444);\n font-size: 0.875rem;\n}\n```\n\n## Layout Patterns\n\n**Spacing:**\n```css\n.container {\n padding: calc(var(--spacing) * 4); /* 1rem */\n gap: calc(var(--spacing) * 2); /* 0.5rem */\n}\n```\n\n**Shadows:**\n```css\n.card {\n box-shadow: var(--shadow-md, 0 4px 6px -1px rgb(0 0 0 / 0.1));\n}\n\n.elevated {\n box-shadow: var(--shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));\n}\n```\n\n**Charts:**\n```css\n.chart-bar:nth-child(1) { background: var(--chart1, #3b82f6); }\n.chart-bar:nth-child(2) { background: var(--chart2, #10b981); }\n.chart-bar:nth-child(3) { background: var(--chart3, #f59e0b); }\n```\n\n**Brand Typography:**\n```css\n.heading {\n font-family: var(--brand-heading-font-family, var(--font-sans, system-ui));\n font-size: var(--brand-heading-font-size, 2rem);\n font-weight: var(--brand-heading-font-weight, 700);\n line-height: var(--brand-heading-line-height, 1.2);\n}\n\n.body-text {\n font-family: var(--brand-body-font-family, var(--font-sans, system-ui));\n font-size: var(--brand-body-font-size, 1rem);\n font-weight: var(--brand-body-font-weight, 400);\n line-height: var(--brand-body-line-height, 1.5);\n}\n```\n\n## Complete Example\n\n```gts\nimport { FieldDef, Component } from 'https://cardstack.com/base/card-api';\nimport { tracked } from '@glimmer/tracking';\nimport { action } from '@ember/object';\n\nexport class ThemedField extends FieldDef {\n static edit = class Edit extends Component<typeof this> {\n @tracked isOpen = false;\n \n <template>\n <div class=\"field-wrapper\">\n <label>Select Option</label>\n <button class=\"trigger\" {{on \"click\" (fn (mut this.isOpen) (not this.isOpen))}}>\n {{@model.value ?? \"Choose...\"}}\n </button>\n \n {{#if this.isOpen}}\n <div class=\"dropdown\">\n {{#each @model.options as |option|}}\n <button class=\"option\">{{option}}</button>\n {{/each}}\n </div>\n {{/if}}\n </div>\n \n <style scoped>\n .field-wrapper {\n display: flex;\n flex-direction: column;\n gap: calc(var(--spacing) * 2);\n }\n \n label {\n font-family: var(--font-sans, system-ui);\n font-weight: 600;\n font-size: 0.875rem;\n color: var(--foreground, #1a1a1a);\n }\n \n .trigger {\n background: var(--input, #f5f5f5);\n color: var(--foreground, #1a1a1a);\n border: 1px solid var(--border, #e0e0e0);\n border-radius: var(--radius, 0.375rem);\n padding: calc(var(--spacing) * 2);\n cursor: pointer;\n }\n \n .trigger:hover {\n background: var(--accent, #f0f9ff);\n }\n \n .trigger:focus {\n outline: 2px solid var(--ring, #3b82f6);\n outline-offset: 2px;\n }\n \n .dropdown {\n background: var(--popover, #ffffff);\n border: 1px solid var(--border, #e0e0e0);\n border-radius: var(--radius, 0.375rem);\n box-shadow: var(--shadow-lg, 0 10px 15px -3px rgb(0 0 0 / 0.1));\n margin-top: calc(var(--spacing) * 2);\n }\n \n .option {\n width: 100%;\n padding: calc(var(--spacing) * 2);\n background: transparent;\n border: none;\n color: var(--popover-foreground, #1a1a1a);\n text-align: left;\n cursor: pointer;\n }\n \n .option:hover {\n background: var(--accent, #f0f9ff);\n }\n </style>\n </template>\n };\n}\n```\n\n## Key Principles\n\n1. **Always use `var(--variable, fallback)` syntax** - Never use variables without fallbacks\n2. **Choose fallbacks that match your field's design** - Don't copy example values blindly\n3. **Use semantic variable names** - `--primary`, not hard-coded colors\n4. **Respect spacing system** - Use `calc(var(--spacing) * n)` for consistency\n5. **Apply focus states** - Use `--ring` for accessibility\n6. **Test without theme** - Ensure fallbacks create a cohesive design\n7. **Leverage brand variables** - Use brand variables for consistent theming across your application", | ||
| "content": "# Theming System and CSS Variables\n\nBoxel uses CSS custom properties (variables) for theming. When creating fields, use these variables. \n\nFallback values break with dark mode and custom themes. If fallbacks are needed, define them once on the parent container class rather than repeating them throughout child selectors.\n\n- You must link to a `Theme` card (instances of `https://cardstack.com/base/structured-theme` or its subclasses) to see the theming. Default theme to link to:\n\n```json\n\"relationships\": {\n \"cardInfo.theme\": {\n \"links\": {\n \"self\": \"https://cardstack.com/base/Theme/cardstack-brand-guide\"\n }\n }\n}\n```\n\n- Never hardcode colors. Always use CSS custom properties.\n\n**Wrong:**\n```css\nlinear-gradient(180deg, #fef7ed 0%, #fed7aa 100%)\n```\n\n**Correct:**\n```css\nlinear-gradient(180deg, var(--muted) 0%, var(--accent) 100%)\n```\n\n- Do not use rgba() values. Use color-mix() to derive semi-transparent variants from semantic tokens:\n\n- `rgba(255,255,255,0.25)` on primary background → `color-mix(in oklch, var(--primary-foreground) 25%, transparent)`\n\n- Icons and SVGs must not use hardcoded hex fills — use theme color tokens via CSS\n\n## Available Theme Variables\n\n### Shadcn Design System Variables\n\n**Colors:**\n- `--foreground`, `--background`\n- `--primary`, `--primary-foreground`\n- `--secondary`, `--secondary-foreground`\n- `--muted`, `--muted-foreground`\n- `--accent`, `--accent-foreground`\n- `--card`, `--card-foreground`\n- `--popover`, `--popover-foreground`\n- `--destructive`, `--destructive-foreground`\n- `--input`, `--ring`, `--border`\n\n**Charts:** `--chart1`, `--chart2`, `--chart3`, `--chart4`, `--chart5`\n\n**Sidebar:**\n- `--sidebar`, `--sidebar-foreground`\n- `--sidebar-primary`, `--sidebar-primary-foreground`\n- `--sidebar-accent`, `--sidebar-accent-foreground`\n- `--sidebar-border`, `--sidebar-ring`\n\n**Typography:** `--font-sans`, `--font-serif`, `--font-mono`, `--tracking-normal`\n\n#### Note: \n\nFor all cards with Themes linked in their `cardInfo.theme`:\n\n- Font-family defaults to `var(--font-sans, 'IBM Plex, sans-serif)'`\n- Font-size defaults to `var(--boxel-font-size-sm)` which is `0.875rem`\n- Letter-spacing is set to `var(--tracking-normal)`\n- Line-height defaults to `var(--boxel-line-height-sm)` which is `~1.385`\n\n**Layout:** `--radius`, `--spacing`\n\nNote: Radius and spacing are mapped to boxel variables:\n```css\n--boxel-sp: var(calc(--spacing * 4), 1rem);\n/* --boxel-sp-*[6xs to 6xl] recalculated based on Perfect Fourth scale */\n\n--boxel-border-radius: var(--radius, 0.625rem);\n/* --boxel-border-radius-*[xxs to xxl] recalculated accordingly */\n```\n\n**Shadows:** `--shadow2xs`, `--shadow-xs`, `--shadow-sm`, `--shadow`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`, `--shadow2xl`\n\n### Brand Variables\n\n#### Brand Logos & Icons\n\n- Primary Logo (On light background):\n```css\n--brand-primary-mark-1\n--brand-primary-mark-greyscale-1\n```\n- Primary Logo (On dark background):\n```css\n--brand-primary-mark-2\n--brand-primary-mark-greyscale-2\n```\n- Primary logo padding ratio and min-height requirements:\n```css\n--brand-primary-mark-clearance-ratio\n--brand-primary-mark-min-height\n```\n\n- Secondary Logo (On light background):\n```css\n--brand-secondary-mark-1\n--brand-secondary-mark-greyscale-1\n```\n- Secondary Logo (On dark background):\n```css\n--brand-secondary-mark-2\n--brand-secondary-mark-greyscale-2\n```\n- Secondary logo padding ratio and min-height requirements:\n```css\n--brand-secondary-mark-clearance-ratio\n--brand-secondary-mark-min-height\n```\n\n- Social media icon: `--brand-social-media-profile-icon`\n\n#### Brand colors and Brand to Boxel/Shadcn Mapping\n\nAll css variables above are valid and recalculated based on brand values. In addition, brands can define their own custom css variables in the Brand Guide, linked via `cardInfo.theme`.\n\nThe system automatically maps brand variables to shadcn and Boxel variables:\n\n```css\n--primary: var(--brand-primary);\n--secondary: var(--brand-secondary);\n--muted: var(--brand-neutral);\n--accent: var(--brand-accent);\n--background: var(--brand-light);\n--foreground: var(--brand-dark);\n--border: var(--brand-border);\n\n--boxel-border-radius: var(--radius, 0.625rem);\n/* --boxel-border-radius-*[xxs to xxl] recalculated accordingly */\n\n--boxel-sp: var(calc(--spacing * 4), 1rem);\n/* --boxel-sp-*[6xs to 6xl] recalculated based on Perfect Fourth scale */\n\n--boxel-font-size: var(--brand-body-font-size, 0.875rem);\n/* --boxel-font-size-*[2xl to 2xs] recalculated */\n\n/* Heading (h1) */\n--boxel-heading-font-family: var(--brand-heading-font-family, var(--boxel-font-family));\n--boxel-heading-font-size: var(--brand-heading-font-size, var(--boxel-font-size-lg));\n--boxel-heading-font-weight: var(--brand-heading-font-weight, 700);\n--boxel-heading-line-height: var(--brand-heading-line-height, var(--boxel-line-height-lg));\n\n/* Section heading (h2) */\n--boxel-section-heading-font-family: var(--brand-section-heading-font-family, var(--boxel-font-family));\n--boxel-section-heading-font-size: var(--brand-section-heading-font-size, var(--boxel-font-size-md));\n--boxel-section-heading-font-weight: var(--brand-section-heading-font-weight, 500);\n--boxel-section-heading-line-height: var(--brand-section-heading-line-height, var(--boxel-line-height-md));\n\n/* Subheading (h3) */\n--boxel-subheading-font-family: var(--brand-subheading-font-family, var(--boxel-font-family);\n--boxel-subheading-font-size: var(--brand-subheading-font-size, var(--boxel-font-size));\n--boxel-subheading-font-weight: var(--brand-subheading-font-weight, 500);\n--boxel-subheading-line-height: var(--brand-subheading-line-height, var(--boxel-line-height));\n\n/* Body (p) */\n--boxel-body-font-family: var(--brand-body-font-family, var(--boxel-font-family));\n--boxel-body-font-size: var(--brand-body-font-size, var(--boxel-font-size-sm));\n--boxel-body-font-weight: var(--brand-body-font-weight, 400);\n--boxel-body-line-height: var(--brand-body-line-height, var(--boxel-line-height-sm));\n\n/* Caption (small) */\n--boxel-caption-font-family: var(--brand-caption-font-family, var(--boxel-font-family));\n--boxel-caption-font-size: var(--brand-caption-font-size, var(--boxel-font-size-xs));\n--boxel-caption-font-weight: var(--brand-caption-font-weight, 500);\n--boxel-caption-line-height: var(--brand-caption-line-height, var(--boxel-line-height-xs));\n```\n\nIf foreground colors were not manually set, they (`--primary-foreground`, `--secondary-foreground`, `--muted-foreground`, `--accent-foreground`) are automatically determined based on contrast using `--brand-light` and `--brand-dark`.\n\n## Complete Example\n\n```gts\n <template>\n <article class='my-card' aria-labelledby='mc-title'>\n <header class='mc-header'>\n <h1 class='mc-title' id='mc-title'><@fields.cardTitle /></h1>\n <p class='mc-summary'><@fields.cardDescription /></p>\n </header>\n\n <div class='mc-body'>\n <div class='mc-main'>\n <section aria-labelledby='mc-section-1'>\n <h2 class='mc-section-heading' id='mc-section-1'>Section 1 Title</h2>\n <p class='mc-prose'>Paragraph</p>\n <ul class='items-grid'>\n <li class='section-item'>\n <h3 class='item-title'>Item 1</h3>\n <p class='item-content'>Item 1 content</p>\n </li>\n <li class='section-item'>\n <h3 class='item-title'>Item 2</h3>\n <p class='item-content'>Item 2 content</p>\n </li>\n <li class='section-item'>\n <h3 class='item-title'>Item 3</h3>\n <p class='item-content'>Item 3 content</p>\n </li>\n </ul>\n </section>\n <section aria-labelledby='mc-section-2'>\n <h2 class='mc-section-heading' id='mc-section-2'>Section 2 Title</h2>\n <p class='mc-prose'>Paragraph</p>\n </section>\n </div>\n\n <aside class='mc-sidebar'>\n <section\n class='sidebar-section'\n aria-labelledby='sidebar-heading-1'\n >\n <h2 class='sidebar-heading' id='sidebar-heading-1'>Sidebar Title 1</h2>\n <ul class='sidebar-list'>\n <li class='sidebar-item'>\n <span>Sidebar item 1</span>\n </li>\n <li class='sidebar-item'>\n <span>Sidebar item 2</span>\n </li>\n <li class='sidebar-item'>\n <span>Sidebar item 3</span>\n </li>\n </ul>\n </section>\n\n <section\n class='sidebar-section'\n aria-labelledby='sidebar-heading-2'\n >\n <h2 class='sidebar-heading' id='sidebar-heading-2'>Sidebar Title 2</h2>\n <dl class='sidebar-dl'>\n <div class='sidebar-dl-row'>\n <dt>Sidebar item 1</dt>\n <dd>Content</dd>\n </div>\n <div class='sidebar-dl-row'>\n <dt>Sidebar item 2</dt>\n <dd>Content</dd>\n </div>\n </dl>\n </section>\n </aside>\n </div>\n\n <footer class='mc-footer'>\n <p>Footer text</p>\n <nav aria-label='Footer links'>\n <ul class='footer-links'>\n <li><a href='#'>Link 1</a></li>\n <li><a href='#'>Link 2</a></li>\n <li><a href='#'>Link 3</a></li>\n </ul>\n </nav>\n </footer>\n </article>\n <style scoped>\n .my-card {\n container-type: inline-size;\n container-name: mc-container;\n height: 100%;\n overflow-y: auto;\n padding: var(--boxel-sp-xl);\n background-color: var(--background);\n color: var(--foreground);\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-lg);\n box-sizing: border-box;\n }\n\n /* Header */\n .mc-header {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n border-bottom: 1px solid var(--border);\n padding-bottom: var(--boxel-sp-lg);\n }\n .mc-title {\n font-size: var(--boxel-font-size-xl);\n font-weight: 700;\n letter-spacing: var(--boxel-lsp-xs);\n margin: 0;\n }\n .mc-summary {\n font-size: var(--boxel-font-size-sm);\n line-height: var(--boxel-line-height-sm);\n color: var(--muted-foreground);\n margin: 0;\n }\n\n /* Body: main + sidebar */\n .mc-body {\n display: grid;\n grid-template-columns: 1fr 16rem;\n gap: var(--boxel-sp-lg);\n align-items: start;\n }\n\n /* Main column */\n .mc-main {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xl);\n }\n .mc-main section {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-sm);\n }\n .mc-prose {\n font-size: var(--boxel-font-size-sm);\n line-height: var(--boxel-line-height);\n color: var(--foreground);\n margin: 0;\n }\n .mc-section-heading {\n font-size: var(--boxel-font-size-lg);\n font-weight: 600;\n margin: 0;\n }\n\n /* Items grid */\n .items-grid {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));\n gap: var(--boxel-sp);\n }\n .section-item {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n background-color: var(--card);\n color: var(--card-foreground);\n padding: var(--boxel-sp);\n border: 1px solid var(--border);\n border-radius: var(--boxel-border-radius);\n box-shadow: var(--shadow);\n }\n .item-title {\n font-size: var(--boxel-font-size-sm);\n font-weight: 600;\n margin: 0;\n }\n .item-content {\n font-size: var(--boxel-font-size-xs);\n color: var(--muted-foreground);\n margin: 0;\n line-height: var(--boxel-line-height-sm);\n }\n\n /* Sidebar */\n .mc-sidebar {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp);\n background-color: var(--sidebar);\n color: var(--sidebar-foreground);\n border: 1px solid var(--sidebar-border);\n border-radius: var(--boxel-border-radius);\n padding: var(--boxel-sp);\n }\n .sidebar-section {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n }\n .sidebar-section + .sidebar-section {\n border-top: 1px solid var(--sidebar-border);\n padding-top: var(--boxel-sp);\n }\n .sidebar-heading {\n font-size: var(--boxel-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: var(--boxel-lsp-lg);\n margin: 0;\n }\n .sidebar-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-5xs);\n }\n .sidebar-item {\n display: flex;\n align-items: center;\n gap: var(--boxel-sp-5xs);\n font-size: var(--boxel-font-size-sm);\n }\n\n /* Definition list */\n .sidebar-dl {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-5xs);\n margin: 0;\n }\n .sidebar-dl-row {\n display: flex;\n justify-content: space-between;\n font-size: var(--boxel-font-size-xs);\n }\n .sidebar-dl-row dt {\n color: var(--muted-foreground);\n }\n .sidebar-dl-row dd {\n margin: 0;\n font-weight: 500;\n }\n\n /* Footer */\n .mc-footer {\n border-top: 1px solid var(--border);\n padding-top: var(--boxel-sp-sm);\n font-size: var(--boxel-font-size-xs);\n color: var(--muted-foreground);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--boxel-sp-xs);\n }\n .mc-footer p {\n font-size: inherit;\n margin: 0;\n }\n .footer-links {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n align-items: center;\n gap: 0;\n }\n .footer-links li + li::before {\n content: '·';\n margin-inline: var(--boxel-sp-xs);\n }\n .mc-footer a {\n color: var(--muted-foreground);\n text-decoration: underline;\n text-underline-offset: 2px;\n }\n .mc-footer a:hover {\n color: var(--foreground);\n }\n\n /* Responsive: stack on narrow containers */\n @container mc-container (max-width: 600px) {\n .mc-body {\n grid-template-columns: 1fr;\n }\n }\n </style>\n </template>\n```\n\n## Key Principles\n\n1. No hard-coded colors — use CSS custom properties\n2. Respect spacing system — Use `calc(var(--spacing) * n)` or `boxel-sp-* [6xs to 6xl]` for consistency\n3. Always prefer boxel-ui components over raw HTML elements. Read the component API in the monorepo.\n4. No `@import url(...)` inside style tag. Font-families are imported automatically by the linked theme.", |
There was a problem hiding this comment.
The content text includes several CSS snippets that are syntactically invalid and/or don’t match how Boxel derives theme variables. For example, --boxel-sp: var(calc(--spacing * 4), 1rem); is not valid CSS (var() can’t wrap calc() like that, and --spacing needs var(--spacing)), and the --boxel-subheading-font-family example is missing a closing parenthesis. Please update these snippets to reflect the actual mappings used by boxel-ui (e.g., --_theme-spacing: calc(var(--spacing) * 4);, --boxel-spacing: var(--_theme-spacing, ...), --boxel-sp: var(--boxel-spacing)).
| "content": "# Theming System and CSS Variables\n\nBoxel uses CSS custom properties (variables) for theming. When creating fields, use these variables. \n\nFallback values break with dark mode and custom themes. If fallbacks are needed, define them once on the parent container class rather than repeating them throughout child selectors.\n\n- You must link to a `Theme` card (instances of `https://cardstack.com/base/structured-theme` or its subclasses) to see the theming. Default theme to link to:\n\n```json\n\"relationships\": {\n \"cardInfo.theme\": {\n \"links\": {\n \"self\": \"https://cardstack.com/base/Theme/cardstack-brand-guide\"\n }\n }\n}\n```\n\n- Never hardcode colors. Always use CSS custom properties.\n\n**Wrong:**\n```css\nlinear-gradient(180deg, #fef7ed 0%, #fed7aa 100%)\n```\n\n**Correct:**\n```css\nlinear-gradient(180deg, var(--muted) 0%, var(--accent) 100%)\n```\n\n- Do not use rgba() values. Use color-mix() to derive semi-transparent variants from semantic tokens:\n\n- `rgba(255,255,255,0.25)` on primary background → `color-mix(in oklch, var(--primary-foreground) 25%, transparent)`\n\n- Icons and SVGs must not use hardcoded hex fills — use theme color tokens via CSS\n\n## Available Theme Variables\n\n### Shadcn Design System Variables\n\n**Colors:**\n- `--foreground`, `--background`\n- `--primary`, `--primary-foreground`\n- `--secondary`, `--secondary-foreground`\n- `--muted`, `--muted-foreground`\n- `--accent`, `--accent-foreground`\n- `--card`, `--card-foreground`\n- `--popover`, `--popover-foreground`\n- `--destructive`, `--destructive-foreground`\n- `--input`, `--ring`, `--border`\n\n**Charts:** `--chart1`, `--chart2`, `--chart3`, `--chart4`, `--chart5`\n\n**Sidebar:**\n- `--sidebar`, `--sidebar-foreground`\n- `--sidebar-primary`, `--sidebar-primary-foreground`\n- `--sidebar-accent`, `--sidebar-accent-foreground`\n- `--sidebar-border`, `--sidebar-ring`\n\n**Typography:** `--font-sans`, `--font-serif`, `--font-mono`, `--tracking-normal`\n\n#### Note: \n\nFor all cards with Themes linked in their `cardInfo.theme`:\n\n- Font-family defaults to `var(--font-sans, 'IBM Plex, sans-serif)'`\n- Font-size defaults to `var(--boxel-font-size-sm)` which is `0.875rem`\n- Letter-spacing is set to `var(--tracking-normal)`\n- Line-height defaults to `var(--boxel-line-height-sm)` which is `~1.385`\n\n**Layout:** `--radius`, `--spacing`\n\nNote: Radius and spacing are mapped to boxel variables:\n```css\n--boxel-sp: var(calc(--spacing * 4), 1rem);\n/* --boxel-sp-*[6xs to 6xl] recalculated based on Perfect Fourth scale */\n\n--boxel-border-radius: var(--radius, 0.625rem);\n/* --boxel-border-radius-*[xxs to xxl] recalculated accordingly */\n```\n\n**Shadows:** `--shadow2xs`, `--shadow-xs`, `--shadow-sm`, `--shadow`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`, `--shadow2xl`\n\n### Brand Variables\n\n#### Brand Logos & Icons\n\n- Primary Logo (On light background):\n```css\n--brand-primary-mark-1\n--brand-primary-mark-greyscale-1\n```\n- Primary Logo (On dark background):\n```css\n--brand-primary-mark-2\n--brand-primary-mark-greyscale-2\n```\n- Primary logo padding ratio and min-height requirements:\n```css\n--brand-primary-mark-clearance-ratio\n--brand-primary-mark-min-height\n```\n\n- Secondary Logo (On light background):\n```css\n--brand-secondary-mark-1\n--brand-secondary-mark-greyscale-1\n```\n- Secondary Logo (On dark background):\n```css\n--brand-secondary-mark-2\n--brand-secondary-mark-greyscale-2\n```\n- Secondary logo padding ratio and min-height requirements:\n```css\n--brand-secondary-mark-clearance-ratio\n--brand-secondary-mark-min-height\n```\n\n- Social media icon: `--brand-social-media-profile-icon`\n\n#### Brand colors and Brand to Boxel/Shadcn Mapping\n\nAll css variables above are valid and recalculated based on brand values. In addition, brands can define their own custom css variables in the Brand Guide, linked via `cardInfo.theme`.\n\nThe system automatically maps brand variables to shadcn and Boxel variables:\n\n```css\n--primary: var(--brand-primary);\n--secondary: var(--brand-secondary);\n--muted: var(--brand-neutral);\n--accent: var(--brand-accent);\n--background: var(--brand-light);\n--foreground: var(--brand-dark);\n--border: var(--brand-border);\n\n--boxel-border-radius: var(--radius, 0.625rem);\n/* --boxel-border-radius-*[xxs to xxl] recalculated accordingly */\n\n--boxel-sp: var(calc(--spacing * 4), 1rem);\n/* --boxel-sp-*[6xs to 6xl] recalculated based on Perfect Fourth scale */\n\n--boxel-font-size: var(--brand-body-font-size, 0.875rem);\n/* --boxel-font-size-*[2xl to 2xs] recalculated */\n\n/* Heading (h1) */\n--boxel-heading-font-family: var(--brand-heading-font-family, var(--boxel-font-family));\n--boxel-heading-font-size: var(--brand-heading-font-size, var(--boxel-font-size-lg));\n--boxel-heading-font-weight: var(--brand-heading-font-weight, 700);\n--boxel-heading-line-height: var(--brand-heading-line-height, var(--boxel-line-height-lg));\n\n/* Section heading (h2) */\n--boxel-section-heading-font-family: var(--brand-section-heading-font-family, var(--boxel-font-family));\n--boxel-section-heading-font-size: var(--brand-section-heading-font-size, var(--boxel-font-size-md));\n--boxel-section-heading-font-weight: var(--brand-section-heading-font-weight, 500);\n--boxel-section-heading-line-height: var(--brand-section-heading-line-height, var(--boxel-line-height-md));\n\n/* Subheading (h3) */\n--boxel-subheading-font-family: var(--brand-subheading-font-family, var(--boxel-font-family);\n--boxel-subheading-font-size: var(--brand-subheading-font-size, var(--boxel-font-size));\n--boxel-subheading-font-weight: var(--brand-subheading-font-weight, 500);\n--boxel-subheading-line-height: var(--brand-subheading-line-height, var(--boxel-line-height));\n\n/* Body (p) */\n--boxel-body-font-family: var(--brand-body-font-family, var(--boxel-font-family));\n--boxel-body-font-size: var(--brand-body-font-size, var(--boxel-font-size-sm));\n--boxel-body-font-weight: var(--brand-body-font-weight, 400);\n--boxel-body-line-height: var(--brand-body-line-height, var(--boxel-line-height-sm));\n\n/* Caption (small) */\n--boxel-caption-font-family: var(--brand-caption-font-family, var(--boxel-font-family));\n--boxel-caption-font-size: var(--brand-caption-font-size, var(--boxel-font-size-xs));\n--boxel-caption-font-weight: var(--brand-caption-font-weight, 500);\n--boxel-caption-line-height: var(--brand-caption-line-height, var(--boxel-line-height-xs));\n```\n\nIf foreground colors were not manually set, they (`--primary-foreground`, `--secondary-foreground`, `--muted-foreground`, `--accent-foreground`) are automatically determined based on contrast using `--brand-light` and `--brand-dark`.\n\n## Complete Example\n\n```gts\n <template>\n <article class='my-card' aria-labelledby='mc-title'>\n <header class='mc-header'>\n <h1 class='mc-title' id='mc-title'><@fields.cardTitle /></h1>\n <p class='mc-summary'><@fields.cardDescription /></p>\n </header>\n\n <div class='mc-body'>\n <div class='mc-main'>\n <section aria-labelledby='mc-section-1'>\n <h2 class='mc-section-heading' id='mc-section-1'>Section 1 Title</h2>\n <p class='mc-prose'>Paragraph</p>\n <ul class='items-grid'>\n <li class='section-item'>\n <h3 class='item-title'>Item 1</h3>\n <p class='item-content'>Item 1 content</p>\n </li>\n <li class='section-item'>\n <h3 class='item-title'>Item 2</h3>\n <p class='item-content'>Item 2 content</p>\n </li>\n <li class='section-item'>\n <h3 class='item-title'>Item 3</h3>\n <p class='item-content'>Item 3 content</p>\n </li>\n </ul>\n </section>\n <section aria-labelledby='mc-section-2'>\n <h2 class='mc-section-heading' id='mc-section-2'>Section 2 Title</h2>\n <p class='mc-prose'>Paragraph</p>\n </section>\n </div>\n\n <aside class='mc-sidebar'>\n <section\n class='sidebar-section'\n aria-labelledby='sidebar-heading-1'\n >\n <h2 class='sidebar-heading' id='sidebar-heading-1'>Sidebar Title 1</h2>\n <ul class='sidebar-list'>\n <li class='sidebar-item'>\n <span>Sidebar item 1</span>\n </li>\n <li class='sidebar-item'>\n <span>Sidebar item 2</span>\n </li>\n <li class='sidebar-item'>\n <span>Sidebar item 3</span>\n </li>\n </ul>\n </section>\n\n <section\n class='sidebar-section'\n aria-labelledby='sidebar-heading-2'\n >\n <h2 class='sidebar-heading' id='sidebar-heading-2'>Sidebar Title 2</h2>\n <dl class='sidebar-dl'>\n <div class='sidebar-dl-row'>\n <dt>Sidebar item 1</dt>\n <dd>Content</dd>\n </div>\n <div class='sidebar-dl-row'>\n <dt>Sidebar item 2</dt>\n <dd>Content</dd>\n </div>\n </dl>\n </section>\n </aside>\n </div>\n\n <footer class='mc-footer'>\n <p>Footer text</p>\n <nav aria-label='Footer links'>\n <ul class='footer-links'>\n <li><a href='#'>Link 1</a></li>\n <li><a href='#'>Link 2</a></li>\n <li><a href='#'>Link 3</a></li>\n </ul>\n </nav>\n </footer>\n </article>\n <style scoped>\n .my-card {\n container-type: inline-size;\n container-name: mc-container;\n height: 100%;\n overflow-y: auto;\n padding: var(--boxel-sp-xl);\n background-color: var(--background);\n color: var(--foreground);\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-lg);\n box-sizing: border-box;\n }\n\n /* Header */\n .mc-header {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n border-bottom: 1px solid var(--border);\n padding-bottom: var(--boxel-sp-lg);\n }\n .mc-title {\n font-size: var(--boxel-font-size-xl);\n font-weight: 700;\n letter-spacing: var(--boxel-lsp-xs);\n margin: 0;\n }\n .mc-summary {\n font-size: var(--boxel-font-size-sm);\n line-height: var(--boxel-line-height-sm);\n color: var(--muted-foreground);\n margin: 0;\n }\n\n /* Body: main + sidebar */\n .mc-body {\n display: grid;\n grid-template-columns: 1fr 16rem;\n gap: var(--boxel-sp-lg);\n align-items: start;\n }\n\n /* Main column */\n .mc-main {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xl);\n }\n .mc-main section {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-sm);\n }\n .mc-prose {\n font-size: var(--boxel-font-size-sm);\n line-height: var(--boxel-line-height);\n color: var(--foreground);\n margin: 0;\n }\n .mc-section-heading {\n font-size: var(--boxel-font-size-lg);\n font-weight: 600;\n margin: 0;\n }\n\n /* Items grid */\n .items-grid {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));\n gap: var(--boxel-sp);\n }\n .section-item {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n background-color: var(--card);\n color: var(--card-foreground);\n padding: var(--boxel-sp);\n border: 1px solid var(--border);\n border-radius: var(--boxel-border-radius);\n box-shadow: var(--shadow);\n }\n .item-title {\n font-size: var(--boxel-font-size-sm);\n font-weight: 600;\n margin: 0;\n }\n .item-content {\n font-size: var(--boxel-font-size-xs);\n color: var(--muted-foreground);\n margin: 0;\n line-height: var(--boxel-line-height-sm);\n }\n\n /* Sidebar */\n .mc-sidebar {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp);\n background-color: var(--sidebar);\n color: var(--sidebar-foreground);\n border: 1px solid var(--sidebar-border);\n border-radius: var(--boxel-border-radius);\n padding: var(--boxel-sp);\n }\n .sidebar-section {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n }\n .sidebar-section + .sidebar-section {\n border-top: 1px solid var(--sidebar-border);\n padding-top: var(--boxel-sp);\n }\n .sidebar-heading {\n font-size: var(--boxel-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: var(--boxel-lsp-lg);\n margin: 0;\n }\n .sidebar-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-5xs);\n }\n .sidebar-item {\n display: flex;\n align-items: center;\n gap: var(--boxel-sp-5xs);\n font-size: var(--boxel-font-size-sm);\n }\n\n /* Definition list */\n .sidebar-dl {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-5xs);\n margin: 0;\n }\n .sidebar-dl-row {\n display: flex;\n justify-content: space-between;\n font-size: var(--boxel-font-size-xs);\n }\n .sidebar-dl-row dt {\n color: var(--muted-foreground);\n }\n .sidebar-dl-row dd {\n margin: 0;\n font-weight: 500;\n }\n\n /* Footer */\n .mc-footer {\n border-top: 1px solid var(--border);\n padding-top: var(--boxel-sp-sm);\n font-size: var(--boxel-font-size-xs);\n color: var(--muted-foreground);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--boxel-sp-xs);\n }\n .mc-footer p {\n font-size: inherit;\n margin: 0;\n }\n .footer-links {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n align-items: center;\n gap: 0;\n }\n .footer-links li + li::before {\n content: '·';\n margin-inline: var(--boxel-sp-xs);\n }\n .mc-footer a {\n color: var(--muted-foreground);\n text-decoration: underline;\n text-underline-offset: 2px;\n }\n .mc-footer a:hover {\n color: var(--foreground);\n }\n\n /* Responsive: stack on narrow containers */\n @container mc-container (max-width: 600px) {\n .mc-body {\n grid-template-columns: 1fr;\n }\n }\n </style>\n </template>\n```\n\n## Key Principles\n\n1. No hard-coded colors — use CSS custom properties\n2. Respect spacing system — Use `calc(var(--spacing) * n)` or `boxel-sp-* [6xs to 6xl]` for consistency\n3. Always prefer boxel-ui components over raw HTML elements. Read the component API in the monorepo.\n4. No `@import url(...)` inside style tag. Font-families are imported automatically by the linked theme.", | |
| "content": "# Theming System and CSS Variables\n\nBoxel uses CSS custom properties (variables) for theming. When creating fields, use these variables. \n\nFallback values break with dark mode and custom themes. If fallbacks are needed, define them once on the parent container class rather than repeating them throughout child selectors.\n\n- You must link to a `Theme` card (instances of `https://cardstack.com/base/structured-theme` or its subclasses) to see the theming. Default theme to link to:\n\n```json\n\"relationships\": {\n \"cardInfo.theme\": {\n \"links\": {\n \"self\": \"https://cardstack.com/base/Theme/cardstack-brand-guide\"\n }\n }\n}\n```\n\n- Never hardcode colors. Always use CSS custom properties.\n\n**Wrong:**\n```css\nlinear-gradient(180deg, #fef7ed 0%, #fed7aa 100%)\n```\n\n**Correct:**\n```css\nlinear-gradient(180deg, var(--muted) 0%, var(--accent) 100%)\n```\n\n- Do not use rgba() values. Use color-mix() to derive semi-transparent variants from semantic tokens:\n\n- `rgba(255,255,255,0.25)` on primary background → `color-mix(in oklch, var(--primary-foreground) 25%, transparent)`\n\n- Icons and SVGs must not use hardcoded hex fills — use theme color tokens via CSS\n\n## Available Theme Variables\n\n### Shadcn Design System Variables\n\n**Colors:**\n- `--foreground`, `--background`\n- `--primary`, `--primary-foreground`\n- `--secondary`, `--secondary-foreground`\n- `--muted`, `--muted-foreground`\n- `--accent`, `--accent-foreground`\n- `--card`, `--card-foreground`\n- `--popover`, `--popover-foreground`\n- `--destructive`, `--destructive-foreground`\n- `--input`, `--ring`, `--border`\n\n**Charts:** `--chart1`, `--chart2`, `--chart3`, `--chart4`, `--chart5`\n\n**Sidebar:**\n- `--sidebar`, `--sidebar-foreground`\n- `--sidebar-primary`, `--sidebar-primary-foreground`\n- `--sidebar-accent`, `--sidebar-accent-foreground`\n- `--sidebar-border`, `--sidebar-ring`\n\n**Typography:** `--font-sans`, `--font-serif`, `--font-mono`, `--tracking-normal`\n\n#### Note: \n\nFor all cards with Themes linked in their `cardInfo.theme`:\n\n- Font-family defaults to `var(--font-sans, 'IBM Plex, sans-serif')`\n- Font-size defaults to `var(--boxel-font-size-sm)` which is `0.875rem`\n- Letter-spacing is set to `var(--tracking-normal)`\n- Line-height defaults to `var(--boxel-line-height-sm)` which is `~1.385`\n\n**Layout:** `--radius`, `--spacing`\n\nNote: Radius and spacing are mapped to boxel variables:\n```css\n--_theme-spacing: calc(var(--spacing) * 4);\n--boxel-spacing: var(--_theme-spacing, 1rem);\n--boxel-sp: var(--boxel-spacing);\n/* --boxel-sp-*[6xs to 6xl] recalculated based on Perfect Fourth scale */\n\n--boxel-border-radius: var(--radius, 0.625rem);\n/* --boxel-border-radius-*[xxs to xxl] recalculated accordingly */\n```\n\n**Shadows:** `--shadow2xs`, `--shadow-xs`, `--shadow-sm`, `--shadow`, `--shadow-md`, `--shadow-lg`, `--shadow-xl`, `--shadow2xl`\n\n### Brand Variables\n\n#### Brand Logos & Icons\n\n- Primary Logo (On light background):\n```css\n--brand-primary-mark-1\n--brand-primary-mark-greyscale-1\n```\n- Primary Logo (On dark background):\n```css\n--brand-primary-mark-2\n--brand-primary-mark-greyscale-2\n```\n- Primary logo padding ratio and min-height requirements:\n```css\n--brand-primary-mark-clearance-ratio\n--brand-primary-mark-min-height\n```\n\n- Secondary Logo (On light background):\n```css\n--brand-secondary-mark-1\n--brand-secondary-mark-greyscale-1\n```\n- Secondary Logo (On dark background):\n```css\n--brand-secondary-mark-2\n--brand-secondary-mark-greyscale-2\n```\n- Secondary logo padding ratio and min-height requirements:\n```css\n--brand-secondary-mark-clearance-ratio\n--brand-secondary-mark-min-height\n```\n\n- Social media icon: `--brand-social-media-profile-icon`\n\n#### Brand colors and Brand to Boxel/Shadcn Mapping\n\nAll css variables above are valid and recalculated based on brand values. In addition, brands can define their own custom css variables in the Brand Guide, linked via `cardInfo.theme`.\n\nThe system automatically maps brand variables to shadcn and Boxel variables:\n\n```css\n--primary: var(--brand-primary);\n--secondary: var(--brand-secondary);\n--muted: var(--brand-neutral);\n--accent: var(--brand-accent);\n--background: var(--brand-light);\n--foreground: var(--brand-dark);\n--border: var(--brand-border);\n\n--boxel-border-radius: var(--radius, 0.625rem);\n/* --boxel-border-radius-*[xxs to xxl] recalculated accordingly */\n\n--_theme-spacing: calc(var(--spacing) * 4);\n--boxel-spacing: var(--_theme-spacing, 1rem);\n--boxel-sp: var(--boxel-spacing);\n/* --boxel-sp-*[6xs to 6xl] recalculated based on Perfect Fourth scale */\n\n--boxel-font-size: var(--brand-body-font-size, 0.875rem);\n/* --boxel-font-size-*[2xl to 2xs] recalculated */\n\n/* Heading (h1) */\n--boxel-heading-font-family: var(--brand-heading-font-family, var(--boxel-font-family));\n--boxel-heading-font-size: var(--brand-heading-font-size, var(--boxel-font-size-lg));\n--boxel-heading-font-weight: var(--brand-heading-font-weight, 700);\n--boxel-heading-line-height: var(--brand-heading-line-height, var(--boxel-line-height-lg));\n\n/* Section heading (h2) */\n--boxel-section-heading-font-family: var(--brand-section-heading-font-family, var(--boxel-font-family));\n--boxel-section-heading-font-size: var(--brand-section-heading-font-size, var(--boxel-font-size-md));\n--boxel-section-heading-font-weight: var(--brand-section-heading-font-weight, 500);\n--boxel-section-heading-line-height: var(--brand-section-heading-line-height, var(--boxel-line-height-md));\n\n/* Subheading (h3) */\n--boxel-subheading-font-family: var(--brand-subheading-font-family, var(--boxel-font-family));\n--boxel-subheading-font-size: var(--brand-subheading-font-size, var(--boxel-font-size));\n--boxel-subheading-font-weight: var(--brand-subheading-font-weight, 500);\n--boxel-subheading-line-height: var(--brand-subheading-line-height, var(--boxel-line-height));\n\n/* Body (p) */\n--boxel-body-font-family: var(--brand-body-font-family, var(--boxel-font-family));\n--boxel-body-font-size: var(--brand-body-font-size, var(--boxel-font-size-sm));\n--boxel-body-font-weight: var(--brand-body-font-weight, 400);\n--boxel-body-line-height: var(--brand-body-line-height, var(--boxel-line-height-sm));\n\n/* Caption (small) */\n--boxel-caption-font-family: var(--brand-caption-font-family, var(--boxel-font-family));\n--boxel-caption-font-size: var(--brand-caption-font-size, var(--boxel-font-size-xs));\n--boxel-caption-font-weight: var(--brand-caption-font-weight, 500);\n--boxel-caption-line-height: var(--brand-caption-line-height, var(--boxel-line-height-xs));\n```\n\nIf foreground colors were not manually set, they (`--primary-foreground`, `--secondary-foreground`, `--muted-foreground`, `--accent-foreground`) are automatically determined based on contrast using `--brand-light` and `--brand-dark`.\n\n## Complete Example\n\n```gts\n <template>\n <article class='my-card' aria-labelledby='mc-title'>\n <header class='mc-header'>\n <h1 class='mc-title' id='mc-title'><@fields.cardTitle /></h1>\n <p class='mc-summary'><@fields.cardDescription /></p>\n </header>\n\n <div class='mc-body'>\n <div class='mc-main'>\n <section aria-labelledby='mc-section-1'>\n <h2 class='mc-section-heading' id='mc-section-1'>Section 1 Title</h2>\n <p class='mc-prose'>Paragraph</p>\n <ul class='items-grid'>\n <li class='section-item'>\n <h3 class='item-title'>Item 1</h3>\n <p class='item-content'>Item 1 content</p>\n </li>\n <li class='section-item'>\n <h3 class='item-title'>Item 2</h3>\n <p class='item-content'>Item 2 content</p>\n </li>\n <li class='section-item'>\n <h3 class='item-title'>Item 3</h3>\n <p class='item-content'>Item 3 content</p>\n </li>\n </ul>\n </section>\n <section aria-labelledby='mc-section-2'>\n <h2 class='mc-section-heading' id='mc-section-2'>Section 2 Title</h2>\n <p class='mc-prose'>Paragraph</p>\n </section>\n </div>\n\n <aside class='mc-sidebar'>\n <section\n class='sidebar-section'\n aria-labelledby='sidebar-heading-1'\n >\n <h2 class='sidebar-heading' id='sidebar-heading-1'>Sidebar Title 1</h2>\n <ul class='sidebar-list'>\n <li class='sidebar-item'>\n <span>Sidebar item 1</span>\n </li>\n <li class='sidebar-item'>\n <span>Sidebar item 2</span>\n </li>\n <li class='sidebar-item'>\n <span>Sidebar item 3</span>\n </li>\n </ul>\n </section>\n\n <section\n class='sidebar-section'\n aria-labelledby='sidebar-heading-2'\n >\n <h2 class='sidebar-heading' id='sidebar-heading-2'>Sidebar Title 2</h2>\n <dl class='sidebar-dl'>\n <div class='sidebar-dl-row'>\n <dt>Sidebar item 1</dt>\n <dd>Content</dd>\n </div>\n <div class='sidebar-dl-row'>\n <dt>Sidebar item 2</dt>\n <dd>Content</dd>\n </div>\n </dl>\n </section>\n </aside>\n </div>\n\n <footer class='mc-footer'>\n <p>Footer text</p>\n <nav aria-label='Footer links'>\n <ul class='footer-links'>\n <li><a href='#'>Link 1</a></li>\n <li><a href='#'>Link 2</a></li>\n <li><a href='#'>Link 3</a></li>\n </ul>\n </nav>\n </footer>\n </article>\n <style scoped>\n .my-card {\n container-type: inline-size;\n container-name: mc-container;\n height: 100%;\n overflow-y: auto;\n padding: var(--boxel-sp-xl);\n background-color: var(--background);\n color: var(--foreground);\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-lg);\n box-sizing: border-box;\n }\n\n /* Header */\n .mc-header {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n border-bottom: 1px solid var(--border);\n padding-bottom: var(--boxel-sp-lg);\n }\n .mc-title {\n font-size: var(--boxel-font-size-xl);\n font-weight: 700;\n letter-spacing: var(--boxel-lsp-xs);\n margin: 0;\n }\n .mc-summary {\n font-size: var(--boxel-font-size-sm);\n line-height: var(--boxel-line-height-sm);\n color: var(--muted-foreground);\n margin: 0;\n }\n\n /* Body: main + sidebar */\n .mc-body {\n display: grid;\n grid-template-columns: 1fr 16rem;\n gap: var(--boxel-sp-lg);\n align-items: start;\n }\n\n /* Main column */\n .mc-main {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xl);\n }\n .mc-main section {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-sm);\n }\n .mc-prose {\n font-size: var(--boxel-font-size-sm);\n line-height: var(--boxel-line-height);\n color: var(--foreground);\n margin: 0;\n }\n .mc-section-heading {\n font-size: var(--boxel-font-size-lg);\n font-weight: 600;\n margin: 0;\n }\n\n /* Items grid */\n .items-grid {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));\n gap: var(--boxel-sp);\n }\n .section-item {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n background-color: var(--card);\n color: var(--card-foreground);\n padding: var(--boxel-sp);\n border: 1px solid var(--border);\n border-radius: var(--boxel-border-radius);\n box-shadow: var(--shadow);\n }\n .item-title {\n font-size: var(--boxel-font-size-sm);\n font-weight: 600;\n margin: 0;\n }\n .item-content {\n font-size: var(--boxel-font-size-xs);\n color: var(--muted-foreground);\n margin: 0;\n line-height: var(--boxel-line-height-sm);\n }\n\n /* Sidebar */\n .mc-sidebar {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp);\n background-color: var(--sidebar);\n color: var(--sidebar-foreground);\n border: 1px solid var(--sidebar-border);\n border-radius: var(--boxel-border-radius);\n padding: var(--boxel-sp);\n }\n .sidebar-section {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-xs);\n }\n .sidebar-section + .sidebar-section {\n border-top: 1px solid var(--sidebar-border);\n padding-top: var(--boxel-sp);\n }\n .sidebar-heading {\n font-size: var(--boxel-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: var(--boxel-lsp-lg);\n margin: 0;\n }\n .sidebar-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-5xs);\n }\n .sidebar-item {\n display: flex;\n align-items: center;\n gap: var(--boxel-sp-5xs);\n font-size: var(--boxel-font-size-sm);\n }\n\n /* Definition list */\n .sidebar-dl {\n display: flex;\n flex-direction: column;\n gap: var(--boxel-sp-5xs);\n margin: 0;\n }\n .sidebar-dl-row {\n display: flex;\n justify-content: space-between;\n font-size: var(--boxel-font-size-xs);\n }\n .sidebar-dl-row dt {\n color: var(--muted-foreground);\n }\n .sidebar-dl-row dd {\n margin: 0;\n font-weight: 500;\n }\n\n /* Footer */\n .mc-footer {\n border-top: 1px solid var(--border);\n padding-top: var(--boxel-sp-sm);\n font-size: var(--boxel-font-size-xs);\n color: var(--muted-foreground);\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: var(--boxel-sp-xs);\n }\n .mc-footer p {\n font-size: inherit;\n margin: 0;\n }\n .footer-links {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n align-items: center;\n gap: 0;\n }\n .footer-links li + li::before {\n content: '·';\n margin-inline: var(--boxel-sp-xs);\n }\n .mc-footer a {\n color: var(--muted-foreground);\n text-decoration: underline;\n text-underline-offset: 2px;\n }\n .mc-footer a:hover {\n color: var(--foreground);\n }\n\n /* Responsive: stack on narrow containers */\n @container mc-container (max-width: 600px) {\n .mc-body {\n grid-template-columns: 1fr;\n }\n }\n </style>\n </template>\n```\n\n## Key Principles\n\n1. No hard-coded colors — use CSS custom properties\n2. Respect spacing system — Use `calc(var(--spacing) * n)` or `boxel-sp-* [6xs to 6xl]` for consistency\n3. Always prefer boxel-ui components over raw HTML elements. Read the component API in the monorepo.\n4. No `@import url(...)` inside style tag. Font-families are imported automatically by the linked theme.", |
| "position": { | ||
| "type": null, | ||
| "referenceId": null | ||
| "referenceId": "" |
There was a problem hiding this comment.
position.referenceId is set to an empty string here, but other Statement cards in this repo consistently use null when there is no reference id. If the intent is “no reference id”, please keep this as null to avoid treating the empty string as a meaningful identifier.
| "referenceId": "" | |
| "referenceId": null |
No description provided.