Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Padeuce — The Digital Operating System for Padel

A production-quality, responsive marketing site for Padeuce, recreated from the supplied design mockup. Dark premium sports-tech aesthetic: black and deep-green surfaces, a single neon yellow-green accent, dense data interfaces and large editorial typography.

Everything is static. There is no build step, no package manager and no runtime dependency — open it with any static file server and it runs.


Contents


Technology

Area Choice Why
Markup Semantic HTML5 All copy lives in index.html and is editable without touching CSS or JS.
Styling Modern CSS, Grid + Flexbox, custom properties Layout is pure CSS; every design token is a variable in one file.
Scripting Vanilla JavaScript (two small files) Progressive enhancement only — the page is complete and navigable with JS disabled.
Icons Local SVG sprite One HTTP request, currentColor inheritance, no icon font or emoji.
Images Local SVG assets No hotlinking, no external requests, no layout shift.
Fonts System font stack with a Space Grotesk / Sora / Manrope / Inter preference Zero network cost; self-hosting is a one-line change (see below).

Deliberately not used: React, Vue, Angular, Svelte, Bootstrap, Tailwind, jQuery, any CSS framework, any inline CSS or JS, and any build tooling.

Why the CSS is split

Each file has one job, loaded in this order (order matters — later files override earlier ones):

File Responsibility
reset.css Browser normalisation. No design decisions.
variables.css Every design token: colour, spacing, radius, type scale, motion.
base.css Document defaults, typography, text utilities, focus, a11y helpers.
layout.css Containers, section rhythm, grid and split primitives.
components.css Reusable pieces: header, buttons, cards, devices, dashboards, tables.
sections.css Composition rules unique to one band of the page, ordered top-to-bottom.
responsive.css All breakpoint overrides, in one place.

Folder structure

/
├── index.html                  All page copy and structure
├── favicon.svg
├── README.md
├── assets/
│   ├── fonts/                  Drop self-hosted woff2 files here (optional)
│   ├── icons/
│   │   └── icons.svg           SVG sprite — every icon on the site
│   └── images/
│       ├── dashboards/         (reserved for dashboard screenshots)
│       ├── devices/            (reserved for device imagery)
│       ├── hero/
│       │   └── padel-court-night.jpg
│       ├── logos/
│       │   └── padeuce-mark.svg
│       └── placeholders/
│           └── avatar.svg
├── css/
│   ├── reset.css
│   ├── variables.css
│   ├── base.css
│   ├── layout.css
│   ├── components.css
│   ├── sections.css
│   └── responsive.css
└── js/
    ├── main.js                 Drawer, scroll spy, reveals, tabs, anchor focus
    └── navigation.js           Sticky header state

Running locally

Any static server works. Pick one:

# Python 3 (no install needed on macOS/Linux)
python3 -m http.server 4173

# Node
npx serve .
npx http-server -p 4173

# PHP
php -S localhost:4173

# Ruby
ruby -run -e httpd . -p 4173

Then open http://localhost:4173.

Opening index.html directly with file:// mostly works, but the SVG sprite (<use href="…">) is blocked by some browsers' file-origin rules, so icons may not appear. Use a server.


Editing the site

Page sections

index.html is commented with a numbered banner before every section:

<!-- ====================================================================
     8. TOURNAMENTS
     ==================================================================== -->

Section IDs, used by the navigation and for deep links: home, problem, opportunity, platform, players, profile, tournaments, live, ecosystem, network, why, commercial, scale, contact.

Brand colours

Edit css/variables.css only. To change the accent across the entire site:

:root {
  --color-accent: #dfff00;         /* primary neon */
  --color-accent-bright: #edff38;  /* hover state */
  --color-accent-soft: rgba(223, 255, 0, 0.12);
  --color-accent-border: rgba(223, 255, 0, 0.35);
}

The surface ramp (--color-black → --color-surface-soft) controls how dark the sections are, and --section-space controls the vertical rhythm of the whole page.

The logo

Replace assets/images/logos/padeuce-mark.svg with your own square mark (keep the viewBox square). It is referenced twice — in the header and the footer:

<img class="logo__mark" src="assets/images/logos/padeuce-mark.svg" alt="" width="32" height="32">
<span class="logo__word">Padeuce</span>

