<?php
/**
 * PaintOps - App Theme Library
 *
 * Lets an Administrator pick the app's whole look (PaintOps > Settings >
 * Appearance) from a small library of templates instead of everything
 * being hardwired to the original steel-blue-on-white. The mechanics:
 * every color/radius the app's stylesheet (includes/job-style.php) and
 * the nav bar (paintops_render_app_nav() in manage-jobs.php) use now
 * reads a --po-* CSS custom property, each with the original value as
 * its var() fallback. A theme is just a named set of values for those
 * properties, plus an optional blob of extra CSS for looks the
 * variables alone can't express (e.g. Dark re-coloring the status
 * badges, Industrial squaring things off).
 *
 * "Classic" is the original look, kept pixel-identical: its accent is
 * defined as var(--nv-primary-accent, #4682B4), so a WP theme that set
 * that variable keeps working exactly as before. Site-wide by design
 * (one admin-chosen theme for the whole crew, Mike's call); a
 * per-user override could be layered on later by swapping which theme
 * paintops_app_theme() returns.
 *
 * Third-party/custom themes can be added with the paintops_app_themes
 * filter, same registry pattern as paintops_calculators in
 * trade-calculators.php.
 */

if (!defined('ABSPATH')) {
    exit;
}

/**
 * The theme registry. Each entry: 'label', 'description' (shown on the
 * Appearance picker), 'vars' (CSS custom properties, see
 * includes/job-style.php for where each is consumed), and 'css' (extra
 * theme-specific rules appended after the variable block).
 */
