Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions skills/brainstorming/scripts/frame-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,82 @@
}
.mockup-body { padding: 1.5rem; }

/* ===== CONTRAST HELPERS ===== */
/*
* Fragment screens inherit this frame's OS-aware color scheme. In dark
* mode, light mockup regions need explicit foreground colors or their text
* can become unreadable. Prefer adding .light-surface or .dark-surface to
* preview regions with custom backgrounds.
*/
.light-surface {
background: #ffffff;
color: #1d1d1f;
}
.light-surface h1,
.light-surface h2,
.light-surface h3,
.light-surface h4,
.light-surface p,
.light-surface span,
.light-surface li,
.light-surface strong,
.light-surface em,
.light-surface code {
color: inherit;
}
.light-surface .label {
color: #6e6e73;
}
.dark-surface {
background: #1d1d1f;
color: #f5f5f7;
}
.dark-surface h1,
.dark-surface h2,
.dark-surface h3,
.dark-surface h4,
.dark-surface p,
.dark-surface span,
.dark-surface li,
.dark-surface strong,
.dark-surface em,
.dark-surface code {
color: inherit;
}
.dark-surface .label {
color: #aeaeb2;
}

/*
* Fallback for common inline light backgrounds in quick fragments. This
* intentionally avoids buttons and inputs, so deliberately styled controls
* keep their own foreground colors.
*/
#claude-content [style*="background:#fff"],
#claude-content [style*="background: #fff"],
#claude-content [style*="background:#ffffff"],
#claude-content [style*="background: #ffffff"],
#claude-content [style*="background:white"],
#claude-content [style*="background: white"] {
color: #1d1d1f;
}
#claude-content [style*="background:#fff"] :is(h1, h2, h3, h4, p, span, li, strong, em, code),
#claude-content [style*="background: #fff"] :is(h1, h2, h3, h4, p, span, li, strong, em, code),
#claude-content [style*="background:#ffffff"] :is(h1, h2, h3, h4, p, span, li, strong, em, code),
#claude-content [style*="background: #ffffff"] :is(h1, h2, h3, h4, p, span, li, strong, em, code),
#claude-content [style*="background:white"] :is(h1, h2, h3, h4, p, span, li, strong, em, code),
#claude-content [style*="background: white"] :is(h1, h2, h3, h4, p, span, li, strong, em, code) {
color: inherit;
}
#claude-content [style*="background:#fff"] .label,
#claude-content [style*="background: #fff"] .label,
#claude-content [style*="background:#ffffff"] .label,
#claude-content [style*="background: #ffffff"] .label,
#claude-content [style*="background:white"] .label,
#claude-content [style*="background: white"] .label {
color: #6e6e73;
}

/* ===== SPLIT VIEW (side-by-side comparison) ===== */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
@media (max-width: 700px) { .split { grid-template-columns: 1fr; } }
Expand Down
21 changes: 21 additions & 0 deletions skills/brainstorming/visual-companion.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,27 @@ The frame template provides these CSS classes for your content:
</div>
```

### Contrast helpers

The companion frame follows the user's OS light/dark mode. When a fragment includes
mockup regions with custom backgrounds, mark them explicitly so foreground text stays
readable:

```html
<div class="mockup-body light-surface">
<h3>White preview area</h3>
<p>Dark readable text inside a light mockup.</p>
</div>

<div class="mockup-body dark-surface">
<h3>Dark preview area</h3>
<p>Light readable text inside a dark mockup.</p>
</div>
```

For complex screens with many custom colors, write a full HTML document instead of a
fragment so the screen can own its complete palette.

### Split view (side-by-side)

```html
Expand Down
11 changes: 11 additions & 0 deletions tests/brainstorm-server/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ async function runTests() {
assert(res.body.includes('data-choice="a"'), 'Fragment interactive elements intact');
});

await test('frame template includes contrast helpers for custom mockup surfaces', async () => {
const fragment = '<div class="mockup-body light-surface"><h2>Light panel</h2><p>Readable copy</p></div>';
fs.writeFileSync(path.join(CONTENT_DIR, 'contrast-fragment.html'), fragment);
await sleep(300);

const res = await fetch(`http://localhost:${TEST_PORT}/`);
assert(res.body.includes('.light-surface'), 'Frame should include light surface helper CSS');
assert(res.body.includes('.dark-surface'), 'Frame should include dark surface helper CSS');
assert(res.body.includes('Light panel'), 'Fragment content should be present');
});

await test('serves newest file by mtime', async () => {
fs.writeFileSync(path.join(CONTENT_DIR, 'older.html'), '<h2>Older</h2>');
await sleep(100);
Expand Down