diff --git a/CHANGELOG.md b/CHANGELOG.md index dde9f45..43b06c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Changed +- **Pico CSS → Tailwind CSS v4** — full design system migration across all templates (except planner, which keeps its own CSS) + - Standalone Tailwind CLI binary (no Node.js) with `make css-build` / `make css-watch` + - Court Tech brand theme: navy/charcoal/electric/accent color palette + - Component classes (`.btn`, `.card`, `.form-input`, `.table`, `.badge`, `.flash`, etc.) in `input.css` for consistent styling + - Self-hosted Commit Mono font (replaces JetBrains Mono) for monospace data display + - Docker multi-stage build: CSS compiled in dedicated stage before Python build +- Landing page teaser calculator restyled with Tailwind utilities and brand colors + +### Removed +- Pico CSS CDN dependency +- `custom.css` (replaced by Tailwind `input.css` with `@layer components`) +- JetBrains Mono font (replaced by self-hosted Commit Mono) + ### Fixed - Empty env vars (e.g. `SECRET_KEY=`) now fall back to defaults instead of silently using `""` — fixes 500 on every request when `.env` has blank values diff --git a/padelnomics/.gitignore b/padelnomics/.gitignore index 4f81702..e9dbb93 100644 --- a/padelnomics/.gitignore +++ b/padelnomics/.gitignore @@ -36,3 +36,7 @@ htmlcov/ dist/ build/ *.egg-info/ + +# Tailwind CSS +bin/tailwindcss +src/padelnomics/static/css/output.css diff --git a/padelnomics/Dockerfile b/padelnomics/Dockerfile index 9d84920..7101de1 100644 --- a/padelnomics/Dockerfile +++ b/padelnomics/Dockerfile @@ -1,3 +1,12 @@ +# CSS build stage (Tailwind standalone CLI, no Node.js) +FROM debian:bookworm-slim AS css-build +ADD https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 /usr/local/bin/tailwindcss +RUN chmod +x /usr/local/bin/tailwindcss +WORKDIR /app +COPY src/ ./src/ +RUN tailwindcss -i ./src/padelnomics/static/css/input.css \ + -o ./src/padelnomics/static/css/output.css --minify + # Build stage FROM python:3.12-slim AS build COPY --from=ghcr.io/astral-sh/uv:0.8 /uv /uvx /bin/ @@ -15,6 +24,7 @@ RUN useradd -m -u 1000 appuser WORKDIR /app RUN mkdir -p /app/data && chown -R appuser:appuser /app COPY --from=build --chown=appuser:appuser /app . +COPY --from=css-build /app/src/padelnomics/static/css/output.css ./src/padelnomics/static/css/output.css USER appuser ENV PYTHONUNBUFFERED=1 ENV DATABASE_PATH=/app/data/app.db diff --git a/padelnomics/Makefile b/padelnomics/Makefile new file mode 100644 index 0000000..a722521 --- /dev/null +++ b/padelnomics/Makefile @@ -0,0 +1,12 @@ +TAILWIND := ./bin/tailwindcss + +bin/tailwindcss: + @mkdir -p bin + curl -sLo bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 + chmod +x bin/tailwindcss + +css-build: bin/tailwindcss + $(TAILWIND) -i src/padelnomics/static/css/input.css -o src/padelnomics/static/css/output.css --minify + +css-watch: bin/tailwindcss + $(TAILWIND) -i src/padelnomics/static/css/input.css -o src/padelnomics/static/css/output.css --watch diff --git a/padelnomics/README.md b/padelnomics/README.md index 4fcf819..62ee193 100644 --- a/padelnomics/README.md +++ b/padelnomics/README.md @@ -2,9 +2,22 @@ Plan, finance, and build your padel business. +## Development +### CSS (Tailwind) - ## CI/CD: +Uses the [Tailwind CSS standalone CLI](https://tailwindcss.com/blog/standalone-cli) — no Node.js required. + +```bash +make css-watch # rebuild on file changes (dev) +make css-build # one-off minified build (CI/Docker) +``` + +The first run downloads the Tailwind binary to `bin/tailwindcss` automatically. + +Edit `src/padelnomics/static/css/input.css` for theme tokens, base styles, and component classes. Output is gitignored — Docker builds it in a dedicated stage. + +## CI/CD: Go to GitLab → padelnomics → Settings → CI/CD → Variables and add: ┌─────────────────┬────────────────────────────┬───────────────────────────────────────────┐ diff --git a/padelnomics/src/padelnomics/admin/templates/admin/index.html b/padelnomics/src/padelnomics/admin/templates/admin/index.html index 8c25d87..0483fed 100644 --- a/padelnomics/src/padelnomics/admin/templates/admin/index.html +++ b/padelnomics/src/padelnomics/admin/templates/admin/index.html @@ -3,62 +3,62 @@ {% block title %}Admin Dashboard - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
+
+
-

Admin Dashboard

+

Admin Dashboard

{% if session.get('admin_impersonating') %} - Currently impersonating a user -
- - -
+
+ Currently impersonating a user +
+ + +
+
{% endif %}
- +
- + -
-
-
Total Users
-

{{ stats.users_total }}

- +{{ stats.users_today }} today, +{{ stats.users_week }} this week -
- -
-
Active Subscriptions
-

{{ stats.active_subscriptions }}

-
- -
-
Task Queue
-

{{ stats.tasks_pending }} pending

+
+
+

Total Users

+

{{ stats.users_total }}

+

+{{ stats.users_today }} today, +{{ stats.users_week }} this week

+
+
+

Active Subscriptions

+

{{ stats.active_subscriptions }}

+
+
+

Task Queue

+

{{ stats.tasks_pending }} pending

{% if stats.tasks_failed > 0 %} - {{ stats.tasks_failed }} failed +

{{ stats.tasks_failed }} failed

{% else %} - 0 failed +

0 failed

{% endif %} -
+
- + -
- All Users - Task Queue - View as User + - -
+ +
-

Recent Users

-
+

Recent Users

+
{% if recent_users %} - +
@@ -69,28 +69,26 @@ {% for u in recent_users %} - + - + {% endfor %}
Email
- {{ u.email }} - {{ u.email }} {{ u.plan or 'free' }}{{ u.created_at[:10] }}{{ u.created_at[:10] }}
- View all → + View all → {% else %} -

No users yet.

+

No users yet.

{% endif %} -
+
- +
-

Failed Tasks

-
+

Failed Tasks

+
{% if failed_tasks %} - +
@@ -102,22 +100,22 @@ {% for task in failed_tasks[:5] %} - + {% endfor %}
Task
{{ task.task_name }}{{ task.error[:50] }}...{{ task.error[:50] }}... -
+ - +
- View all → + View all → {% else %} -

✓ No failed tasks

+

No failed tasks

