Bloque 2 · Componentes 1–7

Tokens, botones, tarjetas, formularios, header, footer, hero.

Cada componente entrega: anatomía, variantes, estados, snippet HTML, snippet .astro listo para pegar, reglas de uso y cómo NO usarlo.

01 / 14 · Foundation

Tokens

Foundation

Bloque :root con todas las variables CSS canónicas. Punto único de cambio para el sistema. Documentado en Bloque 1 con la escala visualizada.

Resumen
  • Color — navy, cream, paper, graphite, steel, ball
  • Tipografía — display Archivo Black 900 · body Inter 400/500/600/700
  • Escala — hero/h1/h2/h3/body-l/body/small/mono-tag
  • Espacio — escala 4 px (--space-1..10)
  • Radius — sm 2 / md 4 / lg 8 / pill 999
  • Container — max 1240 px · pad clamp(20, 4 vw, 32)
Ver bloque completo en Bloque 1 →

Cómo NO usar: hard-code de hex en componentes · inventar valores intermedios · mezclar unidades fuera de la escala (15 px, 30 px no existen) · introducir tokens secundarios sin actualizar el manual.

02 / 14 · Action

Button

Acción

Cuatro variantes — primary, secondary, accent (solo sobre navy), ghost. Tres tamaños — sm, md, lg. Radius md 4 px. Foco con outline amarillo.

Variantes · tamaño md sobre cream
Variantes sobre navy · incluye accent
Tamaños · sm / md / lg
Estados · default · hover · focus · disabled
HTML
<button class="btn btn--primary btn--md">
  Inscríbete
</button>
.astro
---
// src/components/Button.astro
interface Props {
  variant?: 'primary' | 'secondary'
         | 'accent' | 'ghost';
  size?:    'sm' | 'md' | 'lg';
  href?:    string;
  type?:    'button' | 'submit';
}
const { variant='primary', size='md', href, type='button' } = Astro.props;
const Tag = href ? 'a' : 'button';
---
<Tag
  class={`btn btn--${variant} btn--${size}`}
  href={href}
  type={!href ? type : undefined}>
  <slot />
</Tag>
Cómo usar
  • Un primary por sección. El resto son secundarios o ghost.
  • Texto en imperativo y corto: "Inscríbete", "Ver bases".
  • accent SOLO sobre navy. Sobre cream/paper queda prohibido.
  • Tamaño lg reservado a CTAs de hero.
Cómo NO
  • Botón amarillo sobre cream — contraste 1.2:1, ilegible.
  • Border-radius pill en botones generales — solo en chips muy puntuales.
  • Gradientes, sombras decorativas, glow.
  • Texto en MAYÚSCULA gritona dentro del botón.
  • Iconos sin label salvo botón cuadrado de utilidad.
03 / 14 · Container

Card

Contenedor

Tres variantes — default cream con borde, elevated paper, navy inversa. Radius lg 8 px. Cero sombra decorativa.

Categoría

Masculina A

32 jugadores · 16 parejas. Cuadro de eliminación directa con previa de grupos.

Inscríbete →
Categoría

Mixta B

24 parejas · jornadas sábado y domingo. Ideal para padre-hija o madre-hijo.

Inscríbete →
BeachTennis

Femenina · arena

95 jugadoras · pista de playa del Balís. Categoría con su propio sorteo.

Inscríbete →
HTML
<article class="card card--elevated">
  <span class="card__eyebrow">Categoría</span>
  <h3  class="card__title">Mixta B</h3>
  <p   class="card__body">24 parejas…</p>
  <a   class="card__cta" href="#">Inscríbete →</a>
</article>
.astro
---
// src/components/Card.astro
interface Props {
  variant?: 'default' | 'elevated' | 'navy';
  eyebrow?: string;
  title:    string;
  href?:    string;
}
const { variant='default', eyebrow, title, href } = Astro.props;
const klass = variant === 'default'
  ? 'card'
  : `card card--${variant}`;
---
<article class={klass}>
  {eyebrow && <span class="card__eyebrow">{eyebrow}</span>}
  <h3 class="card__title">{title}</h3>
  <p  class="card__body"><slot /></p>
  {href && <a class="card__cta" href={href}>Ver →</a>}
</article>
Cómo usar
  • default en cream — uso general en cuadrículas.
  • elevated en cream — destacar 1 de N (categoría protagonista).
  • navy en zonas claras — invertir un módulo para crear pausa.
  • Eyebrow opcional como mono-tag; máximo 1 CTA por tarjeta.
Cómo NO
  • Box-shadow blur decorativa, halos, glow.
  • Border-left color como acento (mismo defecto que muchos DS).
  • Tarjeta amarilla. Jamás.
  • Más de 2 niveles de jerarquía dentro de la tarjeta.
04 / 14 · Action

Form

Input · Textarea · Select · Checkbox · Radio

Foco con outline 2 px amarillo (ball) sobre el borde navy. Error en borde graphite y mensaje pequeño. Inputs radius-md 4 px. Cero estilo iOS por defecto en selects.

HTML
<label class="field">
  <span class="field__label">Email</span>
  <input class="field__input"
         type="email" required>
</label>

<label class="check">
  <input type="checkbox">
  <span class="check__box"></span>
  <span class="check__label">Acepto bases</span>