The wordmark is plain text, so edit it in place. favicon.svg is a copy of the same mark — replace it too.

Hero imagery

Swap the file and nothing else:

<img src="assets/images/hero/padel-court-night.jpg"
     alt="A blue padel court at night, lit by a floodlight above the perimeter fence"
     width="1535" height="1024" fetchpriority="high">

Update width/height to the new file's real pixel size so the browser reserves the right space. A photograph (.jpg/.webp) works exactly the same way — the darkening is applied by .hero__overlay in CSS, not baked into the file, so any image will pick up the correct treatment. Adjust object-position in css/sections.css if the crop needs nudging.

Navigation links

The header carries only the logo and the section-drawer toggle — there is no primary nav menu. All section navigation happens through the strip below the hero and the drawer (see below).

Footer columns are plain lists; add or remove <li> items inside .footer-nav__list.

Section navigation (strip + drawer)

The page has two linked navigators, both driven by the same code in main.js:

Element Where Behaviour
.section-nav Fixed bar docked to the bottom of the viewport Chip rail with prev/next step buttons and a progress rule
.deck-drawer Fixed panel on the right Toggled by .deck-toggle in the header; open state remembered in localStorage

Both highlight the current section as you scroll, and stay in sync — the strip defines the running order, and each stop collects every link pointing at it.

The two lists must be kept in sync. To add a stop, add one <li> to the strip and one to the drawer, both pointing at the same id:

<!-- strip -->
<li><a class="section-nav__chip" href="#pricing"><span class="section-nav__index">15</span><span class="section-nav__label">Pricing</span></a></li>

<!-- drawer -->
<li><a class="deck-drawer__link" href="#pricing"><span class="deck-drawer__index">15</span>Pricing</a></li>

The index numbers mirror each section's eyebrow number, so update the eyebrow too. The 01 / 14 counter and the progress rules calculate themselves.

Drawer specifics:

  • Width is one value: --drawer-width on .deck-drawer (250px, narrower on mobile).
  • Closed, the panel is visibility: hidden, so its links leave the tab order.
  • Escape closes it and returns focus to the header toggle.
  • Tapping a link closes it below 768px, where the panel covers the content.
  • It sits at z-index: 55 — over the page, under the fixed header, so the header stays usable while the drawer is open.

The fixed chrome is sized from tokens in variables.css: --header-inset and --header-bottom position the header, --section-nav-height / --section-nav-bottom size the docked bar (the latter adds clearance and the iOS safe-area inset), and --drawer-top hangs the drawer below the header. body gets --section-nav-bottom as bottom padding so the footer clears the bar, and scroll-padding-top / -bottom keep jumped-to sections clear of both.

Adding a card

Every card grid uses the same component. Copy one list item and edit the text:

<li class="card">
  <span class="icon-chip">
    <svg class="icon" aria-hidden="true"><use href="assets/icons/icons.svg#icon-club"></use></svg>
  </span>
  <span class="card__label">Clubs</span>
  <h3 class="card__title">Manual admin</h3>
  <p class="card__text">Short supporting sentence.</p>
</li>

The grid reflows automatically — .grid--3 is three columns on desktop, two on tablet and one on mobile.

Adding a revenue stream

In section 13, copy one <li class="card card--numbered card--revenue"> block and update the number, badge, title and description:

<li class="card card--numbered card--revenue">
  <span class="card__topline">
    <span class="card__number">07</span>
    <span class="badge badge--accent">Recurring</span>
  </span>
  <h3 class="card__title">New stream</h3>
  <p class="card__text">What it is and who pays for it.</p>
</li>

Use badge--accent for emphasis and plain badge for a muted label.

Adding a platform capability

In section 10, copy one .matrix__cell. The matrix is a gap-based grid, so the hairline borders redraw themselves:

<div class="matrix__cell">
  <svg class="icon" aria-hidden="true"><use href="assets/icons/icons.svg#icon-plug"></use></svg>
  <h3 class="matrix__title">Integrations</h3>
  <p class="matrix__text">One short line.</p>
</div>

Dashboard content

The dashboards are real markup, not images. The building blocks are .dashboard-frame → .dashboard-header → .dashboard-body → .dashboard-grid → .dashboard-panel, filled with .data-list, .metric, .progress-bar, .bracket and .status-chip.

To change a row, edit the text:

<div class="data-list__row">
  <span class="data-list__label"><span class="rank-index">1</span><span>Ferreira / Duarte</span></span>
  <span class="data-list__value">5.41</span>
</div>

Progress bars and the rating dial take their value from a meter class, not inline CSS:

<span class="progress-bar__track"><span class="progress-bar__fill meter-75"></span></span>
<div class="dial meter-72">…</div>

Available steps are every 5% from meter-0 to meter-100, plus the exact values the page uses. Need another? Add one line to the meter scale in css/components.css:

.meter-83 { --meter: 83%; }

Phone mockups

The hero uses a supplied vector composition rather than markup:

<img class="device-art" src="assets/images/devices/Hero-Device.svg"
     alt="…" width="592" height="981" fetchpriority="high">

Swap the file to change it, and keep the alt text describing what the screen shows — the artwork's own text is outlined, so a screen reader has nothing else to go on. --device-art-width caps how wide it renders.

The players section handset is still built from the .device-phone component. Swap the copy inside .score-display, .set-strip, .stat-grid, .player-row and .progress-bar — no CSS changes required:

<div class="score-display__side score-display__side--serving">
  <span class="score-display__points">5</span>
  <span class="score-display__team">Ferreira / Duarte</span>
</div>

--serving marks the side whose score renders in the accent colour.

Icons

All icons live in assets/icons/icons.svg as <symbol> elements sharing a 24×24 viewBox and 1.5 stroke width. Reference one by id:

<svg class="icon" aria-hidden="true"><use href="assets/icons/icons.svg#icon-trophy"></use></svg>

To add an icon, append a new <symbol id="icon-name" viewBox="0 0 24 24"> to the sprite. Icons inherit currentColor, so colour them by styling the parent.

Self-hosting fonts

Drop .woff2 files into assets/fonts/ and uncomment the @font-face block at the top of css/base.css. The --font-sans stack already lists the preferred families first, so nothing else changes.


Deployment

The site is plain static files — upload the repository root as-is.

# Netlify
netlify deploy --prod --dir .

# Vercel
vercel --prod

# Cloudflare Pages
wrangler pages deploy .

# GitHub Pages — push to the repo, then enable Pages on the branch root
# S3
aws s3 sync . s3://your-bucket --exclude ".git/*" --exclude ".claude/*"

No build command. No output directory. Set the publish directory to the project root and the entry point to index.html.

Before going live, update the absolute URLs in the <head>: canonical, og:url and the og:image / twitter:image paths.


Accessibility

Targets WCAG 2.2 AA:

  • Skip-to-content link as the first focusable element.
  • Semantic landmarks (header, nav, main, footer) and labelled <nav>s.
  • One <h1>; section headings descend in order without skipping levels.
  • Visible two-tone focus ring on every interactive element; focus is never removed.
  • The section drawer's toggle manages aria-expanded / aria-controls, closes on Escape, restores focus to the toggle, and hides its panel with visibility: hidden so closed links leave the tab order.
  • Profile tabs implement the ARIA tabs pattern with roving tabindex and Arrow/Home/End key support.
  • Icon-only controls carry .visually-hidden text labels; decorative SVGs are aria-hidden="true".
  • The comparison table uses <caption>, <th scope="col"> and <th scope="row">, and every cell pairs its icon with a text label — no meaning is carried by colour alone.
  • All interactive targets are at least 44×44px.
  • prefers-reduced-motion: reduce disables animation, transitions and smooth scrolling; reveal animations never hide content when they are suppressed.
  • Anchor navigation moves keyboard focus to the destination section.

With JavaScript disabled the page renders and navigates completely: content is never hidden by default, and the section strip below the hero remains a working list of anchor links. (The drawer needs JS to open, which is why the strip carries the same 14 destinations.)


Browser support

Modern evergreen browsers — Chrome/Edge 105+, Firefox 110+, Safari 15.4+.

The site relies on CSS custom properties, Grid, Flexbox, clamp(), aspect-ratio and :focus-visible. Two effects degrade gracefully rather than breaking:

  • backdrop-filter on the header — falls back to a solid translucent panel.
  • text-wrap: pretty and svh units — ignored by older engines with no layout impact.

No horizontal scrolling occurs at any width from 360px upward; dense dashboards and the comparison table scroll inside their own containers instead.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages