Theme Switching

Themes are controlled via the data-theme attribute on <html> or <body>:

<!-- Light theme -->
<html data-theme="light">

<!-- Dark theme -->
<html data-theme="dark">

<!-- Auto (follows system preference) -->
<html>

JavaScript Toggle

function toggleTheme() {
  const current = document.documentElement.getAttribute('data-theme');
  const next = current === 'dark' ? 'light' : 'dark';
  document.documentElement.setAttribute('data-theme', next);
  localStorage.setItem('theme', next);
}

// Restore on page load
const saved = localStorage.getItem('theme');
if (saved) {
  document.documentElement.setAttribute('data-theme', saved);
}

Color Tokens

Background Colors

Base
--color-bg-base
Surface
--color-bg-surface
Elevated
--color-bg-elevated

Text Colors

Primary
--color-text-primary
Secondary
--color-text-secondary
Muted
--color-text-muted

Semantic Colors

Accent
--color-accent
Success
--color-success
Warning
--color-warning
Danger
--color-danger

Palette Colors

Named colors from the design palette:

Moonstone
--color-moonstone
Olive
--color-olive
Burnt Orange
--color-burnt-orange
Redwood
--color-redwood
Raisin Black
--color-raisin-black

Typography

Font sizes are calculated from --font-size-base (1rem). Adjust the base to scale all typography proportionally.

Token Calculation Default Usage
--font-size-base 1rem (reference) 16px Body text
--font-size-2xs base Γ— 0.625 10px Timeline labels, hints
--font-size-xs base Γ— 0.75 12px Small labels
--font-size-sm base Γ— 0.875 14px Secondary text
--font-size-lg base Γ— 1.125 18px Emphasis
--font-size-xl base Γ— 1.25 20px H3
--font-size-2xl base Γ— 1.5 24px H2
--font-size-3xl base Γ— 1.875 30px H1

Font Families

Token Stack Usage
--font-sans Inter, system-ui, sans-serif Body text, UI
--font-mono ui-monospace, monospace Code, time displays

Line Heights

Token Value Usage
--line-height-small 1 Icons, single-line buttons
--line-height-tight 1.25 Headings
--line-height-normal 1.5 Body text
--line-height-relaxed 1.75 Long-form content

Spacing

Spacing tokens are calculated from --space-1 (0.25rem = 4px). The scale follows a consistent multiplier pattern.

Token Multiplier Default
--space-11Γ— (reference)4px
--space-1-51.5Γ—6px
--space-22Γ—8px
--space-2-52.5Γ—10px
--space-33Γ—12px
--space-44Γ—16px
--space-55Γ—20px
--space-66Γ—24px
--space-88Γ—32px
--space-1010Γ—40px
--space-1212Γ—48px
/* Scale the entire spacing system */
:root {
  --space-1: 0.3rem;  /* Now 4.8px base β†’ all spaces scale up */
}

Interactive Sizing

Button and icon sizes follow WCAG touch target guidelines. --size-touch-min (44px) is the minimum recommended touch target size.

Token Value Usage
--size-touch-min 2.75rem (44px) WCAG minimum touch target
--size-btn-sm 1.75rem (28px) Compact action buttons
--size-btn-md 2.25rem (36px) Standard buttons
--size-btn-lg var(--size-touch-min) Mobile-friendly buttons
--size-btn-xl 3rem (48px) Large touch buttons

Icon Sizes

Icon sizes reference button sizes for consistency:

Token References Default
--size-icon-sm --size-btn-sm 28px
--size-icon-md --size-btn-md 36px
--size-icon-lg --size-btn-lg 44px

Slider & Timeline Tokens

Token References Default Usage
--slider-track-height --space-1-5 6px Slider/timeline track thickness
--slider-thumb-size --font-size-sm 14px Slider thumb diameter
--timeline-handle-width --space-6 24px Loop handle width
--timeline-handle-height --space-8 32px Loop handle height

Container Widths

Use container tokens for consistent max-width constraints across layouts:

Token Value Use Case
--container-2xs 20rem (320px) Small cards, compact forms
--container-xs 24rem (384px) Cards, sidebars
--container-sm 30rem (480px) Forms, narrow content
--container-md 36rem (576px) Medium content blocks
--container-lg 48rem (768px) Article content, main content
--container-xl 64rem (1024px) Wide content areas
--container-2xl 80rem (1280px) Full-width layouts
/* Usage examples */
.card { max-width: var(--container-xs); }
.form { max-width: var(--container-sm); }
.article { max-width: var(--container-lg); }
.page { max-width: var(--container-xl); margin: 0 auto; }

Border & Outline

Border and outline widths are kept in pixels for crisp rendering at all zoom levels:

Token Value Usage
--border-width 1px Standard borders
--border-width-thick 2px Emphasized borders
--outline-width 2px Focus outlines
--outline-offset 2px Focus outline spacing

Border Radius

Border radius tokens reference the spacing scale for consistency:

--radius-sm = --space-1 (4px)
--radius-md = --space-2 (8px)
--radius-lg = --space-3 (12px)
--radius-xl = --space-4 (16px)
--radius-full (9999px - pill/circle)

Buttons

Buttons use the .btn class or the native <button> element with shared styles from ui.css.

Button Style Decision Guide

Use this table to choose the right button style for your use case:

Style When to Use Example
.btn (default) Primary actions: Submit, Save, Confirm
.secondary Secondary actions: Cancel, Back, alternative options
.ghost Tertiary actions: Settings, subtle links, toolbars
.icon Icon-only button with content-based width
.icon.square Icon-only with fixed dimensions for uniform toolbars
.xs Very compact spaces: popovers, inline controls
.active Toggle state: button is currently "on"
.danger Destructive actions: Delete, Remove
.success Positive confirmations: Done, Complete

Primary Buttons

Default button style uses the accent color (olive). Use for main actions.

Button Variants

<button>Primary</button>
<button class="secondary">Secondary</button>
<button class="danger">Danger</button>
<button class="success">Success</button>

Icon Buttons: .icon vs .icon.square

Key difference:

Comparison

.icon (content-based width):

← Different widths based on content

.icon.square (fixed dimensions):

← Same width, uniform toolbar look

Square Button Size Variants

Use size modifiers for different contexts:

ClassSizeUse Case
.square.sm28pxCompact toolbars, inline actions
.square (md)36pxDefault, most toolbars
.square.lg44pxTouch-friendly, mobile controls
.square.xl48pxLarge touch targets, prominent actions
<!-- Content-based icon button -->
<button class="icon">β–Ά</button>

<!-- Fixed-size square button (for uniform toolbars) -->
<button class="icon square">β–Ά</button>
<button class="icon square lg">β–Ά</button>

Ghost Buttons

Minimal buttons with transparent background. Use for tertiary actions or when you want buttons to blend with the background until hovered.

<button class="ghost">Settings</button>
<button class="ghost icon">βš™</button>

Extra Small Buttons

Compact buttons for popovers and tight spaces:

<button class="xs">βˆ’1s</button>
<button class="xs secondary">Cancel</button>

Active/Toggle State

Use .active for toggled-on buttons (e.g., loop mode ON, filter selected):

<button class="icon square secondary">πŸ”</button>
<button class="icon square active">πŸ”</button>

SVG Icons in Buttons

SVG icons inside buttons are automatically sized via .btn svg rules:

<button class="icon square secondary">
  <svg viewBox="0 0 24 24" fill="currentColor">
    <path d="M8 5v14l11-7z"/>
  </svg>
</button>

Button Color Palette

Button colors are derived from the design system palette. Each state has a distinct visual treatment:

