import { LitElement, html, css } from 'lit'; import { customElement } from 'lit/decorators.js'; import '../components/ui-card'; import '../components/ui-button'; import '../components/ui-link'; @customElement('home-page') export class HomePage extends LitElement { static styles = css` :host { flex: 1; display: flex; flex-direction: column; } .hero { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; padding: 5rem 1.5rem 4rem; background: radial-gradient( ellipse at 40% 0%, color-mix(in srgb, var(--color-accent) 18%, transparent) 0%, transparent 55% ), radial-gradient( ellipse at 80% 60%, color-mix(in srgb, var(--color-accent) 8%, transparent) 0%, transparent 50% ), var(--color-bg); overflow: hidden; } .hero::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 1px; background: var(--color-border); } .hero-badge { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.35rem 0.85rem; font-size: 0.78rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 10%, transparent); border: 1px solid color-mix(in srgb, var(--color-accent) 25%, transparent); border-radius: 2rem; margin-bottom: 1.5rem; } .hero-badge svg { width: 0.85rem; height: 0.85rem; } .hero h1 { margin: 0; font-size: clamp(2.2rem, 5vw, 3.5rem); font-weight: 800; letter-spacing: -0.03em; line-height: 1.1; color: var(--color-text); max-width: 700px; } .hero h1 span { background: linear-gradient( 135deg, var(--color-accent), color-mix(in srgb, var(--color-accent) 60%, transparent) ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .hero-sub { margin: 1.25rem 0 2rem; font-size: 1.05rem; line-height: 1.65; color: color-mix(in srgb, var(--color-text) 60%, transparent); max-width: 520px; } .hero-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; justify-content: center; } .btn-secondary { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.65rem 1.25rem; font-size: 0.95rem; font-weight: 600; color: var(--color-text); background: transparent; border: 1px solid var(--color-border); border-radius: 0.5rem; cursor: pointer; transition: border-color 0.25s ease, color 0.25s ease, background 0.25s ease; } .btn-secondary:hover { border-color: var(--color-accent); color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 6%, transparent); } section { padding: 4rem 1.5rem; max-width: 1100px; margin: 0 auto; width: 100%; } section + section { border-top: 1px solid var(--color-border); } .section-label { font-size: 0.78rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--color-accent); margin: 0 0 0.5rem; } .section-title { margin: 0 0 0.5rem; font-size: 1.75rem; font-weight: 700; letter-spacing: -0.02em; color: var(--color-text); } .section-desc { margin: 0 0 2.5rem; font-size: 0.95rem; color: color-mix(in srgb, var(--color-text) 55%, transparent); max-width: 520px; line-height: 1.6; } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; } .stat-card { background: var(--color-bg-nav); border: 1px solid var(--color-border); border-radius: 0.75rem; padding: 1.5rem; display: flex; flex-direction: column; gap: 0.25rem; transition: border-color 0.25s ease; } .stat-card:hover { border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); } .stat-value { font-size: 2rem; font-weight: 800; letter-spacing: -0.03em; color: var(--color-accent); } .stat-label { font-size: 0.85rem; color: color-mix(in srgb, var(--color-text) 55%, transparent); font-weight: 500; } .features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.25rem; } .feature-card { background: var(--color-bg-nav); border: 1px solid var(--color-border); border-radius: 0.75rem; padding: 1.75rem; display: flex; flex-direction: column; gap: 0.75rem; transition: border-color 0.25s ease; } .feature-card:hover { border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); } .feature-icon { width: 2.25rem; height: 2.25rem; display: grid; place-items: center; border-radius: 0.5rem; background: color-mix(in srgb, var(--color-accent) 10%, transparent); color: var(--color-accent); } .feature-icon svg { width: 1.15rem; height: 1.15rem; } .feature-card h3 { margin: 0; font-size: 1rem; font-weight: 650; color: var(--color-text); } .feature-card p { margin: 0; font-size: 0.875rem; line-height: 1.6; color: color-mix(in srgb, var(--color-text) 55%, transparent); } .competitions-list { display: flex; flex-direction: column; gap: 0.75rem; } .comp-row { display: flex; align-items: center; gap: 1.25rem; background: var(--color-bg-nav); border: 1px solid var(--color-border); border-radius: 0.75rem; padding: 1.25rem 1.5rem; transition: border-color 0.25s ease; cursor: pointer; } .comp-row:hover { border-color: color-mix(in srgb, var(--color-accent) 40%, transparent); } .comp-date { display: flex; flex-direction: column; align-items: center; min-width: 3.5rem; padding: 0.5rem 0.65rem; background: color-mix(in srgb, var(--color-accent) 10%, transparent); border-radius: 0.5rem; flex-shrink: 0; } .comp-date-day { font-size: 1.25rem; font-weight: 800; color: var(--color-accent); line-height: 1; } .comp-date-month { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-accent); margin-top: 0.15rem; } .comp-info { flex: 1; display: flex; flex-direction: column; gap: 0.2rem; } .comp-name { font-size: 1rem; font-weight: 650; color: var(--color-text); } .comp-location { display: flex; align-items: center; gap: 0.3rem; font-size: 0.82rem; color: color-mix(in srgb, var(--color-text) 50%, transparent); } .comp-location svg { width: 0.8rem; height: 0.8rem; flex-shrink: 0; } .comp-badge { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; padding: 0.3rem 0.7rem; border-radius: 2rem; flex-shrink: 0; } .comp-badge.upcoming { color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 10%, transparent); border: 1px solid color-mix(in srgb, var(--color-accent) 25%, transparent); } .comp-badge.live { color: #30a46c; background: color-mix(in srgb, #30a46c 10%, transparent); border: 1px solid color-mix(in srgb, #30a46c 25%, transparent); } .comp-badge.ended { color: color-mix(in srgb, var(--color-text) 45%, transparent); background: color-mix(in srgb, var(--color-text) 6%, transparent); border: 1px solid var(--color-border); } @media (max-width: 600px) { .hero { padding: 3.5rem 1.25rem 3rem; } section { padding: 3rem 1.25rem; } .comp-row { flex-wrap: wrap; gap: 0.75rem; } .comp-badge { margin-left: auto; } } `; private navigate(path: string) { this.dispatchEvent( new CustomEvent('nav', { detail: { path }, bubbles: true, composed: true, }) ); } render() { return html`
Track tasks, manage participants, and deliver real-time results for hot air balloon competitions worldwide.
At a glance
FlightScore powers balloon competitions across the globe.
Features
Everything organizers, judges, and pilots need in one place.
Scores update live as judges submit results. Pilots and spectators always see the latest standings.
Define and manage competition tasks with support for all standard ballooning task types.
Every pilot gets a profile with competition history, rankings, and performance statistics.
Public leaderboards let spectators follow the action from anywhere in the world.
Import GPS tracks and calculate distances to targets automatically for precise scoring.
Export final standings and detailed score sheets as PDF or CSV for official records.
Competitions
Discover balloon competitions scored with FlightScore.