Flying Stable Design Guide

Design decisions and patterns established during the UI redesign session (2026-03-31).

Branding

  • App name: Flying Stable (Pegasus/pony theme for the Django desktop starter)

  • Logo: Custom Pegasus SVG, single-color, inline in the topnav using CSS currentColor

  • Sections: “My Ponies” (CRUD demo), “Stable Routines” (background tasks demo)

  • Item statuses: Grazing (backlog), Galloping (active), Show Ready (done)

  • Form labels: Name, Personality, Status

  • Themed messages: “Your pony needs a name.”, “Do you know nothing about your pony?”, “Release All Ponies”, “Starts a simulated stable routine for the pony crew”, “No routines underway. Start a routine to see the stable crew at work.”

Color System

All colors are CSS custom properties defined in :root in app.css. No hardcoded hex values outside :root.

Token

Value

Usage

--teal-deep

#108D82

Primary teal, table headers, edit actions

--teal-bright

#4FC0BC

Nav links, logo, focus rings, active states

--teal-dark

#0A544E

Page header background, title color in tables

--dark

#222121

Topnav and footer background

--accent

#D4790A

Primary action buttons (amber-orange, tuned to match header image)

--accent-hover

#B86808

Hover state for primary buttons

--danger

#C24B5A

Delete/destructive actions (pinkish-red, deliberately not aggressive)

--danger-hover

#A8404E

Hover state for danger elements

--warning

#D4790A

Galloping status badge

--warning-text

#A35E08

Galloping badge text

--bg-page

#F2F4F3

Page background

--bg-card

#FFFFFF

Panel/card background

--text-primary

#222121

Primary text

--text-muted

#5A6B6A

Secondary/muted text

--border

#D4DDDB

Borders and separators

Layout Structure

+--[ Topnav (dark) ]------------------------------------------+
| Logo  FLYING STABLE          My Ponies  Routines  [Button]  |
+--[ 2px teal-bright border ]----------------------------------+
+--[ Page Header (teal-dark, 30vh, optional bg image) ]--------+
|                     Centered H1                              |
+--------------------------------------------------------------+
  +--[ Panel (white card, 1.5rem padding) ]------------------+
  | [hint text]                          [Action Button]     |
  |----------------------------------------------------------|
  | [HEADER BAR - full width gray background]                |
  |   Name     Status    Personality           Updated       |
  |----------------------------------------------------------|
  | Content rows with indented separators                    |
  +----------------------------------------------------------+
+--[ Footer (dark, sticky) ]-----------------------------------+
|                            Desktop Django Starter 2026       |
+--------------------------------------------------------------+

Key measurements

  • Topnav padding: 0.75rem 1.25rem

  • Page header: min-height: 30vh, H1 font-size: clamp(3.5rem, 9vw, 5rem)

  • Panel padding: 1.5rem, bottom: 2.25rem

  • Panel toolbar: negative margin to span full panel width, 1.5rem padding top and bottom

  • Table: full panel width via negative margins, cell padding 1rem, first/last cell padding 1.5rem

  • Logo: 4rem with margin: -1rem 0 to extend beyond topnav

  • Font: Play (Google Fonts, weights 400 and 700 only)

Design Patterns

Empty States

Centered SVG illustration with descriptive text below. Both illustrations follow the same visual language:

  • Opacity layers: 0.18 (back element), 0.35 (middle), 0.6 (front)

  • Accent circle (bottom-right): r=36, stroke opacity 0.2, symbol fill opacity 0.35

  • My Ponies: Stacked document icons with X-in-circle

  • Stable Routines: Three interlocking gears with play-in-circle

  • Illustration CSS width: 280px (items), 235px (tasks, with margin-top: -1rem)

Status Badges

Inline colored badges with matching text and background:

  • Grazing: gray text on light gray (rgba(0,0,0,0.06))

  • Galloping: amber text on light amber (rgba(212,148,10,0.12))

  • Show Ready: teal text on light teal (rgba(16,141,130,0.1))

Buttons

  • Primary (.primary): Amber fill (--accent)

  • Secondary/Ghost (.secondary): Transparent with teal border, hover fills with rgba(16,141,130,0.15)

  • Danger (.danger): Pinkish-red fill (--danger)

  • All buttons: border-radius: 0.5rem, font-weight: 700, 0.6rem 1.25rem padding

Delete Modal

In-page overlay instead of separate page. Fetch-based POST with CSRF token from cookie. Accessible: role="dialog", aria-modal="true", Escape key closes, focus lands on cancel button.

Form Validation

Custom client-side validation with novalidate on the form. Inline tooltip appears below the field with:

  • Warning triangle SVG icon

  • Pink background (rgba(194,75,90,0.08))

  • Small upward-pointing connector triangle

  • justify-self: start to prevent full-width stretch

  • Disappears on input

Table Rows

  • Row separators use ::after pseudo-elements, indented 1.5rem from both sides

  • Last row has no separator

  • Header bar spans full panel width with gray background (--bg-page)

  • vertical-align: top on all cells

  • Title column: max-width: 14rem, bold, --teal-dark color

  • Notes column: muted color, max-width: 20rem, truncated to 20 words

  • Date column: right-aligned, date and time on separate lines

  • Actions: Edit (pencil) + Delete (X-in-circle) icons, 16px, muted gray, colored on hover

Header Background Images

Per-page via {% block header_class %} in base template. Use CSS background-image with a semi-transparent overlay for text readability:

background-image: linear-gradient(rgba(10, 84, 78, 0.3), rgba(10, 84, 78, 0.3)), url('...');
background-size: cover;
background-position: 20% 45%;

Development Tooling

Auto-Reload

django-browser-reload is configured in local.py only. CSS changes trigger automatic browser reload. Template changes may need Cmd+Shift+R.

Screenshots

Playwright is available for automated screenshots:

from playwright.sync_api import sync_playwright
# Use wait_until='domcontentloaded' (not 'networkidle' — browser-reload SSE blocks it)
page.goto('http://127.0.0.1:8000', wait_until='domcontentloaded')
page.wait_for_timeout(1000)
page.screenshot(path='/tmp/screenshot.png')

SVG Optimization

svgo is available via Homebrew for optimizing SVG files.

Splash Screen

Available at /splash/ and now wired into Electron startup. Standalone HTML with:

  • Breathing logo animation

  • Three bouncing dots

  • “Saddling up…” status text

  • Dark background, teal-bright color scheme

  • Reused by Electron during backend startup before the main window is ready

  • Still separate from Tauri’s shell-local splash window and Positron’s current startup flow