apply Court Tech brand design across app

Switch from Outfit/red accent to Inter/Electric Blue (Court Tech Proposal 1).
Updates Pico CSS overrides, planner CSS variables, Chart.js colors, and
Google Fonts. Deep Navy #0F172A backgrounds, Electric Blue #3B82F6 accent,
Vibrant Green #10B981 success, Soft White #F8FAFC headings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-13 08:22:06 +01:00
parent ae0be85544
commit 9b1963618c
5 changed files with 90 additions and 74 deletions

View File

@@ -9,12 +9,12 @@
<div style="display:flex;justify-content:space-between;align-items:center"> <div style="display:flex;justify-content:space-between;align-items:center">
<div class="scenario-item__name">{{ s.name }}</div> <div class="scenario-item__name">{{ s.name }}</div>
<div style="display:flex;gap:6px"> <div style="display:flex;gap:6px">
{% if s.is_default %}<span style="font-size:10px;color:var(--gn,#3dba78)">default</span>{% endif %} {% if s.is_default %}<span style="font-size:10px;color:var(--gn,#10B981)">default</span>{% endif %}
<button onclick="loadScenario({{ s.id }})" style="background:none;border:none;color:var(--bl,#4a90d9);cursor:pointer;font-size:11px;padding:0">Load</button> <button onclick="loadScenario({{ s.id }})" style="background:none;border:none;color:var(--bl,#3B82F6);cursor:pointer;font-size:11px;padding:0">Load</button>
<button hx-delete="{{ url_for('planner.delete_scenario', scenario_id=s.id) }}" <button hx-delete="{{ url_for('planner.delete_scenario', scenario_id=s.id) }}"
hx-target="#scenario-drawer" hx-swap="innerHTML" hx-target="#scenario-drawer" hx-swap="innerHTML"
hx-confirm="Delete this scenario?" hx-confirm="Delete this scenario?"
style="background:none;border:none;color:var(--rd,#d94f4f);cursor:pointer;font-size:11px;padding:0">Del</button> style="background:none;border:none;color:var(--rd,#3B82F6);cursor:pointer;font-size:11px;padding:0">Del</button>
</div> </div>
</div> </div>
{% if s.location %}<div class="scenario-item__meta">{{ s.location }}</div>{% endif %} {% if s.location %}<div class="scenario-item__meta">{{ s.location }}</div>{% endif %}
@@ -22,5 +22,5 @@
</div> </div>
{% endfor %} {% endfor %}
{% else %} {% else %}
<p style="color:var(--txt-3,#4d6278);font-size:13px">No saved scenarios yet. Use the Save button to store your current plan.</p> <p style="color:var(--txt-3,#64748B);font-size:13px">No saved scenarios yet. Use the Save button to store your current plan.</p>
{% endif %} {% endif %}

View File