function paintops_app_themes(): array {
    $themes = [

        'classic' => [
            'label'       => 'Classic',
            'description' => 'The original PaintOps look, steel blue on white, rounded cards.',
            'vars'        => [
                // Deliberately defined via --nv-primary-accent so a WP
                // theme that already customizes the accent keeps working.
                '--po-accent'          => 'var(--nv-primary-accent, #4682B4)',
                '--po-accent-soft'     => 'rgba(70,130,180,0.08)',
                '--po-accent-line'     => 'rgba(70,130,180,0.3)',
                '--po-heading'         => '#2f5aae',
                '--po-text'            => '#333',
                '--po-text-muted'      => '#666',
                '--po-text-soft'       => '#808792',
                '--po-card-bg'         => '#fff',
                '--po-card-border'     => '#ddd',
                '--po-card-shadow'     => '0 1px 2px rgba(0,0,0,.04)',
                '--po-card-header-bg'  => 'rgba(220,219,197,0.16)',
                '--po-tile-bg'         => '#fafbfc',
                '--po-tile-border'     => '#e6e6e6',
                '--po-line'            => '#eee',
                '--po-hover'           => '#f5f7fa',
                '--po-input-border'    => '#ccc',
                '--po-btn2-bg'         => '#fff',
                '--po-positive'        => '#1e7e34',
                '--po-negative'        => '#c0392b',
                '--po-radius'          => '12px',
                '--po-radius-sm'       => '10px',
                '--po-radius-xs'       => '8px',
                '--po-radius-pill'     => '20px',
                '--po-nav-bg'          => 'var(--nv-primary-accent, #4682B4)',
                '--po-nav-active'      => '#B8AF7B',
                '--po-menu-bg'         => '#fff',
                '--po-menu-border'     => '#ddd',
                '--po-menu-text'       => '#333',
                '--po-menu-hover'      => '#f2f2f2',
                '--po-tooltip-bg'      => '#ccd6e4',
                '--po-tooltip-panel'   => '#23282d',
            ],
            'css'         => '',
        ],

        'dark' => [
            'label'       => 'Dark',
            'description' => 'Near-black background with high-contrast text, easy on the eyes, great on phones at a job site.',
            'vars'        => [
                // A medium blue tuned to satisfy BOTH uses at once: light
                // enough to read as link/accent text on the dark page
                // (~4.8:1 on the card bg, passes AA for normal text) AND
                // dark enough that WHITE button text on an accent-filled
                // button clears AA for large/bold button labels (~3.2:1).
                // The previous lighter #6ea8dc read well as text but left
                // white-on-accent buttons (Save, Add Quote, etc.) at only
                // ~2.5:1. Don't lighten this back past ~#5a9bd8 without
                // re-checking button contrast.
                '--po-accent'          => '#4f93d6',
                // AI buttons (.paintops-btn-ai): translucent steel field +
                // lightened text on the dark card (contrast-checked ~7:1).
                '--po-ai-bg'           => 'rgba(79,147,214,0.12)',
                '--po-ai-bg-hover'     => 'rgba(79,147,214,0.2)',
                '--po-ai-text'         => '#9cc4e8',
                '--po-ai-border'       => 'rgba(79,147,214,0.35)',
                '--po-accent-soft'     => 'rgba(110,168,220,0.12)',
                '--po-accent-line'     => 'rgba(110,168,220,0.35)',
                '--po-heading'         => '#9cc3e8',
                '--po-text'            => '#e2e6ea',
                '--po-text-muted'      => '#9aa4af',
                '--po-text-soft'       => '#8b96a3',
                '--po-card-bg'         => '#1d232b',
                '--po-card-border'     => '#333c47',
                '--po-card-shadow'     => '0 1px 3px rgba(0,0,0,.5)',
                '--po-card-header-bg'  => 'rgba(110,168,220,0.08)',
                '--po-tile-bg'         => '#171c22',
                '--po-tile-border'     => '#2c343e',
                '--po-line'            => '#2c343e',
                '--po-hover'           => '#242c35',
                '--po-input-border'    => '#3a444f',
                '--po-btn2-bg'         => '#1d232b',
                '--po-positive'        => '#4ec06d',
                '--po-negative'        => '#ff7a6b',
                '--po-radius'          => '12px',
                '--po-radius-sm'       => '10px',
                '--po-radius-xs'       => '8px',
                '--po-radius-pill'     => '20px',
                '--po-nav-bg'          => '#34567a',
                '--po-nav-active'      => '#8f8551',
                '--po-menu-bg'         => '#1d232b',
                '--po-menu-border'     => '#333c47',
                '--po-menu-text'       => '#dfe4e9',
                '--po-menu-hover'      => '#2a323c',
                '--po-tooltip-bg'      => '#3a444f',
                '--po-tooltip-panel'   => '#0d1117',
            ],
            // The variables cover everything job-style.php draws, but the
            // app also carries a lot of small INLINE styles (gray helper
            // text, white-ish badges) written for a light page. CSS can't
            // beat an inline style without !important, so the attribute-
            // substring overrides below retarget the handful of inline
            // colors used everywhere (grep "#777" etc. across includes/ to
            // see them). Hacky but contained, and only Dark needs it,
            // since the other themes keep light surfaces.
            'css'         => '
body, body.paintops-app-canvas { background: #14181d; color: #e2e6ea; }
h1, h2, h3, h4 { color: #e2e6ea; }
a { color: #4f93d6; }
[style*="color:#777"], [style*="color:#555"], [style*="color:#888"], [style*="color:#666"], [style*="color: #777"], [style*="color: #555"] { color: #9aa4af !important; }
[style*="color:#b00"] { color: #ff7a6b !important; }
[style*="color:green"] { color: #4ec06d !important; }
[style*="background:#eee"], [style*="background:#f1f1f1"], [style*="background:#fafafa"], [style*="background:#f5f5f5"], [style*="background:#f9f9f9"] { background: #242c35 !important; color: #cfd6dd !important; }
[style*="background:#dff0d8"], [style*="background:#d7f5d7"] { background: #1f3d28 !important; color: #7ddc95 !important; }
[style*="border:1px solid #ddd"], [style*="border:1px solid #eee"], [style*="border-bottom:1px solid #eee"] { border-color: #333c47 !important; }
.job-badge-quote     { background: #2a323c; color: #aab4bf; }
.job-badge-estimate  { background: #1e2c3d; color: #8fbbe8; }
.job-badge-bid       { background: #3a2f18; color: #e0b463; }
.job-badge-job       { background: #1f3d28; color: #7ddc95; }
.job-badge-complete-yes { background: #1f3d28; color: #7ddc95; }
.job-badge-complete-no  { background: #43221e; color: #ff9c90; }
.job-badge-muted     { background: #2a323c; color: #9aa4af; }
.job-form select { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 12 8\'%3E%3Cpath fill=\'%23aab4bf\' d=\'M1 1l5 5 5-5\'/%3E%3C/svg%3E"); }
.job-form input, .job-form select, .job-form textarea,
.paintops-email-quote-box input[type="email"], .paintops-email-quote-box input[type="text"], .paintops-email-quote-box textarea,
input[type="text"], input[type="email"], input[type="date"], input[type="number"], select, textarea { background-color: #12161b !important; color: #e2e6ea !important; }
',
        ],

        'modern' => [
            'label'       => 'Modern',
            'description' => 'Clean and airy, a steel-blue accent with a warm peach pop on soft mint white. (Palette: coolors ebe9e9 / f3f8f2 / 3581b8 / fcb07e / dee2d6.)',
            'vars'        => [
                // Steel blue (#3581B8) accent for links/buttons/nav; heading
                // is a darker blue for strong contrast on the light bg.
                '--po-accent'          => '#3581b8',
                '--po-accent-soft'     => 'rgba(53,129,184,0.10)',
                '--po-accent-line'     => 'rgba(53,129,184,0.30)',
                '--po-heading'         => '#1f4d6b',
                '--po-text'            => '#2c3a42',
                '--po-text-muted'      => '#5f7078',
                '--po-text-soft'       => '#8a969c',
                '--po-card-bg'         => '#ffffff',
                // Soft sage (#dee2d6) hairline borders; warm peach-tinted card
                // headers, the palette's blue + peach pairing.
                '--po-card-border'     => '#dee2d6',
                '--po-card-shadow'     => '0 8px 24px rgba(15,23,42,.06)',
                '--po-card-header-bg'  => '#fde8d8',
                '--po-tile-bg'         => '#f3f8f2',
                '--po-tile-border'     => '#e3e8dc',
                '--po-line'            => '#ebe9e9',
                '--po-hover'           => '#eaf2f8',
                '--po-input-border'    => '#cfd6cd',
                '--po-btn2-bg'         => '#ffffff',
                '--po-positive'        => '#1e7e34',
                '--po-negative'        => '#c0392b',
                '--po-radius'          => '14px',
                '--po-radius-sm'       => '10px',
                '--po-radius-xs'       => '8px',
                '--po-radius-pill'     => '24px',
                '--po-nav-bg'          => '#3581b8',
                // Active pill is a darker blue so its white label stays
                // readable (nav labels are always white).
                '--po-nav-active'      => '#1f4d6b',
                '--po-menu-bg'         => '#ffffff',
                '--po-menu-border'     => '#dee2d6',
                '--po-menu-text'       => '#2c3a42',
                '--po-menu-hover'      => '#eaf2f8',
                // Peach (#FCB07E) tooltip bubble, the palette warm pop; dark
                // panel text on it reads at high contrast.
                '--po-tooltip-bg'      => '#fcb07e',
                '--po-tooltip-panel'   => '#1f2a37',
            ],
            'css'         => '
body, body.paintops-app-canvas { background: #f3f8f2; }
.paintops-btn, .job-form button, .button { transition: box-shadow .15s ease, opacity .15s ease; }
.paintops-btn-primary:hover, .job-form button:hover { box-shadow: 0 4px 14px rgba(53,129,184,.35); opacity: 1; }
.job-form-section { text-transform: none; letter-spacing: 0; font-size: 115%; }
',
        ],

        'industrial' => [
            'label'       => 'Industrial',
            'description' => 'Concrete grays, gunmetal menus, slate-blue accent, squared-off corners.',
            'vars'        => [
                // Petrol teal accent (replaced the original safety-orange,
                // which failed contrast on the light-gray surfaces, only
                // ~2.8:1 as link text, ~3.1:1 behind white button text).
                // Teal clears both (~4.9:1 on the card bg, ~5.4:1 behind
                // white) and reads brighter/livelier than the slate it
                // replaced, while still suiting the concrete/steel look.
                // accent-soft/line are teal tints so the primary stat tile
                // / table headers match.
                '--po-accent'          => '#0e7490',
                '--po-accent-soft'     => 'rgba(14,116,144,0.10)',
                '--po-accent-line'     => 'rgba(14,116,144,0.40)',
                '--po-heading'         => '#0e7490',
                '--po-text'            => '#212529',
                '--po-text-muted'      => '#5f6368',
                '--po-text-soft'       => '#80868b',
                '--po-card-bg'         => '#f4f4f5',
                '--po-card-border'     => '#9aa0a6',
                '--po-card-shadow'     => 'none',
                '--po-card-header-bg'  => '#e4e6e8',
                '--po-tile-bg'         => '#e9eaec',
                '--po-tile-border'     => '#b8bdc3',
                '--po-line'            => '#cfd3d7',
                '--po-hover'           => '#e4e6e8',
                '--po-input-border'    => '#9aa0a6',
                '--po-btn2-bg'         => '#f4f4f5',
                '--po-positive'        => '#2e7d32',
                '--po-negative'        => '#c62828',
                '--po-radius'          => '2px',
                '--po-radius-sm'       => '2px',
                '--po-radius-xs'       => '2px',
                '--po-radius-pill'     => '4px',
                '--po-nav-bg'          => '#2b2f33',
                // The teal accent works directly as the active nav pill:
                // its distinctly cyan hue reads as "highlighted" against the
                // neutral gunmetal pills (plus ~2.5:1 luminance), and white
                // label text stays readable (~5.4:1). (The slate accent
                // needed a separate lighter tint here because it was too
                // close in both hue and value to the gunmetal.)
                '--po-nav-active'      => '#0e7490',
                '--po-menu-bg'         => '#33383d',
                '--po-menu-border'     => '#1f2327',
                '--po-menu-text'       => '#e8eaed',
                '--po-menu-hover'      => '#40464c',
                '--po-tooltip-bg'      => '#9aa0a6',
                '--po-tooltip-panel'   => '#1f2327',
            ],
            'css'         => '
body, body.paintops-app-canvas { background: #e9eaec; }
.cs-financial-box, .job-card, .paintops-email-quote-box, .cs-rank-card { border-width: 2px; }
.job-form-section { letter-spacing: 1px; border-left-width: 6px; }
h1.job-title, .job-card .job-title { text-transform: uppercase; letter-spacing: 0.5px; }
.job-badge { border-radius: 2px; }
/* Square the corners that use hardcoded radii (Resources cards, Job Board
   columns/cards, job search box) so they match the squared Industrial look. */
.rl-toolbar, .rl-admin-form-card, .rl-resource-list li, .rl-ai-panel, .rl-ai-card, .rl-embed-wrap iframe,
.rl-toolbar input, .rl-toolbar select,
.paintops-pipeline-column, .paintops-pipeline-card, .paintops-jobsearch-box, .paintops-jobsearch-box input { border-radius: 2px !important; }
',
        ],

        'fresh' => [
            'label'       => 'Fresh',
            'description' => 'Bold and dark, deep navy panels with a bright gold accent. (Palette: coolors 000814 / 001d3d / 003566 / ffc300 / ffd60a.)',
            'vars'        => [
                // Gold (#FFC300) accent on dark navy: gold links/borders read
                // at very high contrast. Primary buttons use gold with DARK
                // navy labels (set in the css block below), since white on
                // gold would be unreadable.
                '--po-accent'          => '#ffc300',
                '--po-accent-soft'     => 'rgba(255,195,0,0.14)',
                '--po-accent-line'     => 'rgba(255,195,0,0.34)',
                // Pale headings for readability on navy; gold stays the pop.
                '--po-heading'         => '#eef2f8',
                '--po-text'            => '#d9e2ee',
                // (2026-07-19, Mike's readability report) These were mid
                // grays over the navy cards and small text vanished; white
                // per Mike, with soft one step gentler for tertiary text.
                '--po-text-muted'      => '#ffffff',
                '--po-text-soft'       => '#dbe4ee',
                '--po-card-bg'         => '#001d3d',
                '--po-card-border'     => '#0b2f56',
                '--po-card-shadow'     => '0 1px 3px rgba(0,0,0,.5)',
                '--po-card-header-bg'  => 'rgba(255,214,10,0.08)',
                '--po-tile-bg'         => '#00284c',
                '--po-tile-border'     => '#0e365f',
                '--po-line'            => '#0a2b4f',
                '--po-hover'           => '#002a52',
                '--po-input-border'    => '#133f6b',
                '--po-btn2-bg'         => '#001d3d',
                // Dark-theme safe positive/negative (readable on navy).
                '--po-positive'        => '#4ec06d',
                '--po-negative'        => '#ff7a6b',
                '--po-radius'          => '12px',
                '--po-radius-sm'       => '9px',
                '--po-radius-xs'       => '7px',
                '--po-radius-pill'     => '22px',
                // Nav bar dark navy; active pill a lighter navy so its white
                // label stays readable.
                '--po-nav-bg'          => '#001d3d',
                '--po-nav-active'      => '#003566',
                '--po-menu-bg'         => '#001d3d',
                '--po-menu-border'     => '#0b2f56',
                '--po-menu-text'       => '#d9e2ee',
                '--po-menu-hover'      => '#002a52',
                // Gold tooltip bubble with dark navy panel text.
                '--po-tooltip-bg'      => '#ffc300',
                '--po-tooltip-panel'   => '#001225',
            ],
            // Like Dark, the variables cover everything job-style.php draws,
            // but the app carries many small INLINE styles (gray helper text,
            // white-ish boxes/badges) written for a light page. CSS cannot beat
            // an inline style without !important, so the attribute-substring
            // overrides below retarget the handful of inline colors used
            // everywhere onto this navy/gold theme, same approach as Dark.
            'css'         => '
body, body.paintops-app-canvas { background: #000814; color: #d9e2ee; }
/* (2026-07-19 round 4) Fresh-only: the nav "+" circle is an OUTLINE at
   rest, the shared solid fill uses the muted ink, which Fresh sets to
   white, making the white "+" vanish. body prefix outguns the bar
   rules; the shared .is-active rules (higher specificity + important)
   still fill it accent on the New Request page. */
body .paintops-bottomnav .pbn-plus { background: transparent; border: 2px solid currentColor; color: inherit; }
h1, h2, h3, h4 { color: #eef2f8; }
a { color: #ffc300; }
.paintops-btn-primary, .paintops-btn-primary:visited { color: #001225 !important; }
.paintops-sticky-save button, .paintops-form-save button, .job-form button[type="submit"] { color: #001225 !important; }
.job-form-section { text-transform: none; letter-spacing: 0; font-size: 112%; }
[style*="color:#777"], [style*="color:#555"], [style*="color:#888"], [style*="color:#666"], [style*="color:#333"], [style*="color:#999"], [style*="color:#aaa"], [style*="color: #777"], [style*="color: #555"], [style*="color: #333"], [style*="color: #666"] { color: #93a5bb !important; }
[style*="color:#b00"], [style*="color:#a94442"], [style*="color:#b32d2e"] { color: #ff7a6b !important; }
[style*="color:green"], [style*="color:#1a7a43"], [style*="color:#0f7b52"] { color: #4ec06d !important; }
[style*="background:#eee"], [style*="background:#f1f1f1"], [style*="background:#fafafa"], [style*="background:#f5f5f5"], [style*="background:#f9f9f9"], [style*="background:#f6f7f7"], [style*="background:#f0f0f1"], [style*="background: #fafafa"] { background: #00284c !important; color: #d9e2ee !important; }
[style*="background:#dff0d8"], [style*="background:#d7f5d7"] { background: #0f3d2a !important; color: #7ddc95 !important; }
[style*="border:1px solid #ddd"], [style*="border:1px solid #eee"], [style*="border:1px solid #ccc"], [style*="border-bottom:1px solid #eee"], [style*="border-bottom:1px solid #f0f0f1"] { border-color: #0e365f !important; }
.job-badge-quote { background: #0a2a4a; color: #9fc3e8; }
.job-badge-estimate { background: #0a2a4a; color: #8fbbe8; }
.job-badge-bid { background: #3a2f18; color: #e0b463; }
.job-badge-job { background: #0f3d2a; color: #7ddc95; }
.job-badge-complete-yes { background: #0f3d2a; color: #7ddc95; }
.job-badge-complete-no { background: #43221e; color: #ff9c90; }
.job-badge-muted { background: #0a2a4a; color: #93a5bb; }
.job-form select { background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' viewBox=\'0 0 12 8\'%3E%3Cpath fill=\'%23aab4bf\' d=\'M1 1l5 5 5-5\'/%3E%3C/svg%3E"); }
.job-form input, .job-form select, .job-form textarea,
.paintops-email-quote-box input[type="email"], .paintops-email-quote-box input[type="text"], .paintops-email-quote-box textarea,
input[type="text"], input[type="email"], input[type="date"], input[type="number"], input[type="tel"], select, textarea { background-color: #00152e !important; color: #e6ecf3 !important; }
',
        ],

        // Registry key kept as 'sunset' on purpose: the active theme is
        // stored in the paintops_app_theme option by key, so reusing the
        // slot means anyone already on the old Sunset theme rolls onto
        // Retro instead of silently falling back to Classic. The label
        // below is what the picker shows.
        'sunset' => [
            'label'       => 'Retro',
            'description' => 'Bold navy & amber, deep-navy anchor with a warm amber pop on clean gray and white. (Palette: coolors 000000 / 14213d / fca311 / e5e5e5 / ffffff.)',
            'vars'        => [
                // Deep navy (#14213D): the anchor for links/buttons/nav bar.
                // White labels on it read at ~15:1, so it doubles as accent
                // and nav color. accent-soft/line are AMBER tints so the
                // palette's warm pop shows on the primary stat tile / headers.
                '--po-accent'          => '#14213d',
                '--po-accent-soft'     => 'rgba(252,163,17,0.16)',
                '--po-accent-line'     => 'rgba(252,163,17,0.40)',
                '--po-heading'         => '#14213d',
                '--po-text'            => '#1f2430',
                '--po-text-muted'      => '#5a6070',
                '--po-text-soft'       => '#8b909b',
                '--po-card-bg'         => '#ffffff',
                '--po-card-border'     => '#e0e0e0',
                '--po-card-shadow'     => '0 1px 3px rgba(0,0,0,.08)',
                // Warm amber-tinted card headers (a soft tint of #FCA311); a
                // navy heading on it reads at high contrast.
                '--po-card-header-bg'  => '#fdeccb',
                '--po-tile-bg'         => '#f6f6f6',
                '--po-tile-border'     => '#e5e5e5',
                '--po-line'            => '#e5e5e5',
                '--po-hover'           => '#fbf2db',
                '--po-input-border'    => '#cccccc',
                '--po-btn2-bg'         => '#ffffff',
                '--po-positive'        => '#1e7e34',
                '--po-negative'        => '#c0392b',
                '--po-radius'          => '12px',
                '--po-radius-sm'       => '10px',
                '--po-radius-xs'       => '8px',
                '--po-radius-pill'     => '18px',
                '--po-nav-bg'          => '#14213d',
                // Black active pill (white label = 21:1), a bold retro anchor.
                '--po-nav-active'      => '#000000',
                '--po-menu-bg'         => '#ffffff',
                '--po-menu-border'     => '#e0e0e0',
                '--po-menu-text'       => '#1f2430',
                '--po-menu-hover'      => '#fbf2db',
                // Full amber (#FCA311) tooltip bubble, the palette pop; navy
                // panel text on it reads at high contrast.
                '--po-tooltip-bg'      => '#fca311',
                '--po-tooltip-panel'   => '#14213d',
            ],
            'css'         => '
body, body.paintops-app-canvas { background: #ededed; }
',
        ],

        'seaside' => [
            'label'       => 'Seaside',
            'description' => 'Coastal navy & coral, steel-navy accent and nav, a coral active pill, sea-foam headers, sky-blue tints on clean white. (Palette: coolors 3d5a80 / 98c1d9 / e0fbfc / ee6c4d / 293241.)',
            'vars'        => [
                // Steel navy (#3D5A80) is the workhorse accent: 7.06:1 as
                // text on white and behind white button/nav labels, so it
                // drives links, buttons and the nav bar. Coral is the pop
                // (see nav-active + css below), used only where it can carry
                // DARK text, as a button/label color with white text it is
                // just 3.05:1 and would fail AA.
                '--po-accent'          => '#3D5A80',
                '--po-accent-soft'     => 'rgba(61,90,128,0.10)',
                '--po-accent-line'     => 'rgba(61,90,128,0.30)',
                '--po-heading'         => '#293241',
                '--po-text'            => '#2b3440',
                // (2026-07-19, Mike round 3) The lightened muted/soft inks
                // were too faint on Seaside surfaces, both now equal the
                // main ink, effectively REMOVING the fade on this theme
                // (his words: remove these completely). Other themes keep
                // their own values.
                '--po-text-muted'      => '#5b6673',
                '--po-text-soft'       => '#6b7684',
                '--po-card-bg'         => '#ffffff',
                '--po-card-border'     => '#d7e3ec',
                '--po-card-shadow'     => '0 1px 3px rgba(41,50,65,.06)',
                // Sea-foam header: the palette's pale cyan. navy heading on
                // it = 11.9:1.
                '--po-card-header-bg'  => '#e0fbfc',
                '--po-tile-bg'         => '#f2fbfd',
                '--po-tile-border'     => '#d3e6ec',
                '--po-line'            => '#e6f1f5',
                '--po-hover'           => '#eef7fb',
                '--po-input-border'    => '#b6cdda',
                '--po-btn2-bg'         => '#ffffff',
                '--po-positive'        => '#1e7e34',
                '--po-negative'        => '#c0392b',
                '--po-radius'          => '12px',
                '--po-radius-sm'       => '10px',
                '--po-radius-xs'       => '8px',
                '--po-radius-pill'     => '20px',
                '--po-nav-bg'          => '#3D5A80',
                // Coral (#EE6C4D) active pill, the signature coastal pop.
                // The nav normally puts WHITE text on the active pill, but
                // white-on-coral is only 3.05:1; the css block below flips
                // the active label to dark navy (#1a2330 on coral = 5.19:1).
                '--po-nav-active'      => '#EE6C4D',
                '--po-menu-bg'         => '#ffffff',
                '--po-menu-border'     => '#d7e3ec',
                '--po-menu-text'       => '#2b3440',
                '--po-menu-hover'      => '#eef7fb',
                '--po-tooltip-bg'      => '#98C1D9',
                '--po-tooltip-panel'   => '#293241',
            ],
            // (2026-07-19) The old coral-active-pill contrast override was
            // removed with the retired pills nav; the unified app bar marks
            // the active item with accent-colored TEXT on the card surface.
            // Follow-up (Mike, same day): coral as the ACTIVE color on the
            // wide-screen top bar read weak, so the active item uses the
            // palette charcoal #293241 instead (his spec). Desktop bar
            // only (.pab-*); the phone bottom bar keeps the accent. The
            // body-prefixed selector outguns the bar's own
            // 3-class !important rule, which prints later in the document.
            'css'         => '
body, body.paintops-app-canvas { background: #f4f6f9; }
body .paintops-appbar .pab-item.is-active { background: #f2fbfd !important; color: #293241 !important; }
',
        ],

        'mist' => [
            'label'       => 'Mist',
            'description' => 'Cool and calm, a soft monochrome of blue-grays: slate accent, charcoal headings, pale-cyan and mist tints on clean white. (Palette: coolors e0fbfc / c2dfe3 / 9db4c0 / 5c6b73 / 253237.)',
            'vars'        => [
                // Muted slate (#5C6B73) as accent, deliberately understated
                // for this monochrome look, but still AA (5.52:1 on white and
                // behind white labels). Charcoal (#253237) carries headings
                // and the active nav pill.
                '--po-accent'          => '#5C6B73',
                '--po-accent-soft'     => 'rgba(92,107,115,0.10)',
                '--po-accent-line'     => 'rgba(92,107,115,0.30)',
                '--po-heading'         => '#253237',
                '--po-text'            => '#2c3a40',
                '--po-text-muted'      => '#5c6b73',
                '--po-text-soft'       => '#8fa2ab',
                '--po-card-bg'         => '#ffffff',
                '--po-card-border'     => '#dbe6e9',
                '--po-card-shadow'     => '0 1px 2px rgba(37,50,55,.05)',
                '--po-card-header-bg'  => '#e0fbfc',
                '--po-tile-bg'         => '#f3f8f9',
                '--po-tile-border'     => '#dbe6e9',
                '--po-line'            => '#eaf1f2',
                '--po-hover'           => '#eef5f6',
                '--po-input-border'    => '#b7c9cf',
                '--po-btn2-bg'         => '#ffffff',
                '--po-positive'        => '#1e7e34',
                '--po-negative'        => '#c0392b',
                '--po-radius'          => '12px',
                '--po-radius-sm'       => '10px',
                '--po-radius-xs'       => '8px',
                '--po-radius-pill'     => '18px',
                '--po-nav-bg'          => '#5C6B73',
                '--po-nav-active'      => '#253237',
                '--po-menu-bg'         => '#ffffff',
                '--po-menu-border'     => '#dbe6e9',
                '--po-menu-text'       => '#2c3a40',
                '--po-menu-hover'      => '#eef5f6',
                '--po-tooltip-bg'      => '#c2dfe3',
                '--po-tooltip-panel'   => '#253237',
            ],
            // Soft light-blue primary buttons (charcoal text on #c2dfe3, a
            // palette color) instead of the default solid-slate fill,
            // Mike wanted Mist to lean light. charcoal-on-#c2dfe3 is a very
            // high contrast, and the light fill still outranks the white
            // secondary button so the primary action keeps the lead.
            // NOTE: .job-form button is overridden WITHOUT !important on
            // purpose, so a .paintops-btn-secondary <button> inside a form
            // (whose rule IS !important, at lower specificity) still wins and
            // stays white. The primary-specific selectors below carry
            // !important to beat the base rules they replace, and re-add a
            // visible border since two of those base rules set border:none.
            'css'         => '
body, body.paintops-app-canvas { background: #ffffff; }
/* (2026-07-19, Mike spec) Active menu item as a filled #a6dbff chip
   with the theme charcoal on it, the SAME pair as Mist primary buttons
   below, so the active state matches the theme primary-action look.
   Desktop bar only; body prefix outguns the bar own later rules. */
body .paintops-appbar .pab-item.is-active { background: #a6dbff !important; color: #253237 !important; }
.job-form button { background: #a6dbff; color: #253237; border: 1px solid #7fbfe8; }
.paintops-btn-primary, .paintops-btn-primary:visited,
.paintops-sticky-save button, .paintops-form-save button,
.job-form button[type="submit"] {
  background: #a6dbff !important; color: #253237 !important; border: 1px solid #7fbfe8 !important;
}
',
        ],
    ];

    return (array) apply_filters('paintops_app_themes', $themes);
}

/**
 * The active theme's key, validated against the registry so a stale
 * option value (e.g. a filter-added theme later removed) falls back to
 * Classic instead of emitting an empty variable block.
 */
function paintops_app_theme(): string {
    $theme = (string) get_option('paintops_app_theme', 'seaside');
    $themes = paintops_app_themes();
    return isset($themes[$theme]) ? $theme : 'seaside';
}

/**
 * The active theme's CSS: the :root variable set plus the theme's extra
 * rules. Returned as RAW CSS with no <style> wrapper, job-style.php
 * echoes it at the very END of its own stylesheet, inside its
 * (historically never-closed) <style> element, which is exactly what
 * makes a theme's extra rules land later in the cascade than the base
 * rules and win. Do not add <style> tags here: an opener emitted inside
 * an already-open style element is swallowed as invalid CSS text.
 * Returns the Classic block at minimum, so callers never need a
 * fallback.
 */
function paintops_app_theme_css(): string {
    $themes = paintops_app_themes();
    $theme = $themes[paintops_app_theme()];

    $out = "\n/* PaintOps theme: " . esc_html(paintops_app_theme()) . " (PaintOps > Settings > Appearance) */\n:root {\n";
    foreach ((array) ($theme['vars'] ?? []) as $name => $value) {
        // Var names come from the registry (code or a dev's filter), not
        // user input, but sanitize anyway since this is raw CSS output.
        $name = preg_replace('/[^a-zA-Z0-9\-_]/', '', (string) $name);
        $value = str_replace(['<', '>', '{', '}'], '', (string) $value);
        $out .= "    {$name}: {$value};\n";
    }
    $out .= "}\n";

    $extra = trim((string) ($theme['css'] ?? ''));
    if ($extra !== '') {
        $out .= $extra . "\n";
    }

    return $out;
}