</label>
.astro · Field.astro
---
interface Props {
  label:  string;
  name:   string;
  type?:  'text'|'email'|'tel'|'textarea'|'select';
  error?: string;
  required?: boolean;
}
const { label, name, type='text', error, required } = Astro.props;
---
<label class={`field ${error ? 'field--error' : ''}`}>
  <span class="field__label">{label}</span>
  {type === 'textarea'
    ? <textarea class="field__input" name={name} required={required} />
    : <input class="field__input" type={type} name={name} required={required} />}
  {error && <span class="field__msg">{error}</span>}
</label>
Cómo usar
  • Labels SIEMPRE visibles (no solo placeholder).
  • Validación nativa HTML5 (required, type).
  • Error en borde + mensaje breve y específico.
  • Touch target mínimo 44 px alto.
Cómo NO
  • Placeholder como única label.
  • Error en rojo saturado fuera de paleta.
  • Iconos en el input que reducen el touch target.
  • Checkbox/radio nativos del sistema — siempre con custom box.
05 / 14 · Navigation

Header / Nav

Sticky · shrink · panel móvil

Desktop sticky 80 px, encoge a 64 px tras scroll. Mobile: slide desde la derecha sobre navy, full-height. CTA primary visible en ambos.

Desktop · 80 px Desktop · shrunk 64 px tras scroll Mobile · panel desde la derecha (navy)
.astro · Header.astro
---
import Button from './Button.astro';
const path = Astro.url.pathname;
const nav = [
  { href: '/',                label: 'El torneo' },
  { href: '/inscripciones',   label: 'Inscripciones' },
  { href: '/resultados',     label: 'Resultados' },
  { href: '/cena-clausura',  label: 'Cena' },
  { href: '/patrocinadores', label: 'Patrocinadores' },
  { href: '/ediciones',      label: 'Ediciones' },
];
---
<header class="header" id="site-header">
  <a class="header__brand" href="/">
    <img src="/logos/padelgazar-positivo.svg" alt="Padelgazar" />
    <span class="header__brand-text">PADEL<br/>GAZAR</span>
  </a>
  <nav class="header__nav">
    {nav.map(i => (
      <a href={i.href} class="header__link"
         aria-current={path === i.href ? 'page' : undefined}>{i.label}</a>
    ))}
  </nav>
  <Button href="/inscripciones" size="sm">Inscríbete</Button>
</header>
<script>
  const h = document.getElementById('site-header');
  addEventListener('scroll', () => h.classList.toggle('header--shrunk', scrollY > 32));
</script>
Cómo usar
  • Una sola CTA primary; el resto es nav.
  • aria-current="page" marca el activo. Sin colorear el texto — borde inferior.
  • Mobile: drawer ocupa <90 % de ancho, fondo navy, foco trapped.
Cómo NO
  • Mega-menú multi-columna — no encaja con el tono.
  • Subrayar todos los links permanentemente.
  • CTA accent (amarillo) en versión desktop sobre cream — solo aparece en drawer navy.
06 / 14 · Navigation

Footer

4 cols · co-branding obligatorio

Fondo navy. Cuatro columnas en desktop, una en mobile. Co-branding Websalia obligatorio en TODAS las páginas. Logo de Websalia 32 px de alto.

.astro · Footer.astro
---
// src/components/Footer.astro · co-branding Websalia obligatorio
---
<footer class="footer">
  <div class="footer__inner">
    <div class="footer__col footer__col--brand">
      <img class="footer__logo"
           src="/logos/padelgazar-mono-blanco.svg" alt="Padelgazar" />
      <p class="footer__tag">El verano del Maresme.</p>
    </div>
    </* 3 columnas más */>
  </div>
  <div class="footer__bar">
    <span>© 2026 Padelgazar · C.N. El Balís</span>
    <div class="footer__co">
      <span class="t-mono-tag">Diseñado por</span>
      <img src="/logos/websalia.svg" alt="Websalia" />
    </div>
  </div>
</footer>
Cómo usar
  • Logo Padelgazar mono-blanco arriba a la izquierda.
  • Co-branding "Diseñado por Websalia" siempre presente.
  • Links subrayados al hover, no permanente.
Cómo NO
  • Footer cream — siempre navy para cerrar la página.
  • Iconos sociales decorativos sin función real.
  • Omitir Websalia.
07 / 14 · Layout

Hero

Variante navy · variante cream

Dos variantes — navy para la home, cream para subpáginas. Cifras siempre en chip navy + amarillo cuando viven sobre cream. Una sola idea por hero.

Hero navy · home
Julio – Septiembre 2026 · C.N. El Balís

PADEL
GAZAR
2026

160 jugadores · 8 categorías · cena de clausura · White Party.
Tres meses con la pandilla, en casa.

Hero cream · subpáginas
Edición 2026 · 8 categorías

Inscripciones abiertas hasta el 30 jun

Elige tu categoría, paga la cuota y reserva la cena. El sorteo se publica el primer sábado de julio.

.astro · Hero.astro
---
interface Props {
  variant?: 'navy' | 'cream';
  eyebrow?: string;
  title:    string;
}
const { variant='navy', eyebrow, title } = Astro.props;
---
<section class={`hero hero--${variant}`}>
  <div class="hero__inner">
    {eyebrow && <span class="hero__eyebrow">{eyebrow}</span>}
    <h1 class="hero__title" set:html={title}></h1>
    <slot />
  </div>
</section>
Cómo usar
  • Una sola idea. Una sola CTA primary (la accent en hero navy es legal).
  • Año del torneo como highlight amarillo solo en hero navy.
  • Subtítulo <14 palabras.
Cómo NO
  • Foto de stock genérico de pádel como background.
  • Cinco CTAs en línea.
  • Amarillo directo sobre cream — siempre dentro de chip.