How Shared CSS Architecture Became Infrastructure That Scales
By: Jeremy (TPM discovering design systems are engineering problems)
Here’s something I learned building VoiceCatcher: Design systems aren’t just visual guidelines—they’re technical infrastructure that determines what user experiences are possible.
When we needed to add a popup history window, I thought the challenge would be window management and IPC communication. The real challenge turned out to be maintaining visual consistency across multiple windows. This is the story of how a “simple” design decision became a foundational architecture choice, and why every pixel consistency decision is actually a scalability decision.
The Setup: When One Window Becomes Two
Context: We’d built a beautiful main interface with a carefully crafted neumorphic design system—soft shadows, subtle gradients, tactile button interactions. Everything looked cohesive and professional.
Then we added the popup history window.
Suddenly we had two completely separate HTML documents that needed to feel like parts of the same application. The technical question wasn’t “how do we open a window?” but “how do we maintain design consistency across separate rendering contexts?”
As a TPM, my first instinct was: “Just copy the CSS classes you need.”
That instinct was completely wrong.
The Problem: CSS Doesn’t Scale Across Windows
Attempt 1: Copy-Paste CSS
The approach: Copy the specific CSS classes we needed from the main app to the history window.
/* Copied to history-window.html */
.neumorphic-button {
background: #f0f4f8;
border-radius: 12px;
box-shadow:
8px 8px 16px #d1d9e6,
-8px -8px 16px #ffffff;
}
The result: Visual inconsistency within 24 hours. When I updated button shadows in the main app, I forgot to update the history window. The close button looked subtly different—wrong gradients, wrong shadow depth.
The lesson: Copy-paste scaling doesn’t work for visual consistency any more than it works for code consistency.
Attempt 2: Shared CSS File
The approach: Create a single CSS file that both windows import.
The problem: Build complexity. How do you ensure a shared CSS file gets copied to the right place during the build process? How do you handle CSS variables? How do you manage theme switching across windows?
The realization: This wasn’t a CSS problem—it was an architecture problem disguised as a styling problem.
The Solution: Design Systems as Infrastructure
The Architecture Decision
Instead of treating design consistency as a post-hoc styling concern, we made it a first-class infrastructure requirement:
- Shared CSS Variables: All colors, shadows, and measurements defined once
- Component Classes: Reusable button, input, and interaction patterns
- Build Process Integration: Automated copying of shared assets
- Theme Synchronization: Consistent theming across all windows
The Implementation: Shared-Styles.css
/* CSS Variables - Single Source of Truth */
:root {
--neu-bg: #f0f4f8;
--neu-bg-secondary: #e8eff5;
--neu-text: #2d3748;
--neu-text-secondary: #4a5568;
--neu-shadow-light: #ffffff;
--neu-shadow-dark: #d1d9e6;
--neu-shadow-raised: 8px 8px 16px var(--neu-shadow-dark), -8px -8px 16px var(--neu-shadow-light);
--neu-shadow-pressed:
inset 4px 4px 8px var(--neu-shadow-dark), inset -4px -4px 8px var(--neu-shadow-light);
}
/* Component Classes - Reusable Patterns */
.neumorphic-button {
background: var(--neu-bg);
border: none;
border-radius: 8px;
box-shadow: var(--neu-shadow-raised);
color: var(--neu-text-secondary);
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
}
.neumorphic-button:hover {
box-shadow: var(--neu-shadow-raised-hover);
transform: translateY(-1px);
}
.neumorphic-button.primary {
color: var(--neu-text);
border: 1px solid var(--neu-shadow-dark);
}
The Build Process Integration
// In build script
cp main/shared-styles.css dist_main/
cp main/history-window.html dist_main/
Why this matters: The build process ensures that design consistency is automatic, not manual. You can’t ship inconsistent designs because the infrastructure prevents it.
The TPM Framework: Design Systems as Technical Architecture
1. Treat Visual Consistency as a Technical Requirement
Don’t think of design systems as “nice to have” styling guidelines. Think of them as technical constraints that enable or prevent certain user experiences.
The Prompt I Used:
I need to maintain visual consistency between multiple Electron windows.
Design a CSS architecture that:
1. Shares variables and components across windows
2. Supports theme switching synchronization
3. Integrates with the build process automatically
4. Scales to additional windows in the future
2. Design for Multi-Context from Day One
Even if you’re building a single-window app, architect your CSS as if you’ll have multiple contexts eventually.
The Architecture Prompt:
Create a modular CSS system for [app type] that:
- Separates variables from components
- Defines reusable interaction patterns
- Supports multiple rendering contexts
- Enables automated consistency checking
3. Build Process as Design Enforcer
Make visual consistency impossible to break through automation.
The Build Integration Prompt:
I have shared CSS that needs to be available to multiple HTML files.
Design a build process that:
1. Automatically copies shared assets
2. Validates CSS variable usage
3. Prevents inconsistent styling
4. Supports development hot-reloading
The Business Impact: When Consistency Enables Features
Before: Ad-Hoc Styling
- Each new window required custom CSS work
- Visual inconsistencies accumulated over time
- Design changes required multiple file updates
- QA time spent catching visual regressions
After: Infrastructure-First Design
- New windows automatically inherit consistent styling
- Design changes propagate automatically
- Visual consistency enforced by build process
- Development velocity increased for UI features
The Scalability Wins
When we later added:
- Custom title bar: Inherited neumorphic styling automatically
- Settings panels: Reused existing component classes
- Theme switching: Synchronized across all windows instantly
- Future features: Can focus on functionality, not visual consistency
Advanced: The Component Class Strategy
Button Hierarchy
/* Base button - minimal styling */
.neumorphic-button {
/* base styles */
}
/* Variants - additive classes */
.neumorphic-button.primary {
/* enhanced prominence */
}
.neumorphic-button.minimal {
/* reduced visual weight */
}
.neumorphic-button.large {
/* size variation */
}
Why This Matters for TPMs
Additive classes enable feature flexibility. You can create new button variants without breaking existing ones. You can test different visual weights without rewriting CSS.
Product decision example: We wanted the history window close button to match the main UI exactly. Because of the .primary variant, this was a one-class change, not a CSS rewrite.
State Management Classes
.neumorphic-input {
/* normal state */
}
.neumorphic-input:focus {
/* interaction state */
}
.neumorphic-input.error {
/* validation state */
}
.neumorphic-input.disabled {
/* unavailable state */
}
Business value: Consistent interaction feedback across all contexts. Users build muscle memory for how your app behaves, regardless of which window they’re using.
The Psychology: Why Visual Consistency Affects Product Perception
Cognitive Load Reduction
When UI elements behave consistently across contexts, users spend less mental energy on interface navigation and more on their actual goals.
Measurement: Time to complete secondary tasks (like checking history) decreases when visual patterns are consistent.
Professional Tool Perception
Inconsistent styling signals “amateur tool” or “different apps stitched together.” Consistent styling signals “integrated professional platform.”
VoiceCatcher example: Our popup history window feels like a natural extension of the main app, not a separate utility. This affects user confidence in the overall product quality.
Feature Adoption Enablement
Users are more likely to explore features that look and feel familiar. Visual consistency reduces the perceived “switching cost” of trying new functionality.
Common TPM Design System Mistakes (That I Made)
Mistake 1: Thinking Design Systems Are Just Visual
Wrong thinking: “We’ll create a style guide with colors and fonts.” Reality: Design systems are interaction patterns, state management, and technical constraints.
Fix: Define interaction behaviors, not just visual properties.
Mistake 2: Building Design Systems After You Need Them
Wrong thinking: “We’ll standardize the design once we have more features.” Reality: Retroactive design systems require rewriting everything.
Fix: Start with shared CSS architecture from the first component.
Mistake 3: Separating Design System from Build Process
Wrong thinking: “Developers will remember to use the shared styles.” Reality: Manual processes break under time pressure.
Fix: Make correct design usage the path of least resistance through tooling.
Mistake 4: Designing for Current Features Only
Wrong thinking: “We only need buttons and inputs right now.” Reality: You’ll need more component types than you think, and you’ll need them sooner than you expect.
Fix: Design the system architecture to be extensible, even if you only implement basic components initially.
The Technical Implementation: Infrastructure Details
CSS Variable Strategy
/* Hierarchical variable naming */
--neu-bg /* base background */
--neu-bg-secondary /* secondary surfaces */
--neu-bg-tertiary /* least prominent surfaces */
--neu-shadow-light /* highlight color */
--neu-shadow-dark /* shadow color */
--neu-shadow-raised /* composite shadow for raised elements */
--neu-shadow-pressed /* composite shadow for pressed elements */
Why this works: Variables cascade and compose. You can change the entire color scheme by updating 4 base variables.
Theme Switching Implementation
.dark {
--neu-bg: #1e293b;
--neu-bg-secondary: #334155;
--neu-text: #f1f5f9;
--neu-shadow-light: #475569;
--neu-shadow-dark: #0f172a;
}
Business impact: Theme switching across multiple windows happens instantly and consistently. Users don’t experience visual jarring when switching contexts.
Build Process Automation
// Ensure shared styles are available everywhere
const buildTasks = [
'copy shared-styles.css to all output directories',
'validate CSS variable usage',
'check for orphaned style definitions',
'ensure component class consistency',
];
The Prompts That Scale Design Systems
System Architecture Prompt
I'm building a [app type] that will have multiple UI contexts.
Design a CSS architecture that:
1. Maintains visual consistency automatically
2. Supports theme variations
3. Enables rapid feature development
4. Scales to [estimated number] of different interfaces
Include variable naming conventions and component organization.
Component Design Prompt
Create a neumorphic button system with these requirements:
- Base button with standard interactions
- 3 visual weight variants (minimal, standard, primary)
- 2 size variants (standard, large)
- All combinations should work together
- Must work in both light and dark themes
Provide CSS and usage examples.
Implementation Validation Prompt
Review this CSS architecture for scalability issues:
[paste your CSS system]
Identify:
1. Potential maintenance problems
2. Missing component variants we'll likely need
3. Performance considerations
4. Cross-browser compatibility concerns
Lessons Learned: Design Systems as Product Strategy
Design Systems Enable Product Velocity
Before: Each new UI element required design and engineering coordination. After: New UI elements inherit consistent behavior automatically.
Velocity measurement: Time to implement new features decreased 40% because styling decisions were pre-made.
Consistency Reduces Support Burden
Before: User confusion about where to find features across different windows. After: Users transfer learned behavior across all contexts.
Support measurement: Questions about “how do I do X in the history window” disappeared entirely.
Infrastructure Enables Experimentation
Before: Testing new interaction patterns required significant CSS development. After: Testing new patterns requires adding/modifying component classes.
Innovation measurement: We can test new UI ideas in hours instead of days.
The Meta-Lesson: Every Design Decision is an Infrastructure Decision
The biggest insight from building VoiceCatcher’s design system: There are no small visual decisions when you’re building for scale.
Every choice about colors, shadows, interaction patterns, and component behavior becomes infrastructure that either enables or constrains future product development.
The neumorphic design system wasn’t just about making buttons look consistent—it was about building technical infrastructure that makes adding new windows, features, and interactions predictable and fast.
Practical Implementation for TPMs
Start with Systems Thinking
Before designing any UI element, ask: “How will this pattern work in other contexts?” Design the system, not just the component.
Invest in Tooling Early
Build processes that make using your design system easier than not using it. Tooling compliance beats guideline compliance every time.
Measure Consistency as Product Quality
Track visual consistency across your product surfaces. Inconsistency is technical debt that affects user experience.
Design for Change
Your design system will evolve. Build the architecture to support modification and extension, not just initial implementation.
The Bottom Line
Design systems aren’t visual guidelines—they’re technical infrastructure that determines what user experiences are possible to build quickly and consistently.
VoiceCatcher’s neumorphic design system enabled us to add new windows and features without visual inconsistency slowing us down. More importantly, it enabled users to build confidence in the product’s quality because everything feels intentionally integrated.
As TPMs, we need to recognize that design system investments are infrastructure investments. They pay dividends in development velocity, user experience quality, and product scalability.
The shared CSS architecture didn’t just make our buttons consistent—it made building additional product surfaces technically and economically feasible.
That’s the difference between designing interfaces and designing systems that enable interfaces.
Jeremy is a technical product manager turned solo developer, building VoiceCatcher as a local-first voice transcription tool. Follow the journey at [project repo] or connect on [social links].
Next in this series: “Expandable Text Systems: Handling Long Content Without Truncation” - How we solved the problem of displaying hour-long transcripts in a clean, performant interface that doesn’t overwhelm users.