@@ -1,39 +1,55 @@
/* Padelnomics — Pico CSS brand overrides */ /* Padelnomics — Court Tech brand overrides for Pico CSS */
:root[data-theme="dark"] { :root[data-theme="dark"] {
/* Background layers */ /* Background layers — Deep Navy family */
--pico-background-color: #0b0f14; --pico-background-color: #0F172A;
--pico-card-background-color: #111820; --pico-card-background-color: #1E293B;
--pico-card-sectioning-background-color: #171f2a; --pico-card-sectioning-background-color: #253347;
/* Text */ /* Text — Soft White / Slate */
--pico-color: #b8c9da; --pico-color: #CBD5E1;
--pico-muted-color: #7a8fa3; --pico-muted-color: #94A3B8;
--pico-muted-border-color: rgba(255,255,255,0.06); --pico-muted-border-color: rgba(255,255,255,0.08);
/* Primary accent (red) */ /* Primary accent — Electric Blue */
--pico-primary: #d94f4f; --pico-primary: #3B82F6;
--pico-primary-hover: #c94545; --pico-primary-hover: #2563EB;
--pico-primary-focus: rgba(217,79,79,0.25); --pico-primary-focus: rgba(59,130,246,0.25);
--pico-primary-inverse: #fff; --pico-primary-inverse: #fff;
/* Typography */ /* Secondary — Charcoal */
--pico-font-family: 'Outfit', system-ui, sans-serif; --pico-secondary: #94A3B8;
--pico-secondary-hover: #CBD5E1;
--pico-secondary-focus: rgba(148,163,184,0.25);
--pico-secondary-inverse: #0F172A;
/* Typography — Inter */
--pico-font-family: 'Inter', system-ui, -apple-system, sans-serif;
--pico-font-family-monospace: 'JetBrains Mono', monospace; --pico-font-family-monospace: 'JetBrains Mono', monospace;
/* Borders */ /* Borders */
--pico-border-color: rgba(255,255,255,0.06); --pico-border-color: #334155;
/* Form styling */ /* Form styling */
--pico-form-element-background-color: #171f2a; --pico-form-element-background-color: #1E293B;
--pico-form-element-border-color: rgba(255,255,255,0.1); --pico-form-element-border-color: #334155;
--pico-form-element-focus-color: #d94f4f; --pico-form-element-focus-color: #3B82F6;
} }
/* Headings use warm cream */ /* Headings — Soft White, Inter */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
color: #e8dcc8; color: #F8FAFC;
font-family: 'Outfit', system-ui, sans-serif; font-family: 'Inter', system-ui, -apple-system, sans-serif;
}
/* Data & metrics use monospace */
.metric, .mono, [data-mono] {
font-family: 'JetBrains Mono', monospace;
}
/* Success states — Vibrant Green */
.success, [data-success] {
color: #10B981;
} }
article { article {

View File

@@ -1,28 +1,28 @@
/* Padelnomics Planner — scoped under .planner-app */ /* Padelnomics Planner — scoped under .planner-app */
/* Isolates planner from Pico CSS resets */ /* Court Tech brand — Deep Navy + Electric Blue */
.planner-app { .planner-app {
--bg: #0b0f14; --bg: #0F172A;
--bg-2: #111820; --bg-2: #1E293B;
--bg-3: #171f2a; --bg-3: #253347;
--bg-4: #1d2733; --bg-4: #2D3F54;
--border: rgba(255,255,255,0.06); --border: rgba(255,255,255,0.08);
--border-2: rgba(255,255,255,0.1); --border-2: rgba(255,255,255,0.12);
--txt: #b8c9da; --txt: #CBD5E1;
--txt-2: #7a8fa3; --txt-2: #94A3B8;
--txt-3: #4d6278; --txt-3: #64748B;
--head: #e8dcc8; --head: #F8FAFC;
--wht: #f5f0e8; --wht: #F8FAFC;
--rd: #d94f4f; --rd: #3B82F6;
--rd-bg: rgba(217,79,79,0.08); --rd-bg: rgba(59,130,246,0.08);
--gn: #3dba78; --gn: #10B981;
--gn-bg: rgba(61,186,120,0.08); --gn-bg: rgba(16,185,129,0.08);
--bl: #4a90d9; --bl: #3B82F6;
--bl-bg: rgba(74,144,217,0.08); --bl-bg: rgba(59,130,246,0.08);
--am: #d4a03c; --am: #F59E0B;
--am-bg: rgba(212,160,60,0.08); --am-bg: rgba(245,158,11,0.08);
font-family: 'Outfit', sans-serif; font-family: 'Inter', sans-serif;
font-size: 14px; font-size: 14px;
color: var(--txt); color: var(--txt);
background: var(--bg); background: var(--bg);
@@ -81,7 +81,7 @@
background: transparent; background: transparent;
color: var(--txt-2); color: var(--txt-2);
cursor: pointer; cursor: pointer;
font-family: 'Outfit', sans-serif; font-family: 'Inter', sans-serif;
font-weight: 500; font-weight: 500;
transition: all 0.15s; transition: all 0.15s;
} }
@@ -109,7 +109,7 @@
color: var(--txt-3); color: var(--txt-3);
cursor: pointer; cursor: pointer;
white-space: nowrap; white-space: nowrap;
font-family: 'Outfit', sans-serif; font-family: 'Inter', sans-serif;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
transition: all 0.15s; transition: all 0.15s;
} }
@@ -267,7 +267,7 @@
outline: none; outline: none;
} }
.slider-combo input[type=number]:focus { .slider-combo input[type=number]:focus {
border-color: rgba(217,79,79,0.5); border-color: rgba(59,130,246,0.5);
} }
/* Hide number spinners */ /* Hide number spinners */
.slider-combo input[type=number]::-webkit-outer-spin-button, .slider-combo input[type=number]::-webkit-outer-spin-button,
@@ -295,7 +295,7 @@
color: var(--txt-3); color: var(--txt-3);
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
font-family: 'Outfit', sans-serif; font-family: 'Inter', sans-serif;
transition: all 0.15s; transition: all 0.15s;
} }
.toggle-btn--active { .toggle-btn--active {
@@ -325,7 +325,7 @@
} }
.data-table td { .data-table td {
padding: 6px 8px; padding: 6px 8px;
font-family: 'Outfit', sans-serif; font-family: 'Inter', sans-serif;
color: var(--txt); color: var(--txt);
} }
.data-table td.mono { .data-table td.mono {
@@ -383,7 +383,7 @@
margin-left: 4px; margin-left: 4px;
flex-shrink: 0; flex-shrink: 0;
font-style: italic; font-style: italic;
font-family: 'Outfit', sans-serif; font-family: 'Inter', sans-serif;
vertical-align: middle; vertical-align: middle;
} }
.ti .tp { .ti .tp {
@@ -465,7 +465,7 @@
color: #fff; color: #fff;
} }
.lead-cta-bar a:first-of-type:hover { .lead-cta-bar a:first-of-type:hover {
background: #c94545; background: #2563EB;
} }
.lead-cta-bar a:last-of-type { .lead-cta-bar a:last-of-type {
background: transparent; background: transparent;
@@ -505,7 +505,7 @@
transition: background 0.15s; transition: background 0.15s;
} }
.lead-cta__btn:hover { .lead-cta__btn:hover {
background: #c94545; background: #2563EB;
} }
/* ── Exit waterfall ── */ /* ── Exit waterfall ── */