State Background Text Border Example
Primary #849324 (olive) #fff none
Secondary surface primary #d0d3db
Active (Toggle) rgba(132,147,36,0.15) #849324 #849324 (2px)
Ghost transparent primary #d0d3db
Danger #ba5624 (burnt orange) #fff none
Success #2a7b6f (teal) #fff none

Color Variables

Button colors reference these CSS custom properties:

Active State Design Pattern

The .active class uses a semi-transparent accent background with colored textβ€”a standard UI pattern for toggle buttons that:

vs ← Primary action (different purpose)

Popovers

Floating UI using the native Popover API. Zero JavaScript required!

Browser support: Chrome 114+, Firefox 125+, Safari 17+ (all major browsers).

Basic Usage

Native Popover
Click outside or press Escape to close!
Edit Mode
<!-- Toggle button - no JavaScript! -->
<button popovertarget="my-popover">Toggle</button>
<div id="my-popover" popover class="popover">
  <div class="popover-header">
    <span class="popover-title">Title</span>
    <button class="popover-close" popovertarget="my-popover" popovertargetaction="hide">Γ—</button>
  </div>
  <div class="popover-body">Content</div>
</div>

<!-- Accent border for edit modes -->
<div id="edit" popover class="popover accent">...</div>

<!-- Modal (no light dismiss) -->
<div id="modal" popover="manual" class="popover modal">...</div>

Positioning (CSS Anchor Positioning)

Position popovers relative to their trigger using position-area. Browser support: Chrome/Edge 125+ (May 2024). Falls back to centered on unsupported browsers.

Centered Positions

Popover appears centered on the specified side of the button:

Centered above
Centered below

Edge-Aligned Positions

Popover edge aligns with the button's edge. Use .start (left/top) or .end (right/bottom):

Horizontal: .top.start = above + left-aligned, .top.end = above + right-aligned

← Left edge aligned
Right edge aligned β†’
← Left edge aligned
Right edge aligned β†’

Vertical: .left.start = left + top-aligned, .left.end = left + bottom-aligned

↑ Top aligned
↓ Bottom aligned
↑ Top aligned
↓ Bottom aligned

Corner Area Positions