{% endif %} -
+
diff --git a/padelnomics/src/padelnomics/admin/templates/admin/login.html b/padelnomics/src/padelnomics/admin/templates/admin/login.html index 6de0942..06bdfdf 100644 --- a/padelnomics/src/padelnomics/admin/templates/admin/login.html +++ b/padelnomics/src/padelnomics/admin/templates/admin/login.html @@ -3,28 +3,27 @@ {% block title %}Admin Login - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Admin Login

-
- -
+
+
+

Admin Login

+ + - - - - +
+ + -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/admin/templates/admin/tasks.html b/padelnomics/src/padelnomics/admin/templates/admin/tasks.html index e72af3f..57406e1 100644 --- a/padelnomics/src/padelnomics/admin/templates/admin/tasks.html +++ b/padelnomics/src/padelnomics/admin/templates/admin/tasks.html @@ -3,104 +3,108 @@ {% block title %}Tasks - Admin - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

Task Queue

- ← Dashboard +
+
+

Task Queue

+ ← Dashboard
- + {% if failed_tasks %} -
-

Failed Tasks ({{ failed_tasks | length }})

-
- - - - - - - - - - - - - {% for task in failed_tasks %} - - - - - - - - - {% endfor %} - -
IDTaskErrorRetriesCreated
{{ task.id }}{{ task.task_name }} -
- {{ task.error[:40] if task.error else 'No error' }}... -
{{ task.error }}
-
-
{{ task.retries }}{{ task.created_at[:16] }} -
-
- - -
-
- - -
-
-
-
+
+

Failed Tasks ({{ failed_tasks | length }})

+
+
+ + + + + + + + + + + + + {% for task in failed_tasks %} + + + + + + + + + {% endfor %} + +
IDTaskErrorRetriesCreated
{{ task.id }}{{ task.task_name }} +
+ {{ task.error[:40] if task.error else 'No error' }}... +
{{ task.error }}
+
+
{{ task.retries }}{{ task.created_at[:16] }} +
+
+ + +
+
+ + +
+
+
+
+
{% endif %} - +
-

Recent Tasks

-
+

Recent Tasks

+
{% if tasks %} - - - - - - - - - - - - - {% for task in tasks %} - - - - - - - - - {% endfor %} - -
IDTaskStatusRun AtCreatedCompleted
{{ task.id }}{{ task.task_name }} - {% if task.status == 'complete' %} - ✓ complete - {% elif task.status == 'failed' %} - ✗ failed - {% elif task.status == 'pending' %} - ○ pending - {% else %} - {{ task.status }} - {% endif %} - {{ task.run_at[:16] if task.run_at else '-' }}{{ task.created_at[:16] }}{{ task.completed_at[:16] if task.completed_at else '-' }}
+
+ + + + + + + + + + + + + {% for task in tasks %} + + + + + + + + + {% endfor %} + +
IDTaskStatusRun AtCreatedCompleted
{{ task.id }}{{ task.task_name }} + {% if task.status == 'complete' %} + complete + {% elif task.status == 'failed' %} + failed + {% elif task.status == 'pending' %} + pending + {% else %} + {{ task.status }} + {% endif %} + {{ task.run_at[:16] if task.run_at else '-' }}{{ task.created_at[:16] }}{{ task.completed_at[:16] if task.completed_at else '-' }}
+
{% else %} -

No tasks in queue.

+

No tasks in queue.

{% endif %} -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/admin/templates/admin/user_detail.html b/padelnomics/src/padelnomics/admin/templates/admin/user_detail.html index 919576b..33fc187 100644 --- a/padelnomics/src/padelnomics/admin/templates/admin/user_detail.html +++ b/padelnomics/src/padelnomics/admin/templates/admin/user_detail.html @@ -3,67 +3,75 @@ {% block title %}User: {{ user.email }} - Admin - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

{{ user.email }}

- ← Users +
+
+

{{ user.email }}

+ ← Users
- -
+ +
-
-

User Info

-
-
ID
-
{{ user.id }}
- -
Email
-
{{ user.email }}
- -
Name
-
{{ user.name or '-' }}
- -
Created
-
{{ user.created_at }}
- -
Last Login
-
{{ user.last_login_at or 'Never' }}
+
+

User Info

+
+
+
ID
+
{{ user.id }}
+
+
+
Email
+
{{ user.email }}
+
+
+
Name
+
{{ user.name or '-' }}
+
+
+
Created
+
{{ user.created_at }}
+
+
+
Last Login
+
{{ user.last_login_at or 'Never' }}
+
-
- +
+ -
-

Subscription

-
-
Plan
-
- {% if user.plan %} - {{ user.plan }} - {% else %} - free - {% endif %} -
- -
Status
-
{{ user.sub_status or 'N/A' }}
- +
+

Subscription

+
+
+
Plan
+
+ {% if user.plan %} + {{ user.plan }} + {% else %} + free + {% endif %} +
+
+
+
Status
+
{{ user.sub_status or 'N/A' }}
+
{% if user.paddle_customer_id %} -
Paddle Customer
-
{{ user.paddle_customer_id }}
+
+
Paddle Customer
+
{{ user.paddle_customer_id }}
+
{% endif %}
-
-
- - -
-

Actions

-
-
- - -
-
+ + + +
+

Actions

+
+ + +
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/admin/templates/admin/users.html b/padelnomics/src/padelnomics/admin/templates/admin/users.html index 15cd27b..c68a2c2 100644 --- a/padelnomics/src/padelnomics/admin/templates/admin/users.html +++ b/padelnomics/src/padelnomics/admin/templates/admin/users.html @@ -3,81 +3,76 @@ {% block title %}Users - Admin - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

Users

- ← Dashboard +
+
+

Users

+ ← Dashboard
- + -
-
- - + +
+ +
- + -
+
{% if users %} - - - - - - - - - - - - - - {% for u in users %} - - - - - - - - - - {% endfor %} - -
IDEmailNamePlanJoinedLast Login
{{ u.id }}{{ u.email }}{{ u.name or '-' }} - {% if u.plan %} - {{ u.plan }} - {% else %} - free - {% endif %} - {{ u.created_at[:10] }}{{ u.last_login_at[:10] if u.last_login_at else 'Never' }} -
- - -
-
- +
+ + + + + + + + + + + + + + {% for u in users %} + + + + + + + + + + {% endfor %} + +
IDEmailNamePlanJoinedLast Login
{{ u.id }}{{ u.email }}{{ u.name or '-' }} + {% if u.plan %} + {{ u.plan }} + {% else %} + free + {% endif %} + {{ u.created_at[:10] }}{{ u.last_login_at[:10] if u.last_login_at else 'Never' }} +
+ + +
+
+
+ -
+
{% if page > 1 %} - ← Previous + ← Previous {% endif %} - Page {{ page }} + Page {{ page }} {% if users | length == 50 %} - Next → + Next → {% endif %}
{% else %} -

No users found.

+

No users found.

{% endif %} -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/auth/templates/login.html b/padelnomics/src/padelnomics/auth/templates/login.html index 89b9964..b171b7c 100644 --- a/padelnomics/src/padelnomics/auth/templates/login.html +++ b/padelnomics/src/padelnomics/auth/templates/login.html @@ -3,37 +3,34 @@ {% block title %}Sign In - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Sign In

-

Enter your email to receive a sign-in link.

-
- -
+
+
+

Sign In

+

Enter your email to receive a sign-in link.

+ + - - - - +
+ + - -
- - Don't have an account? - Sign up - -
-
+ +

+ Don't have an account? + Sign up +

+
{% endblock %} diff --git a/padelnomics/src/padelnomics/auth/templates/magic_link_sent.html b/padelnomics/src/padelnomics/auth/templates/magic_link_sent.html index b733b1b..90b87a2 100644 --- a/padelnomics/src/padelnomics/auth/templates/magic_link_sent.html +++ b/padelnomics/src/padelnomics/auth/templates/magic_link_sent.html @@ -3,33 +3,31 @@ {% block title %}Check Your Email - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Check Your Email

-
- -

We've sent a sign-in link to:

-

{{ email }}

- -

Click the link in the email to sign in. The link expires in {{ config.MAGIC_LINK_EXPIRY_MINUTES }} minutes.

- +
+
+

Check Your Email

+ +

We've sent a sign-in link to:

+

{{ email }}

+ +

Click the link in the email to sign in. The link expires in {{ config.MAGIC_LINK_EXPIRY_MINUTES }} minutes.

+
- -
- Didn't receive the email? -
    + +
    + Didn't receive the email? +
    • Check your spam folder
    • Make sure the email address is correct
    • Wait a minute and try again
    - -
    + + - +
    -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/auth/templates/signup.html b/padelnomics/src/padelnomics/auth/templates/signup.html index 4ddd6ec..4d4db82 100644 --- a/padelnomics/src/padelnomics/auth/templates/signup.html +++ b/padelnomics/src/padelnomics/auth/templates/signup.html @@ -3,39 +3,35 @@ {% block title %}Sign Up - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Create Free Account

-

Save your padel business plan, get supplier quotes, and find financing.

-
+
+
+

Create Free Account

+

Save your padel business plan, get supplier quotes, and find financing.

-
+ -
+ +

+ Already have an account? + Sign in +

+
{% endblock %} diff --git a/padelnomics/src/padelnomics/billing/templates/pricing.html b/padelnomics/src/padelnomics/billing/templates/pricing.html index 2becf23..3ff8e07 100644 --- a/padelnomics/src/padelnomics/billing/templates/pricing.html +++ b/padelnomics/src/padelnomics/billing/templates/pricing.html @@ -2,17 +2,17 @@ {% block title %}Free Financial Planner - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

100% Free. No Catch.

+
+
+

100% Free. No Catch.

The most sophisticated padel court financial planner available — completely free. Plan your investment with 60+ variables, sensitivity analysis, and professional-grade projections.

-
+ -
-
-
Financial Planner
-

Free — forever

-
    +
    +
    +

    Financial Planner

    +

    Free — forever

    +
    • 60+ adjustable variables
    • 6 analysis tabs (CAPEX, Operating, Cash Flow, Returns, Metrics)
    • Sensitivity analysis (utilization + pricing)
    • @@ -21,27 +21,27 @@
    • Indoor/outdoor & rent/buy models
    {% if user %} - Open Planner + Open Planner {% else %} - Create Free Account + Create Free Account {% endif %} -
+
- +
{% endblock %} diff --git a/padelnomics/src/padelnomics/billing/templates/success.html b/padelnomics/src/padelnomics/billing/templates/success.html index 9b9bbc8..82dcd56 100644 --- a/padelnomics/src/padelnomics/billing/templates/success.html +++ b/padelnomics/src/padelnomics/billing/templates/success.html @@ -3,17 +3,13 @@ {% block title %}Welcome - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Welcome to Padelnomics!

-
+
+
+

Welcome to Padelnomics!

-

Your account is ready. Start planning your padel court investment with our financial planner.

+

Your account is ready. Start planning your padel court investment with our financial planner.

-

- Open Planner -

-
+ Open Planner +
{% endblock %} diff --git a/padelnomics/src/padelnomics/dashboard/templates/index.html b/padelnomics/src/padelnomics/dashboard/templates/index.html index 0132732..2c9daec 100644 --- a/padelnomics/src/padelnomics/dashboard/templates/index.html +++ b/padelnomics/src/padelnomics/dashboard/templates/index.html @@ -2,39 +2,33 @@ {% block title %}Dashboard - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

Dashboard

-

Welcome back{% if user.name %}, {{ user.name }}{% endif %}!

-
+
+

Dashboard

+

Welcome back{% if user.name %}, {{ user.name }}{% endif %}!

-
-
-
Saved Scenarios
-

{{ stats.scenarios }}

- No limits -
- -
-
Lead Requests
-

{{ stats.leads }}

- Supplier & financing inquiries -
- -
-
Plan
-

Free

- Full access to all features -
+
+
+

Saved Scenarios

+

{{ stats.scenarios }}

+

No limits

+
+
+

Lead Requests

+

{{ stats.leads }}

+

Supplier & financing inquiries

+
+
+

Plan

+

Free

+

Full access to all features

+
-
-

Quick Actions

- -
+

Quick Actions

+
{% endblock %} diff --git a/padelnomics/src/padelnomics/dashboard/templates/settings.html b/padelnomics/src/padelnomics/dashboard/templates/settings.html index 04c1234..98af2ba 100644 --- a/padelnomics/src/padelnomics/dashboard/templates/settings.html +++ b/padelnomics/src/padelnomics/dashboard/templates/settings.html @@ -2,47 +2,45 @@ {% block title %}Settings - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

Settings

-
+
+

Settings

-
-

Profile

-
-
+
+

Profile

+
+ - +
+ + +

Email cannot be changed

+
- +
+ + +
- + -
+
-

Danger Zone

-
-

Once you delete your account, there is no going back.

+

Danger Zone

+
+

Once you delete your account, there is no going back.

- Delete Account -

This will delete all your scenarios and data permanently.

+ Delete Account +

This will delete all your scenarios and data permanently.

- +
-
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/leads/templates/financing.html b/padelnomics/src/padelnomics/leads/templates/financing.html index 8e41740..0f33ae6 100644 --- a/padelnomics/src/padelnomics/leads/templates/financing.html +++ b/padelnomics/src/padelnomics/leads/templates/financing.html @@ -2,35 +2,39 @@ {% block title %}Find Financing - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

Find Financing for Your Padel Project

+
+
+

Find Financing for Your Padel Project

We work with banks and investors experienced in sports facility financing. Tell us about your project and we'll make introductions.

-
+ -
-
+
+ - +
+ + +
- +
+ + +
- +
+ + +

The total CAPEX from your financial plan.

+
- +
+ + +
- + -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/leads/templates/suppliers.html b/padelnomics/src/padelnomics/leads/templates/suppliers.html index d29ffde..3b755e9 100644 --- a/padelnomics/src/padelnomics/leads/templates/suppliers.html +++ b/padelnomics/src/padelnomics/leads/templates/suppliers.html @@ -2,35 +2,39 @@ {% block title %}Get Court Supplier Quotes - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-

Get Court Supplier Quotes

+
+
+

Get Court Supplier Quotes

Tell us about your project and we'll connect you with verified padel court suppliers who can provide detailed quotes.

-
+ -
-
+
+ - +
+ + +
- +
+ + +
- +
+ + +

Optional — helps suppliers tailor their proposals.

+
- +
+ + +
- + -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/public/templates/about.html b/padelnomics/src/padelnomics/public/templates/about.html index e35157c..bc6924d 100644 --- a/padelnomics/src/padelnomics/public/templates/about.html +++ b/padelnomics/src/padelnomics/public/templates/about.html @@ -3,33 +3,31 @@ {% block title %}About - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

About {{ config.APP_NAME }}

-
+
+
+

About {{ config.APP_NAME }}

-
+

Padel is the fastest-growing sport in Europe, but opening a padel hall is still a leap of faith for most entrepreneurs. The financials are complex: CAPEX varies wildly depending on venue type, location drives utilization, and the difference between a 60% and 75% occupancy rate can mean the difference between a great investment and a money pit.

We built Padelnomics because we couldn't find a financial planning tool that was good enough. Existing calculators are either too simplistic (5 inputs, one output) or locked behind expensive consulting engagements. We wanted something with the depth of a professional financial model but the accessibility of a web app.

The result is a free financial planner with 60+ adjustable variables, 6 analysis tabs, sensitivity analysis, and the professional metrics that banks and investors need to see. Every assumption is transparent and adjustable. No black boxes.

-

Why free?

+

Why free?

The planner is free because we believe better planning leads to better padel venues, and that's good for the entire industry. We make money by connecting entrepreneurs with court suppliers and financing partners when they're ready to move from planning to building.

-

What's next

+

What's next

Padelnomics is building the infrastructure for padel entrepreneurship. After planning comes financing, building, and operating. We're working on market intelligence powered by real booking data, a supplier marketplace for court equipment, and analytics tools for venue operators.

-
+
-
+
{% if user %} - Open Planner + Open Planner {% else %} - Create Free Account + Create Free Account {% endif %} -
-
+ +
{% endblock %} diff --git a/padelnomics/src/padelnomics/public/templates/features.html b/padelnomics/src/padelnomics/public/templates/features.html index d21a3ac..6731764 100644 --- a/padelnomics/src/padelnomics/public/templates/features.html +++ b/padelnomics/src/padelnomics/public/templates/features.html @@ -7,76 +7,70 @@ {% endblock %} {% block content %} -
-
-

Everything You Need to Plan Your Padel Business

-

Professional-grade financial modeling, completely free.

+
+
+

Everything You Need to Plan Your Padel Business

+

Professional-grade financial modeling, completely free.

-
-
-

60+ Variables

-

Every assumption is adjustable. Court costs, rent, hourly pricing, utilization curves, financing terms, exit multiples. Nothing is hard-coded — your model reflects your reality.

-
- -
-

6 Analysis Tabs

-

Assumptions, Investment (CAPEX), Operating Model, Cash Flow, Returns & Exit, and Key Metrics. Each tab with interactive charts that update in real time as you adjust inputs.

-
+
+
+

60+ Variables

+

Every assumption is adjustable. Court costs, rent, hourly pricing, utilization curves, financing terms, exit multiples. Nothing is hard-coded — your model reflects your reality.

+
+
+

6 Analysis Tabs

+

Assumptions, Investment (CAPEX), Operating Model, Cash Flow, Returns & Exit, and Key Metrics. Each tab with interactive charts that update in real time as you adjust inputs.

+
-
-
-

Indoor & Outdoor

-

Model indoor halls (rent an existing building or build new) and outdoor courts with seasonality adjustments. Compare scenarios side by side to find the best approach for your market.

-
- -
-

Sensitivity Analysis

-

See how your IRR and cash yield change across different utilization rates and pricing levels. Find your break-even point instantly with the built-in sensitivity matrix.

-
+
+
+

Indoor & Outdoor

+

Model indoor halls (rent an existing building or build new) and outdoor courts with seasonality adjustments. Compare scenarios side by side to find the best approach for your market.

+
+
+

Sensitivity Analysis

+

See how your IRR and cash yield change across different utilization rates and pricing levels. Find your break-even point instantly with the built-in sensitivity matrix.

+
-
-
-

Professional Metrics

-

IRR, MOIC, DSCR, cash-on-cash yield, break-even utilization, RevPAH, debt yield. The metrics banks and investors expect to see in a padel court business plan.

-
- -
-

Save & Compare

-

Save unlimited scenarios. Test different locations, court counts, financing structures, and pricing strategies. Load and compare to find the optimal plan for your investment.

-
+
+
+

Professional Metrics

+

IRR, MOIC, DSCR, cash-on-cash yield, break-even utilization, RevPAH, debt yield. The metrics banks and investors expect to see in a padel court business plan.

+
+
+

Save & Compare

+

Save unlimited scenarios. Test different locations, court counts, financing structures, and pricing strategies. Load and compare to find the optimal plan for your investment.

+
-
-
-

Detailed CAPEX Breakdown

-

Model every cost line individually: court installation, flooring, lighting, climate control, changing rooms, reception, parking, landscaping. Toggle between renting a building and constructing new. Adjust land costs, construction costs per sqm, and fit-out budgets independently.

-
+
+
+

Detailed CAPEX Breakdown

+

Model every cost line individually: court installation, flooring, lighting, climate control, changing rooms, reception, parking, landscaping. Toggle between renting a building and constructing new. Adjust land costs, construction costs per sqm, and fit-out budgets independently.

+
+
+

Operating Model

+

Peak and off-peak pricing with configurable hour splits. Monthly utilization ramp-up curves. Staff costs, maintenance, insurance, marketing, and utilities — all adjustable with sliders. Revenue from court rentals, coaching, equipment, and F&B.

+
+
+

Cash Flow & Financing

+

10-year monthly cash flow projections. Model your equity/debt split, interest rates, and loan terms. See debt service coverage ratios and free cash flow month by month. Waterfall charts show exactly where your money goes.

+
+
+

Returns & Exit

+

Calculate your equity IRR and MOIC under different exit scenarios. Model cap rate exits with configurable holding periods. See your equity waterfall from initial investment through to exit proceeds.

+
+
-
-

Operating Model

-

Peak and off-peak pricing with configurable hour splits. Monthly utilization ramp-up curves. Staff costs, maintenance, insurance, marketing, and utilities — all adjustable with sliders. Revenue from court rentals, coaching, equipment, and F&B.

-
- -
-

Cash Flow & Financing

-

10-year monthly cash flow projections. Model your equity/debt split, interest rates, and loan terms. See debt service coverage ratios and free cash flow month by month. Waterfall charts show exactly where your money goes.

-
- -
-

Returns & Exit

-

Calculate your equity IRR and MOIC under different exit scenarios. Model cap rate exits with configurable holding periods. See your equity waterfall from initial investment through to exit proceeds.

-
-
- -
+
{% if user %} - Open Planner + Open Planner {% else %} - Create Free Account + Create Free Account {% endif %} -
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/public/templates/landing.html b/padelnomics/src/padelnomics/public/templates/landing.html index a367c7b..f8a6f42 100644 --- a/padelnomics/src/padelnomics/public/templates/landing.html +++ b/padelnomics/src/padelnomics/public/templates/landing.html @@ -10,29 +10,8 @@ {% endblock %} {% block content %} -
+
-
-

Plan Your Padel Business
in Minutes, Not Months

-

+

+

Plan Your Padel Business
in Minutes, Not Months

+

Model your padel court investment with 60+ variables, sensitivity analysis, and professional-grade projections.

-
-
-

Quick ROI Estimate

+
+
+

Quick ROI Estimate

-
- - - 6 -
-
- - - €50/hr -
-
- - - 40% -
-
- - - €30K -
-
- - - 25% -
- -

Assumes €8/m² rent, 5% interest, 10-year loan, 300 m² per court

- -
-
-
Total Investment
-
-
CAPEX (rent model)
+
+
+ + + 6
-
-
Monthly Cash Flow
-
-
After debt service
+
+ + + €50/hr
-
-
Payback Period
-
-
Years to recover equity
+
+ + + 40%
-
-
Cash-on-Cash
-
-
Annual return on equity
+
+ + + €30K +
+
+ + + 25%
-
-

Want the full picture? The planner models 60+ variables with monthly projections, sensitivity analysis, and connects you with court suppliers.

+

Assumes €8/m² rent, 5% interest, 10-year loan, 300 m² per court

+ +
+
+
Total Investment
+
+
CAPEX (rent model)
+
+
+
Monthly Cash Flow
+
+
After debt service
+
+
+
Payback Period
+
+
Years to recover equity
+
+
+
Cash-on-Cash
+
+
Annual return on equity
+
+
+ +
+

Want the full picture? The planner models 60+ variables with monthly projections, sensitivity analysis, and connects you with court suppliers.

{% if user %} - Start Planning + Start Planning {% else %} - Create Your Plan + Create Your Plan {% endif %}
-
-

From Idea to Operating Hall

-
-
-
Plan
-

Model your padel hall investment with our financial planner. CAPEX, operating costs, cash flow, returns, sensitivity analysis.

-
-
-
Finance
-

Connect with banks and investors experienced in sports facility loans. Your planner data becomes your business case.

-
-
-
Build
-

Get quotes from verified court suppliers. Compare pricing, quality, and delivery timelines for your specific project.

-
-
-
Operate
-

Coming soon: analytics powered by real booking data, benchmarking against similar venues, optimization recommendations.

-
+
+

From Idea to Operating Hall

+
+
+

📊 Plan

+

Model your padel hall investment with our financial planner. CAPEX, operating costs, cash flow, returns, sensitivity analysis.

+
+
+

💰 Finance

+

Connect with banks and investors experienced in sports facility loans. Your planner data becomes your business case.

+
+
+

🏗️ Build

+

Get quotes from verified court suppliers. Compare pricing, quality, and delivery timelines for your specific project.

+
+
+

🎾 Operate

+

Coming soon: analytics powered by real booking data, benchmarking against similar venues, optimization recommendations.

+
-
-

Built for Serious Padel Entrepreneurs

-
-
-

60+ Variables

-

Every assumption is adjustable. Court costs, rent, pricing, utilization, financing terms, exit scenarios. Nothing is hard-coded.

-
-
-

6 Analysis Tabs

-

Assumptions, Investment (CAPEX), Operating Model, Cash Flow, Returns & Exit, and Key Metrics. Each with interactive charts.

-
-
-

Indoor & Outdoor

-

Model indoor halls (rent or build) and outdoor courts with seasonality. Compare scenarios side by side.

-
+
+

Built for Serious Padel Entrepreneurs

+
+
+

🔧 60+ Variables

+

Every assumption is adjustable. Court costs, rent, pricing, utilization, financing terms, exit scenarios. Nothing is hard-coded.

+
+
+

📋 6 Analysis Tabs

+

Assumptions, Investment (CAPEX), Operating Model, Cash Flow, Returns & Exit, and Key Metrics. Each with interactive charts.

+
+
+

☀️ Indoor & Outdoor

+

Model indoor halls (rent or build) and outdoor courts with seasonality. Compare scenarios side by side.

+
-
-
-

Sensitivity Analysis

-

See how your returns change with different utilization rates and pricing. Find your break-even point instantly.

-
-
-

Professional Metrics

-

IRR, MOIC, DSCR, cash-on-cash yield, break-even utilization, RevPAH, debt yield. The metrics banks and investors want to see.

-
-
-

Save & Compare

-

Save unlimited scenarios. Test different locations, court counts, financing structures. Find the optimal plan.

-
+
+
+

📉 Sensitivity Analysis

+

See how your returns change with different utilization rates and pricing. Find your break-even point instantly.

+
+
+

🎯 Professional Metrics

+

IRR, MOIC, DSCR, cash-on-cash yield, break-even utilization, RevPAH, debt yield. The metrics banks and investors want to see.

+
+
+

💾 Save & Compare

+

Save unlimited scenarios. Test different locations, court counts, financing structures. Find the optimal plan.

+
-
-

Padel Court Investment Planning

-

- Padel is the fastest-growing sport in Europe, with demand for courts far outstripping supply in Germany, the UK, Scandinavia, and beyond. Opening a padel hall can be a lucrative investment, but the numbers need to work. A typical indoor padel venue with 6-8 courts requires between €300K (renting an existing building) and €2-3M (building new), with payback periods of 3-5 years for well-located venues. -

-

- The key variables that determine success are location (driving utilization), construction costs (CAPEX), rent or land costs, and pricing strategy. Our financial planner lets you model all of these variables interactively, seeing the impact on your IRR, MOIC, cash flow, and debt service coverage ratio in real time. Whether you're an entrepreneur exploring your first venue, a real estate developer adding padel to a mixed-use project, or an investor evaluating a padel hall acquisition, Padelnomics gives you the financial clarity to make informed decisions. -

+
+

Padel Court Investment Planning

+
+

+ Padel is the fastest-growing sport in Europe, with demand for courts far outstripping supply in Germany, the UK, Scandinavia, and beyond. Opening a padel hall can be a lucrative investment, but the numbers need to work. A typical indoor padel venue with 6-8 courts requires between €300K (renting an existing building) and €2-3M (building new), with payback periods of 3-5 years for well-located venues. +

+

+ The key variables that determine success are location (driving utilization), construction costs (CAPEX), rent or land costs, and pricing strategy. Our financial planner lets you model all of these variables interactively, seeing the impact on your IRR, MOIC, cash flow, and debt service coverage ratio in real time. Whether you're an entrepreneur exploring your first venue, a real estate developer adding padel to a mixed-use project, or an investor evaluating a padel hall acquisition, Padelnomics gives you the financial clarity to make informed decisions. +

+
-
-

Start Planning Today

-

Start with your plan. Then get quotes from verified court suppliers and connect with financing partners.

+
+

Start Planning Today

+

Start with your plan. Then get quotes from verified court suppliers and connect with financing partners.

{% if user %} - Start Planning + Start Planning {% else %} - Create Your Plan + Create Your Plan {% endif %}
@@ -334,24 +260,24 @@ function tCalc() { var cfEl = document.getElementById('tr-cf'); cfEl.innerHTML = fmt(netCF); - cfEl.className = 'tm-value ' + (netCF >= 0 ? 'tm-green' : 'tm-red'); + cfEl.className = 'font-mono text-2xl font-bold ' + (netCF >= 0 ? 'text-accent' : 'text-danger'); var pbEl = document.getElementById('tr-payback'); if (payback > 0 && payback <= 30) { pbEl.textContent = payback.toFixed(1) + 'yr'; - pbEl.className = 'tm-value ' + (payback <= 5 ? 'tm-blue' : 'tm-navy'); + pbEl.className = 'font-mono text-2xl font-bold ' + (payback <= 5 ? 'text-electric' : 'text-navy'); } else { pbEl.innerHTML = '—'; - pbEl.className = 'tm-value tm-red'; + pbEl.className = 'font-mono text-2xl font-bold text-danger'; } var cocEl = document.getElementById('tr-coc'); if (isFinite(coc)) { cocEl.textContent = (coc * 100).toFixed(1) + '%'; - cocEl.className = 'tm-value ' + (coc >= 0 ? 'tm-green' : 'tm-red'); + cocEl.className = 'font-mono text-2xl font-bold ' + (coc >= 0 ? 'text-accent' : 'text-danger'); } else { cocEl.innerHTML = '—'; - cocEl.className = 'tm-value tm-navy'; + cocEl.className = 'font-mono text-2xl font-bold text-navy'; } } diff --git a/padelnomics/src/padelnomics/public/templates/privacy.html b/padelnomics/src/padelnomics/public/templates/privacy.html index a24ee35..26a2653 100644 --- a/padelnomics/src/padelnomics/public/templates/privacy.html +++ b/padelnomics/src/padelnomics/public/templates/privacy.html @@ -3,90 +3,90 @@ {% block title %}Privacy Policy - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Privacy Policy

-

Last updated: February 2026

-
- -
-

1. Information We Collect

-

We collect information you provide directly:

-
    -
  • Email address (required for account creation)
  • -
  • Name (optional)
  • -
  • Financial planning data (scenario inputs and projections)
  • -
-

We automatically collect:

-
    -
  • IP address
  • -
  • Browser type
  • -
  • Usage data
  • -
-
- -
-

2. How We Use Information

-

We use your information to:

-
    -
  • Provide and maintain the service
  • -
  • Process payments
  • -
  • Send transactional emails
  • -
  • Improve the service
  • -
  • Respond to support requests
  • -
-
- -
-

3. Information Sharing

-

We do not sell your personal information. We may share information with:

-
    -
  • Service providers (Resend for email, Plausible for privacy-friendly analytics)
  • -
  • Law enforcement when required by law
  • -
-
- -
-

4. Data Retention

-

We retain your data as long as your account is active. Upon deletion, we remove your data within 30 days.

-
- -
-

5. Security

-

We implement industry-standard security measures including encryption, secure sessions, and regular backups.

-
- -
-

6. Cookies

-

We use essential cookies for session management. We do not use tracking or advertising cookies.

-
- -
-

7. Your Rights

-

You have the right to:

-
    -
  • Access your data
  • -
  • Correct inaccurate data
  • -
  • Delete your account and data
  • -
  • Export your data
  • -
-
- -
-

8. GDPR Compliance

-

For EU users: We process data based on consent and legitimate interest. You may contact us to exercise your GDPR rights.

-
- -
-

9. Changes

-

We may update this policy. We will notify you of significant changes via email.

-
- -
-

10. Contact

-

For privacy inquiries: {{ config.EMAIL_FROM }}

-
-
+
+
+

Privacy Policy

+

Last updated: February 2026

+ +
+
+

1. Information We Collect

+

We collect information you provide directly:

+
    +
  • Email address (required for account creation)
  • +
  • Name (optional)
  • +
  • Financial planning data (scenario inputs and projections)
  • +
+

We automatically collect:

+
    +
  • IP address
  • +
  • Browser type
  • +
  • Usage data
  • +
+
+ +
+

2. How We Use Information

+

We use your information to:

+
    +
  • Provide and maintain the service
  • +
  • Process payments
  • +
  • Send transactional emails
  • +
  • Improve the service
  • +
  • Respond to support requests
  • +
+
+ +
+

3. Information Sharing

+

We do not sell your personal information. We may share information with:

+
    +
  • Service providers (Resend for email, Plausible for privacy-friendly analytics)
  • +
  • Law enforcement when required by law
  • +
+
+ +
+

4. Data Retention

+

We retain your data as long as your account is active. Upon deletion, we remove your data within 30 days.

+
+ +
+

5. Security

+

We implement industry-standard security measures including encryption, secure sessions, and regular backups.

+
+ +
+

6. Cookies

+

We use essential cookies for session management. We do not use tracking or advertising cookies.

+
+ +
+

7. Your Rights

+

You have the right to:

+
    +
  • Access your data
  • +
  • Correct inaccurate data
  • +
  • Delete your account and data
  • +
  • Export your data
  • +
+
+ +
+

8. GDPR Compliance

+

For EU users: We process data based on consent and legitimate interest. You may contact us to exercise your GDPR rights.

+
+ +
+

9. Changes

+

We may update this policy. We will notify you of significant changes via email.

+
+ +
+

10. Contact

+

For privacy inquiries: {{ config.EMAIL_FROM }}

+
+
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/public/templates/terms.html b/padelnomics/src/padelnomics/public/templates/terms.html index cf349fc..c99d9dd 100644 --- a/padelnomics/src/padelnomics/public/templates/terms.html +++ b/padelnomics/src/padelnomics/public/templates/terms.html @@ -3,69 +3,69 @@ {% block title %}Terms of Service - {{ config.APP_NAME }}{% endblock %} {% block content %} -
-
-
-

Terms of Service

-

Last updated: February 2026

-
- -
-

1. Acceptance of Terms

-

By accessing or using {{ config.APP_NAME }}, you agree to be bound by these Terms of Service. If you do not agree, do not use the service.

-
- -
-

2. Description of Service

-

{{ config.APP_NAME }} provides a software-as-a-service platform. Features and functionality may change over time.

-
- -
-

3. User Accounts

-

You are responsible for maintaining the security of your account. You must provide accurate information and keep it updated.

-
- -
-

4. Acceptable Use

-

You agree not to:

-
    -
  • Violate any laws or regulations
  • -
  • Infringe on intellectual property rights
  • -
  • Transmit harmful code or malware
  • -
  • Attempt to gain unauthorized access
  • -
  • Interfere with service operation
  • -
-
- -
-

5. Financial Projections Disclaimer

-

The financial planner provides estimates based on your inputs. Projections are not guarantees of future performance. Always consult qualified financial and legal advisors before making investment decisions.

-
- -
-

6. Termination

-

We may terminate or suspend your account for violations of these terms. You may cancel your account at any time.

-
- -
-

7. Disclaimer of Warranties

-

The service is provided "as is" without warranties of any kind. We do not guarantee uninterrupted or error-free operation.

-
- -
-

8. Limitation of Liability

-

We shall not be liable for any indirect, incidental, special, or consequential damages arising from use of the service.

-
- -
-

9. Changes to Terms

-

We may modify these terms at any time. Continued use after changes constitutes acceptance of the new terms.

-
- -
-

10. Contact

-

For questions about these terms, please contact us at {{ config.EMAIL_FROM }}.

-
-
+
+
+

Terms of Service

+

Last updated: February 2026

+ +
+
+

1. Acceptance of Terms

+

By accessing or using {{ config.APP_NAME }}, you agree to be bound by these Terms of Service. If you do not agree, do not use the service.

+
+ +
+

2. Description of Service

+

{{ config.APP_NAME }} provides a software-as-a-service platform. Features and functionality may change over time.

+
+ +
+

3. User Accounts

+

You are responsible for maintaining the security of your account. You must provide accurate information and keep it updated.

+
+ +
+

4. Acceptable Use

+

You agree not to:

+
    +
  • Violate any laws or regulations
  • +
  • Infringe on intellectual property rights
  • +
  • Transmit harmful code or malware
  • +
  • Attempt to gain unauthorized access
  • +
  • Interfere with service operation
  • +
+
+ +
+

5. Financial Projections Disclaimer

+

The financial planner provides estimates based on your inputs. Projections are not guarantees of future performance. Always consult qualified financial and legal advisors before making investment decisions.

+
+ +
+

6. Termination

+

We may terminate or suspend your account for violations of these terms. You may cancel your account at any time.

+
+ +
+

7. Disclaimer of Warranties

+

The service is provided "as is" without warranties of any kind. We do not guarantee uninterrupted or error-free operation.

+
+ +
+

8. Limitation of Liability

+

We shall not be liable for any indirect, incidental, special, or consequential damages arising from use of the service.

+
+ +
+

9. Changes to Terms

+

We may modify these terms at any time. Continued use after changes constitutes acceptance of the new terms.

+
+ +
+

10. Contact

+

For questions about these terms, please contact us at {{ config.EMAIL_FROM }}.

+
+
+
{% endblock %} diff --git a/padelnomics/src/padelnomics/static/css/custom.css b/padelnomics/src/padelnomics/static/css/custom.css deleted file mode 100644 index 0c5a6e7..0000000 --- a/padelnomics/src/padelnomics/static/css/custom.css +++ /dev/null @@ -1,83 +0,0 @@ -/* Padelnomics — Court Tech brand overrides for Pico CSS */ - -:root[data-theme="light"] { - /* Background layers — Soft White family */ - --pico-background-color: #F8FAFC; - --pico-card-background-color: #FFFFFF; - --pico-card-sectioning-background-color: #F1F5F9; - - /* Text — Slate / Deep Navy */ - --pico-color: #475569; - --pico-muted-color: #64748B; - --pico-muted-border-color: #E2E8F0; - - /* Headings — Deep Navy (overrides Pico's per-level grays) */ - --pico-h1-color: #0F172A; - --pico-h2-color: #0F172A; - --pico-h3-color: #1E293B; - --pico-h4-color: #1E293B; - --pico-h5-color: #334155; - --pico-h6-color: #334155; - - /* Primary accent — Electric Blue */ - --pico-primary: #3B82F6; - --pico-primary-hover: #2563EB; - --pico-primary-focus: rgba(59,130,246,0.25); - --pico-primary-inverse: #fff; - - /* Secondary — Slate */ - --pico-secondary: #64748B; - --pico-secondary-hover: #475569; - --pico-secondary-focus: rgba(100,116,139,0.25); - --pico-secondary-inverse: #F8FAFC; - - /* Typography — Inter */ - --pico-font-family: 'Inter', system-ui, -apple-system, sans-serif; - --pico-font-family-monospace: 'JetBrains Mono', monospace; - - /* Borders */ - --pico-border-color: #E2E8F0; - - /* Form styling */ - --pico-form-element-background-color: #FFFFFF; - --pico-form-element-border-color: #CBD5E1; - --pico-form-element-focus-color: #3B82F6; -} - -/* Headings — Deep Navy, Inter - Force heading colors with !important to beat Pico's multi-layer - variable cascade (theme selectors + prefers-color-scheme media). */ -h1, h2, h3, h4, h5, h6 { - color: #0F172A !important; - font-family: 'Inter', system-ui, -apple-system, sans-serif; -} -h4, h5, h6 { - color: #1E293B !important; -} - -/* Data & metrics use monospace */ -.metric, .mono, [data-mono] { - font-family: 'JetBrains Mono', monospace; -} - -/* Success states — Vibrant Green */ -.success, [data-success] { - color: #10B981; -} - -article { - margin-bottom: 1.5rem; -} - -table { - width: 100%; -} - -/* HTMX loading indicators */ -.htmx-indicator { - display: none; -} -.htmx-request .htmx-indicator, -.htmx-request.htmx-indicator { - display: inline; -} diff --git a/padelnomics/src/padelnomics/static/css/input.css b/padelnomics/src/padelnomics/static/css/input.css new file mode 100644 index 0000000..a884353 --- /dev/null +++ b/padelnomics/src/padelnomics/static/css/input.css @@ -0,0 +1,204 @@ +@import "tailwindcss"; + +/* ── Commit Mono (self-hosted) ── */ +@font-face { + font-family: "Commit Mono"; + src: url("../fonts/CommitMono-400-Regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "Commit Mono"; + src: url("../fonts/CommitMono-700-Regular.woff2") format("woff2"); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +/* ── Brand Theme ── */ +@theme { + --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif; + --font-mono: "Commit Mono", ui-monospace, monospace; + + --color-navy: #0F172A; + --color-charcoal: #1E293B; + --color-electric: #3B82F6; + --color-electric-hover: #2563EB; + --color-accent: #10B981; + --color-soft-white: #F8FAFC; + --color-light-gray: #E2E8F0; + --color-mid-gray: #CBD5E1; + --color-slate: #64748B; + --color-slate-dark: #475569; + --color-danger: #EF4444; + --color-danger-hover: #DC2626; + --color-warning: #F59E0B; +} + +/* ── Base layer ── */ +@layer base { + body { + @apply bg-soft-white text-slate-dark font-sans antialiased; + } + h1, h2, h3 { + @apply text-navy font-bold tracking-tight; + } + h4, h5, h6 { + @apply text-charcoal font-semibold; + } + a { + @apply text-electric hover:text-electric-hover transition-colors; + } + hr { + @apply border-light-gray my-6; + } +} + +/* ── Component classes ── */ +@layer components { + /* Page container */ + .container-page { + @apply max-w-6xl mx-auto px-4 sm:px-6 lg:px-8; + } + + /* Cards (replace Pico
) */ + .card { + @apply bg-white border border-light-gray rounded-lg p-6 mb-6; + } + .card-header { + @apply border-b border-light-gray pb-3 mb-4 text-sm text-slate font-medium; + } + + /* Buttons — shared base */ + .btn, .btn-secondary, .btn-danger { + @apply inline-flex items-center justify-center px-5 py-2.5 rounded-lg + font-semibold text-sm transition-colors cursor-pointer + focus:outline-none focus:ring-2 focus:ring-electric/50; + } + .btn { + @apply bg-electric text-white hover:bg-electric-hover; + } + .btn-secondary { + @apply bg-slate-dark text-white hover:bg-navy; + } + .btn-danger { + @apply bg-danger text-white hover:bg-danger-hover; + } + .btn-outline { + @apply inline-flex items-center justify-center px-5 py-2.5 rounded-lg + font-semibold text-sm transition-colors cursor-pointer + bg-transparent text-slate-dark border border-mid-gray + hover:bg-light-gray hover:text-navy + focus:outline-none focus:ring-2 focus:ring-electric/50; + } + .btn-sm { + @apply px-3 py-1.5 text-xs; + } + + /* Forms */ + .form-label { + @apply block text-sm font-medium text-charcoal mb-1; + } + .form-input { + @apply w-full px-3 py-2 rounded-lg border border-mid-gray bg-white + text-slate-dark placeholder-slate + focus:outline-none focus:ring-2 focus:ring-electric/50 focus:border-electric + transition-colors; + } + .form-hint { + @apply text-xs text-slate mt-1; + } + + /* Tables */ + .table { + @apply w-full text-sm; + } + .table th { + @apply text-left px-3 py-2 text-xs font-semibold text-slate uppercase tracking-wider + border-b-2 border-light-gray; + } + .table td { + @apply px-3 py-2 border-b border-light-gray text-slate-dark; + } + .table tbody tr:hover { + @apply bg-soft-white; + } + + /* Flash messages */ + .flash, .flash-error, .flash-success, .flash-warning { + @apply px-4 py-3 rounded-lg mb-4 border-l-4 bg-white text-slate-dark text-sm; + } + .flash { + @apply border-electric; + } + .flash-error { + @apply border-danger; + } + .flash-success { + @apply border-accent; + } + .flash-warning { + @apply border-warning; + } + + /* Badge (replaces Pico ) */ + .badge, .badge-success, .badge-danger, .badge-warning { + @apply inline-block px-2 py-0.5 text-xs font-semibold rounded-full; + } + .badge { + @apply bg-electric/10 text-electric; + } + .badge-success { + @apply bg-accent/10 text-accent; + } + .badge-danger { + @apply bg-danger/10 text-danger; + } + .badge-warning { + @apply bg-warning/10 text-warning; + } + + /* Heading group (replaces Pico
) */ + .heading-group { + @apply mb-6; + } + .heading-group h1, + .heading-group h2 { + @apply mb-1; + } + .heading-group p { + @apply text-slate text-lg; + } + + /* Grid helpers (replaces Pico .grid) */ + .grid-auto { + @apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6; + } + .grid-2 { + @apply grid grid-cols-1 md:grid-cols-2 gap-6; + } + .grid-3 { + @apply grid grid-cols-1 md:grid-cols-3 gap-6; + } + .grid-4 { + @apply grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6; + } + + /* Monospace data display */ + .metric { + @apply font-mono text-navy; + } + .mono { + @apply font-mono; + } + + /* HTMX loading indicators */ + .htmx-indicator { + display: none; + } + .htmx-request .htmx-indicator, + .htmx-request.htmx-indicator { + display: inline; + } +} diff --git a/padelnomics/src/padelnomics/static/fonts/CommitMono-400-Regular.woff2 b/padelnomics/src/padelnomics/static/fonts/CommitMono-400-Regular.woff2 new file mode 100644 index 0000000..011d67c Binary files /dev/null and b/padelnomics/src/padelnomics/static/fonts/CommitMono-400-Regular.woff2 differ diff --git a/padelnomics/src/padelnomics/static/fonts/CommitMono-700-Regular.woff2 b/padelnomics/src/padelnomics/static/fonts/CommitMono-700-Regular.woff2 new file mode 100644 index 0000000..af84f79 Binary files /dev/null and b/padelnomics/src/padelnomics/static/fonts/CommitMono-700-Regular.woff2 differ diff --git a/padelnomics/src/padelnomics/static/fonts/CommitMono-LICENSE.txt b/padelnomics/src/padelnomics/static/fonts/CommitMono-LICENSE.txt new file mode 100644 index 0000000..96d39dd --- /dev/null +++ b/padelnomics/src/padelnomics/static/fonts/CommitMono-LICENSE.txt @@ -0,0 +1,90 @@ +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/padelnomics/src/padelnomics/templates/base.html b/padelnomics/src/padelnomics/templates/base.html index 3eceeab..2800c1f 100644 --- a/padelnomics/src/padelnomics/templates/base.html +++ b/padelnomics/src/padelnomics/templates/base.html @@ -1,5 +1,5 @@ - + @@ -10,57 +10,46 @@ - - - - + - - + + {% block head %}{% endblock %} - {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} -
+
{% for category, message in messages %} -
+
{{ message }} -
+
{% endfor %}
{% endif %} @@ -69,31 +58,31 @@ {% block content %}{% endblock %} -