View File

@@ -462,9 +462,9 @@ function renderCapex(d){
renderChart('chartCapex','doughnut',{ renderChart('chartCapex','doughnut',{
labels:d.capexItems.filter(i=>i.amount>0).map(i=>i.name), labels:d.capexItems.filter(i=>i.amount>0).map(i=>i.name),
datasets:[{data:d.capexItems.filter(i=>i.amount>0).map(i=>i.amount), datasets:[{data:d.capexItems.filter(i=>i.amount>0).map(i=>i.amount),
backgroundColor:['#d94f4f','#4a90d9','#3dba78','#d4a03c','#8b5cf6','#ec4899','#06b6d4','#84cc16','#f97316','#6366f1','#14b8a6','#a855f7','#ef4444','#22c55e','#eab308'], backgroundColor:['#3B82F6','#10B981','#F59E0B','#8B5CF6','#EC4899','#06B6D4','#84CC16','#F97316','#6366F1','#14B8A6','#A855F7','#EF4444','#22C55E','#EAB308','#2563EB'],
borderWidth:0}] borderWidth:0}]
},{plugins:{legend:{position:'right',labels:{color:'#7a8fa3',font:{size:10,family:'Outfit'},boxWidth:10,padding:6}}}}); },{plugins:{legend:{position:'right',labels:{color:'#94A3B8',font:{size:10,family:'Inter'},boxWidth:10,padding:6}}}});
} }
function renderOperating(d){ function renderOperating(d){
@@ -499,10 +499,10 @@ function renderOperating(d){
renderChart('chartRevRamp','bar',{ renderChart('chartRevRamp','bar',{
labels:rampData.map(m=>'M'+m.m), labels:rampData.map(m=>'M'+m.m),
datasets:[ datasets:[
{label:'Revenue',data:rampData.map(m=>Math.round(m.totalRev)),backgroundColor:'rgba(61,186,120,0.5)',borderRadius:3}, {label:'Revenue',data:rampData.map(m=>Math.round(m.totalRev)),backgroundColor:'rgba(16,185,129,0.5)',borderRadius:3},
{label:'OpEx+Debt',data:rampData.map(m=>Math.round(Math.abs(m.opex)+Math.abs(m.loan))),backgroundColor:'rgba(217,79,79,0.4)',borderRadius:3}, {label:'OpEx+Debt',data:rampData.map(m=>Math.round(Math.abs(m.opex)+Math.abs(m.loan))),backgroundColor:'rgba(239,68,68,0.4)',borderRadius:3},
] ]
},{scales:{x:{ticks:{maxTicksLimit:12,color:'#4d6278',font:{size:9}}},y:{ticks:{color:'#4d6278',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{labels:{color:'#7a8fa3',font:{size:10}}}}}); },{scales:{x:{ticks:{maxTicksLimit:12,color:'#64748B',font:{size:9}}},y:{ticks:{color:'#64748B',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{labels:{color:'#94A3B8',font:{size:10}}}}});
const plData = [ const plData = [
{label:'Court Rev',val:Math.round(d.courtRevMonth)}, {label:'Court Rev',val:Math.round(d.courtRevMonth)},
@@ -513,8 +513,8 @@ function renderOperating(d){
]; ];
renderChart('chartPL','bar',{ renderChart('chartPL','bar',{
labels:plData.map(p=>p.label), labels:plData.map(p=>p.label),
datasets:[{data:plData.map(p=>p.val),backgroundColor:plData.map(p=>p.val>=0?'rgba(61,186,120,0.6)':'rgba(217,79,79,0.5)'),borderRadius:4}] datasets:[{data:plData.map(p=>p.val),backgroundColor:plData.map(p=>p.val>=0?'rgba(16,185,129,0.6)':'rgba(239,68,68,0.5)'),borderRadius:4}]
},{indexAxis:'y',scales:{x:{ticks:{color:'#4d6278',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}},y:{ticks:{color:'#7a8fa3',font:{size:10}}}},plugins:{legend:{display:false}}}); },{indexAxis:'y',scales:{x:{ticks:{color:'#64748B',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}},y:{ticks:{color:'#94A3B8',font:{size:10}}}},plugins:{legend:{display:false}}});
} }
function renderCashflow(d){ function renderCashflow(d){
@@ -530,13 +530,13 @@ function renderCashflow(d){
renderChart('chartCF','bar',{ renderChart('chartCF','bar',{
labels:d.months.map(m=>m.m%12===1?'Y'+m.yr:''), labels:d.months.map(m=>m.m%12===1?'Y'+m.yr:''),
datasets:[{data:d.months.map(m=>Math.round(m.ncf)), datasets:[{data:d.months.map(m=>Math.round(m.ncf)),
backgroundColor:d.months.map(m=>m.ncf>=0?'rgba(61,186,120,0.5)':'rgba(217,79,79,0.4)'),borderRadius:2}] backgroundColor:d.months.map(m=>m.ncf>=0?'rgba(16,185,129,0.5)':'rgba(239,68,68,0.4)'),borderRadius:2}]
},{scales:{x:{ticks:{color:'#4d6278',font:{size:9}}},y:{ticks:{color:'#4d6278',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}}); },{scales:{x:{ticks:{color:'#64748B',font:{size:9}}},y:{ticks:{color:'#64748B',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}});
renderChart('chartCum','line',{ renderChart('chartCum','line',{
labels:d.months.map(m=>m.m%6===1?'M'+m.m:''), labels:d.months.map(m=>m.m%6===1?'M'+m.m:''),
datasets:[{data:d.months.map(m=>Math.round(m.cum)),borderColor:'#4a90d9',backgroundColor:'rgba(74,144,217,0.08)',fill:true,pointRadius:0,tension:0.3}] datasets:[{data:d.months.map(m=>Math.round(m.cum)),borderColor:'#3B82F6',backgroundColor:'rgba(59,130,246,0.08)',fill:true,pointRadius:0,tension:0.3}]
},{scales:{x:{ticks:{color:'#4d6278',font:{size:9}}},y:{ticks:{color:'#4d6278',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}}); },{scales:{x:{ticks:{color:'#64748B',font:{size:9}}},y:{ticks:{color:'#64748B',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}});
let rows = d.annuals.map(y=>{ let rows = d.annuals.map(y=>{
const dscr = y.ds>0?y.ebitda/y.ds:999; const dscr = y.ds>0?y.ebitda/y.ds:999;
@@ -577,8 +577,8 @@ function renderReturns(d){
renderChart('chartDSCR','bar',{ renderChart('chartDSCR','bar',{
labels:d.dscr.map(x=>'Y'+x.year), labels:d.dscr.map(x=>'Y'+x.year),
datasets:[{data:d.dscr.map(x=>Math.min(x.dscr,10)),backgroundColor:d.dscr.map(x=>x.dscr>=1.2?'rgba(61,186,120,0.5)':'rgba(217,79,79,0.5)'),borderRadius:4}] datasets:[{data:d.dscr.map(x=>Math.min(x.dscr,10)),backgroundColor:d.dscr.map(x=>x.dscr>=1.2?'rgba(16,185,129,0.5)':'rgba(239,68,68,0.5)'),borderRadius:4}]
},{scales:{x:{ticks:{color:'#7a8fa3'}},y:{ticks:{color:'#4d6278',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}}); },{scales:{x:{ticks:{color:'#94A3B8'}},y:{ticks:{color:'#64748B',font:{size:9}},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}});
const utils = [15,20,25,30,35,40,45,50,55,60,65,70]; const utils = [15,20,25,30,35,40,45,50,55,60,65,70];
const isIn = S.venue==='indoor'; const isIn = S.venue==='indoor';
@@ -655,8 +655,8 @@ function renderSeasonChart(){
const months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; const months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
renderChart('chartSeason','bar',{ renderChart('chartSeason','bar',{
labels:months, labels:months,
datasets:[{data:S.season.map(s=>s*100),backgroundColor:S.season.map(s=>s>0?'rgba(61,186,120,0.5)':'rgba(217,79,79,0.2)'),borderRadius:4}] datasets:[{data:S.season.map(s=>s*100),backgroundColor:S.season.map(s=>s>0?'rgba(16,185,129,0.5)':'rgba(239,68,68,0.2)'),borderRadius:4}]
},{scales:{x:{ticks:{color:'#7a8fa3'}},y:{max:110,ticks:{color:'#4d6278'},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}}); },{scales:{x:{ticks:{color:'#94A3B8'}},y:{max:110,ticks:{color:'#64748B'},grid:{color:'rgba(255,255,255,0.03)'}}},plugins:{legend:{display:false}}});
} }
// ── Chart Helper ────────────────────────────────────────── // ── Chart Helper ──────────────────────────────────────────
@@ -667,15 +667,15 @@ function renderChart(canvasId,type,data,opts={}){
const defaults = { const defaults = {
responsive:true, maintainAspectRatio:false, animation:{duration:0}, responsive:true, maintainAspectRatio:false, animation:{duration:0},
scales:{}, scales:{},
plugins:{legend:{labels:{color:'#7a8fa3',font:{family:'Outfit',size:10}}}}, plugins:{legend:{labels:{color:'#94A3B8',font:{family:'Inter',size:10}}}},
}; };
if(type==='doughnut'||type==='pie'){ if(type==='doughnut'||type==='pie'){
delete defaults.scales; delete defaults.scales;
defaults.cutout = '55%'; defaults.cutout = '55%';
} else { } else {
defaults.scales = { defaults.scales = {
x:{ticks:{color:'#4d6278',font:{size:9,family:'Outfit'}},grid:{display:false},border:{color:'rgba(255,255,255,0.06)'}}, x:{ticks:{color:'#64748B',font:{size:9,family:'Inter'}},grid:{display:false},border:{color:'rgba(255,255,255,0.08)'}},
y:{ticks:{color:'#4d6278',font:{size:9,family:'JetBrains Mono'}},grid:{color:'rgba(255,255,255,0.03)'},border:{color:'rgba(255,255,255,0.06)'}}, y:{ticks:{color:'#64748B',font:{size:9,family:'JetBrains Mono'}},grid:{color:'rgba(255,255,255,0.03)'},border:{color:'rgba(255,255,255,0.06)'}},
}; };
} }
charts[canvasId] = new Chart(ctx,{type,data,options:deepMerge(defaults,opts)}); charts[canvasId] = new Chart(ctx,{type,data,options:deepMerge(defaults,opts)});

View File

@@ -9,7 +9,7 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
<!-- Fonts --> <!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet">
<!-- Brand overrides --> <!-- Brand overrides -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">