Popover appears in the corner area (outside the button's bounds):

β†– Corner area
β†— Corner area
↙ Corner area
β†˜ Corner area
<!-- Anchor positioning requires anchor-name on trigger -->
<button popovertarget="my-pop" style="anchor-name: --my-anchor;">Open</button>
<div id="my-pop" popover class="popover top" style="position-anchor: --my-anchor;">
  Centered above button
</div>

<!-- Edge-aligned: popover's left edge aligns with button's left edge -->
<div id="my-pop" popover class="popover top start" style="position-anchor: --my-anchor;">
  Left-aligned above button
</div>

<!-- Position classes:
  Centered: top, bottom, left, right
  Edge-aligned: top start, top end, bottom start, bottom end,
                left start, left end, right start, right end
  Corner areas: top-left, top-right, bottom-left, bottom-right
-->

CSS Classes Reference

Class Description
.popover Base container with background, border, shadow
.popover.accent Accent border color for edit modes
.popover.compact Reduced spacing
.popover.modal Adds backdrop styling (use with popover="manual")
Centered Positions
.top, .bottom Centered above/below anchor
.left, .right Centered left/right of anchor
Edge-Aligned Positions
.top.start, .bottom.start Above/below, popover's left edge aligned with button's left edge
.top.end, .bottom.end Above/below, popover's right edge aligned with button's right edge
.left.start, .right.start Left/right, popover's top edge aligned with button's top edge
.left.end, .right.end Left/right, popover's bottom edge aligned with button's bottom edge
Corner Area Positions
.top-left, .top-right In corner area above-left / above-right
.bottom-left, .bottom-right In corner area below-left / below-right
Structure Elements
.popover-header Header with title and optional close button
.popover-title Title text
.popover-close Close button
.popover-body Main content area
.popover-footer Footer with action buttons
.popover-input Styled input for editing values

Dialogs

Modal dialogs using the native <dialog> element. Requires minimal JavaScript (.showModal() / .close()).

Browser support: Chrome 37+, Firefox 98+, Safari 15.4+ (excellent support).

Basic Usage

Dialog Title

This is a native dialog element. Press Escape to close or click the backdrop.

Edit Settings
Confirm Action

Are you sure you want to delete this item? This action cannot be undone.

<!-- Button opens dialog -->
<button onclick="document.getElementById('my-dialog').showModal()">Open</button>

<dialog id="my-dialog" class="dialog">
  <div class="dialog-header">
    <span class="dialog-title">Title</span>
    <button class="dialog-close" onclick="this.closest('dialog').close()">Γ—</button>
  </div>
  <div class="dialog-body">
    <p>Dialog content here.</p>
  </div>
  <div class="dialog-footer">
    <button class="btn ghost" onclick="this.closest('dialog').close()">Cancel</button>
    <button class="btn" onclick="this.closest('dialog').close()">OK</button>
  </div>
</dialog>

<!-- Using form method="dialog" auto-closes on submit -->
<dialog id="edit-dialog" class="dialog">
  <form method="dialog">
    <div class="dialog-body">
      <input type="text" class="dialog-input">
    </div>
    <div class="dialog-footer">
      <button type="submit" class="btn">Save</button>
    </div>
  </form>
</dialog>

CSS Classes Reference

Class Description
.dialog Base container with background, border, shadow, animation
.dialog-header Header with title and optional close button
.dialog-title Title text
.dialog-close Close button (same as .popover-close)
.dialog-body Main content area
.dialog-footer Footer with action buttons
.dialog-input Styled input for forms

Popover vs Dialog

Feature Popover Dialog
JavaScript None required Minimal (.showModal())
Backdrop Optional (popover="manual") Always with ::backdrop
Position Anchor-relative (CSS) Centered (fixed)
Focus trap No Yes (native)
Use case Tooltips, menus, inline edit Confirmations, forms, settings

Media Player Controls

Styles for media player components. Use standard button classes with .secondary and .icon.square for consistent controls.

Player Control Buttons

Use .btn.icon.square.secondary for player controls, .active for toggled state:

<button class="icon square secondary">β–Ά</button>
<button class="icon square active">πŸ”</button>
<button class="icon square secondary" disabled>⏭</button>

Time Display

Monospace time display for current time / duration:

0:00 / 3:45 12:34 / 59:59
<span class="time-display">0:00 / 3:45</span>

Timeline Slider

Styled range input for media progress:

<input type="range" class="timeline" min="0" max="100" value="35">

Complete Player Controls Example

1:15 / 4:30

Unified Player Color Variables

Both audio and video players share a unified color system. These variables adapt to light/dark themes automatically.

Structure Colors

Variable Light Mode Dark Mode Usage
--player-bg #f5f5f5 #1a1a1a Player container background
--player-panel-bg #ffffff #282828 Control panels, cards
--player-surface #e0e0e0 #3f3f3f Timeline tracks, borders
--player-item-bg #e8e9ed #1a1a1a List items, cards
--player-item-hover-bg #d0d3db #3f3f3f Hover state

Accent Colors

Accent (Olive)
--player-accent
Danger
--player-danger
Selected Item
--player-item-selected-bg

Text Colors

Variable Light Mode Dark Mode Usage
--player-text-primary #202030 #ffffff Primary text, labels
--player-text-secondary #666666 #aaaaaa Time display, hints
--player-item-selected-text #ffffff #1a1a1a Text on selected items
/* Customizing player colors */
audio-loop-player,
youtube-loop-player {
  --player-accent: #3ea6ff;        /* Blue accent */
  --player-danger: #ff4444;        /* Red for stop/delete */
  --player-panel-bg: #1e1e2e;      /* Custom panel color */
}