From 03fd0c0e6e57b1bb7344074a7ed044df360e85e9 Mon Sep 17 00:00:00 2001 From: egdev6 Date: Fri, 5 Jun 2026 19:27:21 +0200 Subject: [PATCH] docs(harness): enforce bilingual docs --- .atl/AGENTS.md | 1 + .atl/skills/pr-reviewer/SKILL.md | 2 + docs/COMPONENTS.md | 491 +++++++++++++++---------------- docs/CONTRIBUTING.en.md | 11 + docs/CONTRIBUTING.md | 11 + 5 files changed, 256 insertions(+), 260 deletions(-) diff --git a/.atl/AGENTS.md b/.atl/AGENTS.md index 071a54aa..add1446f 100644 --- a/.atl/AGENTS.md +++ b/.atl/AGENTS.md @@ -62,6 +62,7 @@ Components live in `src/components/{atoms|molecules|organisms}/{kebab-name}/` wi - For package-facing changes (package output, exports, generated declarations, peer ranges, React major upgrades, or CI/package distribution policy), require `pnpm run build`; require `pnpm run verify:package` when published output or consumer compatibility can change. Tests/Storybook alone are not enough for React major upgrades. - Generated declarations must not leak internal path aliases or CSS side-effect imports into the published `.d.ts` output - English only — code, comments, stories +- Paired repository docs are bilingual: base `*.md` files are Spanish and matching `*.en.md` files are English. When editing docs under `docs/` or root README files, preserve that split, update both language variants when the content changes, and never replace the Spanish base file with English prose. - Commit messages must follow the commitlint-enforced Conventional Commit format: `(): `. PR titles should follow the same format for review consistency. Allowed types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`. Use scopes for domains such as `a11y`, `tokens`, or `infra` instead of inventing custom types. --- diff --git a/.atl/skills/pr-reviewer/SKILL.md b/.atl/skills/pr-reviewer/SKILL.md index f75f12c6..a6b20861 100644 --- a/.atl/skills/pr-reviewer/SKILL.md +++ b/.atl/skills/pr-reviewer/SKILL.md @@ -38,6 +38,7 @@ Run first. If any check fails, return **REJECTED** and do not continue to option | Linked issue assigned to someone else without permission evidence | Fetch linked issue assignees; if any assignee is not the contributor/user, require explicit reassignment/takeover permission before review proceeds. | | Invalid PR title | Conventional Commit format: `(): `. | | PR template incomplete | No required placeholder sections left empty. | +| Paired docs language split broken | For root/docs `*.md` + `*.en.md` pairs, base `*.md` must remain Spanish and matching `*.en.md` must remain English unless maintainers explicitly approve a language migration. | | Branch/diff scope unclear | Diff contains unrelated work without an explicit explanation. | | Component audit missing for component changes | Run or cite `components-auditor`; CRITICAL/MAJOR findings block PR. | | Storybook conventions contradicted | Use `component-contributor/references/stories.md` as source of truth; reject drift such as `parameters.docs.description.component`. | @@ -56,6 +57,7 @@ Run after automatic rejection checks pass. - [ ] Generated/build/runtime artifacts are absent. - [ ] Review workload is reasonable; if over 400 changed lines, use chained PR strategy or record maintainer exception. - [ ] Public API changes are intentional and documented. +- [ ] Paired docs keep the repository language split: Spanish in base `*.md`, English in matching `*.en.md`. ### 2 — Component quality evidence diff --git a/docs/COMPONENTS.md b/docs/COMPONENTS.md index 74c1816b..271ae7f8 100644 --- a/docs/COMPONENTS.md +++ b/docs/COMPONENTS.md @@ -1,18 +1,18 @@ -# Stack-and-Flow — Component Visual Specification +# Stack-and-Flow — Especificación visual de componentes -> Reference for AI agents writing or reviewing component code. Covers every interactive state, glow system, transition rules, gradient border technique, and accessibility requirements. Derived from the Agent Teams reference project and Stack-and-Flow tokens. +> Referencia para agentes de IA que escriben o revisan código de componentes. Cubre todos los estados interactivos, el sistema de glow, las reglas de transición, la técnica de bordes con degradado y los requisitos de accesibilidad. Se basa en los tokens de Stack-and-Flow y en el contrato visual actual del proyecto. --- -## 1. Compositional Principles +## 1. Principios de composición -These rules are system-wide and non-negotiable. Every component must comply with all of them. +Estas reglas se aplican a todo el sistema y no admiten excepciones. Todos los componentes deben cumplirlas. -**Rule 1 — `backdrop-filter: blur` only on floating elements.** -Only elements that literally float above page content (navbar, mobile sidebar, modal backdrops, sticky bars, or an explicitly floating `CardContainer` with `backdropBlur` enabled) use `backdrop-filter`. Content cards are opaque — they use `background: #0B131E`. `blur` signals "I am floating"; opaque signals "I am content". Never apply `backdrop-filter` to feature cards, release cards, pipeline cards, or any card that lives in normal document flow. `CardContainer` defaults to `backdropBlur="none"`; `backdropBlur="sm" | "md" | "lg"` is only for floating/glass treatments above other content. +**Regla 1 — `backdrop-filter: blur` solo en elementos flotantes.** +Solo los elementos que realmente flotan sobre el contenido de la página (navbar, barra lateral móvil, fondos de modal, barras sticky o un `CardContainer` explícitamente flotante con `backdropBlur` activado) usan `backdrop-filter`. Las cards de contenido son opacas: usan `background: #0B131E`. El `blur` comunica "estoy flotando"; una superficie opaca comunica "soy contenido". Nunca apliques `backdrop-filter` a cards de features, release cards, pipeline cards ni a ninguna card que viva en el flujo normal del documento. `CardContainer` usa `backdropBlur="none"` por defecto; `backdropBlur="sm" | "md" | "lg"` queda reservado para tratamientos flotantes o glass por encima de otros contenidos. -**Rule 2 — Never animate gradient background directly. Use `::before` opacity instead.** -A `linear-gradient` cannot be transitioned by the browser. Instead, place the hover gradient on a `::before` pseudo-element with `opacity: 0`, then transition only `opacity` to `1` on hover. This runs on the GPU compositor and produces a smooth fade. The background property on the element itself remains static or uses only simple `background-color` transitions. +**Regla 2 — Nunca animes el fondo con degradado directamente. Usa la opacidad de `::before` en su lugar.** +El navegador no puede interpolar un `linear-gradient`. En su lugar, coloca el degradado de hover en un pseudo-elemento `::before` con `opacity: 0` y anima solo `opacity` hasta `1` al hacer hover. Eso se ejecuta en el compositor de la GPU y produce una transición suave. El `background` del elemento principal permanece estático o usa solo transiciones simples de `background-color`. ```css /* ✅ Correct pattern */ @@ -39,16 +39,16 @@ A `linear-gradient` cannot be transitioned by the browser. Instead, place the ho } ``` -**Rule 3 — Decorative glow is semantic; focus glow is accessibility.** -Treat decorative glow/elevation as part of the component contract, not as a raw visual toggle. A component may ship with decorative glow at rest, on hover, or not at all depending on its variant semantics. Where the component API supports it, expose `emphasis="default" | "flat"` so quiet contexts can suppress decorative glow without changing hierarchy, behavior, or semantics. +**Regla 3 — El glow decorativo es semántico; el glow de focus es accesibilidad.** +Trata el glow o la elevación decorativos como parte del contrato del componente, no como un simple interruptor visual. Un componente puede incluir glow decorativo en reposo, en hover o no incluirlo en absoluto según la semántica de su variante. Cuando la API lo permita, expón `emphasis="default" | "flat"` para que los contextos más sobrios puedan suprimir el glow decorativo sin alterar la jerarquía, el comportamiento ni la semántica. -Focus-visible rings/glows are different: they are accessibility affordances and must never be disabled by `emphasis`, quiet modes, or decorative shadow toggles. Never remove `shadow-glow-focus-*`, focus rings, or selected-state accessibility glow through decorative API controls. +Los anillos o glows de `focus-visible` son otra cosa: son indicadores de accesibilidad y nunca deben desactivarse mediante `emphasis`, modos sobrios ni toggles de sombra decorativa. Nunca elimines `shadow-glow-focus-*`, los anillos de focus ni el glow de accesibilidad del estado seleccionado a través de controles decorativos de la API. -**Rule 4 — `backdrop-filter` and gradient on the same element are forbidden.** -A frosted element (`backdrop-filter: blur`) must not also carry a decorative gradient background layer. They conflict visually (the blur already creates depth) and can cause GPU compositing artifacts. Choose one: frosted surface OR gradient surface. +**Regla 4 — `backdrop-filter` y un degradado en el mismo elemento están prohibidos.** +Un elemento con efecto esmerilado (`backdrop-filter: blur`) no debe llevar además una capa decorativa de fondo con degradado. Ambos recursos compiten visualmente (el blur ya aporta profundidad) y pueden generar artefactos de composición en la GPU. Elige una sola opción: superficie esmerilada O superficie con degradado. -**Rule 5 — Never use `transition: all`.** -Always enumerate exactly the properties being animated. `transition: all` animates every CSS property including layout-forcing ones (`width`, `height`, `top`, `left`, `padding`), which triggers reflow and causes jank. Permitted properties to animate: `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`. +**Regla 5 — No uses nunca `transition: all`.** +Enumera siempre exactamente las propiedades que se animan. `transition: all` anima todas las propiedades CSS, incluidas las que fuerzan layout (`width`, `height`, `top`, `left`, `padding`), lo que dispara reflow y genera tirones visuales. Las propiedades permitidas para animar son: `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`. ```css /* ✅ Correct */ @@ -59,53 +59,53 @@ transition: transition: all 0.25s ease; ``` -**Rule 6 — Hover direction is tonally upward for both primary and secondary.** -On `:hover`, primary button gradient shifts lighter (`#ff1a4b → #ff3366` start, `#cc0030 → #e0003a` end) and glow intensity increases. Secondary button background tint increases from `rgba(255,0,54,0.06)` to `rgba(255,0,54,0.12)` and border opacity increases. Hover always makes elements feel more elevated — never darker or more muted. +**Regla 6 — El hover debe aclarar el tono tanto en primary como en secondary.** +En `:hover`, el degradado del botón primary se aclara (`#ff1a4b → #ff3366` al inicio, `#cc0030 → #e0003a` al final) y la intensidad del glow aumenta. El tinte de fondo del botón secondary sube de `rgba(255,0,54,0.06)` a `rgba(255,0,54,0.12)` y también aumenta la opacidad del borde. El hover siempre debe hacer que los elementos se perciban más elevados, nunca más oscuros ni más apagados. -**Rule 7 — Focus ring uses `box-shadow`, never `outline`.** -`outline` does not respect `border-radius` — it draws a rectangle around a pill button. `box-shadow` follows the shape. Use: +**Regla 7 — El anillo de focus usa `box-shadow`, nunca `outline`.** +`outline` no respeta `border-radius`: dibuja un rectángulo alrededor de un botón tipo píldora. `box-shadow` sí sigue la forma. Usa: -- Dark: `box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.40)` -- Light: `box-shadow: 0 0 0 3px rgba(219, 20, 60, 0.35)` +- Oscuro: `box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.40)` +- Claro: `box-shadow: 0 0 0 3px rgba(219, 20, 60, 0.35)` -Never use `outline: none` without an alternative visible focus indicator. +Nunca uses `outline: none` sin un indicador de focus visible alternativo. -**Rule 8 — Disabled state uses opacity, never color change.** -`opacity: 0.4` on the entire component signals disabled. Never change text color, border color, or background to a "grey" variant — this creates a fake semantic signal and breaks the visual system. Always pair with `cursor: not-allowed` and `pointer-events: none`. +**Regla 8 — El estado disabled usa opacidad; nunca cambio de color.** +Aplicar `opacity: 0.4` a todo el componente comunica el estado disabled. Nunca cambies el color del texto, el color del borde ni el fondo a una variante "gris": eso crea una señal semántica falsa y rompe el sistema visual. Acompáñalo siempre con `cursor: not-allowed` y `pointer-events: none`. -**Rule 9 — Gradient borders use `::before` pseudo-element, never `border-image`.** -`border-image` does not work with `border-radius` — the gradient clips to a rectangle, destroying the pill shape. The correct technique uses `::before` absolutely positioned with `inset: -1.5px` and `z-index: -1`, with the gradient as its `background` and `border-radius: inherit`. +**Regla 9 — Los bordes con degradado usan un pseudo-elemento `::before`, nunca `border-image`.** +`border-image` no funciona con `border-radius`: el degradado se recorta como un rectángulo y rompe la forma de píldora. La técnica correcta usa un `::before` posicionado de forma absoluta con `inset: -1.5px` y `z-index: -1`, usando el degradado como `background` y `border-radius: inherit`. -**Rule 10 — Default touch target is 44×44px for interactive elements.** -Buttons and action-style links use a default minimum `height: 44px` from `sm` upward. Nav links: minimum `44px` high area. Dropdown items: `padding: 7px 12px` minimum with 14px font. Component-specific compact/dense size scales may go below 44px only when explicitly approved, documented on the prop/story, implemented on native controls, and still keyboard/focus accessible; use the default scale when touch-first targets are required. Calendar is an approved dense component scale because date grids need compact scanning density. +**Regla 10 — El objetivo táctil predeterminado para elementos interactivos es de 44×44px.** +Los botones y links de acción usan un mínimo predeterminado de `height: 44px` desde `sm` en adelante. Los nav links deben ofrecer al menos un área de `44px` de alto. Los items de dropdown usan como mínimo `padding: 7px 12px` con tipografía de 14px. Las escalas compactas o densas de componentes concretos pueden bajar de 44px solo cuando estén explícitamente aprobadas, documentadas en la prop o la story, implementadas sobre controles nativos y sigan siendo accesibles por teclado y focus; usa la escala predeterminada cuando el caso requiera objetivos touch-first. Calendar es una excepción densa aprobada porque las cuadrículas de fechas necesitan una densidad de escaneo compacta. -**Action size scale — `xs | sm | md | lg`.** -For `Button`, `IconButton`, and Link variants used as actions (`button` / `outlined`), `xs` is the dense compact size: reduce typography, icon size, gap, horizontal padding, and height so it is visibly smaller than `sm`. `Link` `regular` remains inline typography-only, while CTA-style `sm` and above keep the 44px target. +**Escala de tamaño de acción: `xs | sm | md | lg`.** +En `Button`, `IconButton` y las variantes de Link usadas como acciones (`button` / `outlined`), `xs` es el tamaño compacto y denso: reduce tipografía, tamaño de icono, separación, padding horizontal y altura para que se vea claramente más pequeño que `sm`. `Link` `regular` sigue siendo una variante tipográfica inline, mientras que los CTA `sm` y superiores conservan el objetivo de 44px. -**Rule 11 — Never animate layout-forcing properties.** -Do not animate `width`, `height`, `top`, `left`, `margin`, `padding`. These trigger layout reflow on every frame. For position animations use `transform: translateY/translateX`. For size animations use `transform: scale`. +**Regla 11 — No animes propiedades que fuerzan layout.** +No animes `width`, `height`, `top`, `left`, `margin` ni `padding`. Estas propiedades fuerzan reflow en cada frame. Para animaciones de posición usa `transform: translateY/translateX`. Para animaciones de tamaño usa `transform: scale`. -**Rule 12 — Cards that are interactive links use `position: relative; z-index: 1` on content children.** -When a card has a `::before` hover gradient overlay, all content children need `position: relative; z-index: 1` to appear above the overlay. Forgetting this causes text and icons to be covered by the gradient layer on hover. +**Regla 12 — Las cards que funcionan como enlaces interactivos usan `position: relative; z-index: 1` en sus hijos de contenido.** +Cuando una card tiene un overlay de degradado `::before` en hover, todos sus hijos de contenido necesitan `position: relative; z-index: 1` para quedar por encima del overlay. Si se omite, el texto y los iconos quedan tapados por la capa de degradado durante el hover. --- -## 2. State Behavior Reference +## 2. Referencia de comportamiento por estado -| State | What changes | What never changes | +| Estado | Qué cambia | Qué nunca cambia | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| **hover** | `box-shadow` intensifies; gradient shifts lighter (primary); background tint increases (secondary); `border-color` opacity increases; `transform: translateY(-6px)` on cards | Border radius; font weight; text color (stays `#ffffff` on primary/secondary); component dimensions | -| **focus** | `box-shadow` adds 3px ring: `0 0 0 3px rgba(255,0,54,0.40)` dark / `0 0 0 3px rgba(219,20,60,0.35)` light, merged with existing shadow | Gradient; background tint; `border-color`; dimensions | -| **active** | Gradient shifts darker (`#ff1a4b → #cc002b` primary); scale compresses slightly (`transform: scale(0.98)`); glow contracts | Border radius; text color; font weight | -| **disabled** | `opacity: 0.4`; `cursor: not-allowed`; `pointer-events: none` | All colors stay identical to base state — no grey substitution | +| **hover** | `box-shadow` se intensifica; el degradado se aclara (primary); aumenta el tinte de fondo (secondary); sube la opacidad de `border-color`; `transform: translateY(-6px)` en cards | Radio de borde; peso tipográfico; color del texto (se mantiene en `#ffffff` en primary y secondary); dimensiones del componente | +| **focus** | `box-shadow` añade un anillo de 3px: `0 0 0 3px rgba(255,0,54,0.40)` en oscuro / `0 0 0 3px rgba(219,20,60,0.35)` en claro, combinado con la sombra existente | Degradado; tinte de fondo; `border-color`; dimensiones | +| **active** | El degradado se oscurece (`#ff1a4b → #cc002b` en primary); la escala se comprime ligeramente (`transform: scale(0.98)`); el glow se contrae | Radio de borde; color del texto; peso tipográfico | +| **disabled** | `opacity: 0.4`; `cursor: not-allowed`; `pointer-events: none` | Todos los colores se mantienen idénticos al estado base, sin sustitución por grises | --- -## 3. Components +## 3. Componentes ### 3.1 Button — Primary -**Base (dark):** +**Base (oscuro):** ```css background: linear-gradient(135deg, #ff1a4b 0%, #cc0030 100%); @@ -130,7 +130,7 @@ transition: background 0.25s ease; ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: linear-gradient(135deg, #ff3366 0%, #e0003a 100%); @@ -141,7 +141,7 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); ``` -**Hero variant hover (stronger glow — used in hero / sticky bar):** +**Hover de la variante hero (glow más intenso; se usa en hero / sticky bar):** ```css background: linear-gradient(135deg, #ff3366 0%, #e0003a 100%); @@ -152,7 +152,7 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22); ``` -**Focus (dark):** +**Focus (oscuro):** ```css /* Merged with base box-shadow — add the focus ring as the outermost layer */ @@ -165,7 +165,7 @@ box-shadow: outline: none; ``` -**Active (dark):** +**Active (oscuro):** ```css transform: scale(0.98); @@ -181,14 +181,14 @@ pointer-events: none; /* gradient, glow, and colors remain identical to base — no grey substitution */ ``` -**Light mode:** -No differences for primary button — white text over red gradient passes contrast in both modes. The gradient values and glow remain the same. +**Modo claro:** +No hay diferencias para el botón principal: el texto blanco sobre un degradado rojo pasa el contraste en ambos modos. Los valores de gradiente y el brillo siguen siendo los mismos. --- ### 3.2 Button — Secondary -**Base (dark):** +**Base (oscuro):** ```css background: rgba(255, 0, 54, 0.06); @@ -212,7 +212,7 @@ transition: border-color 0.25s ease; ``` -**Hero / sticky bar base (slightly stronger glow):** +**Base para hero / sticky bar (glow ligeramente más fuerte):** ```css background: rgba(255, 0, 54, 0.06); @@ -223,7 +223,7 @@ box-shadow: inset 0 0 12px rgba(255, 0, 54, 0.05); ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: rgba(255, 0, 54, 0.12); @@ -234,7 +234,7 @@ box-shadow: inset 0 0 16px rgba(255, 0, 54, 0.08); ``` -**Focus (dark):** +**Focus (oscuro):** ```css box-shadow: @@ -245,7 +245,7 @@ box-shadow: outline: none; ``` -**Active (dark):** +**Active (oscuro):** ```css transform: scale(0.98); @@ -260,7 +260,7 @@ cursor: not-allowed; pointer-events: none; ``` -**Light mode:** +**Modo claro:** ```css color: #cc0030; @@ -268,7 +268,7 @@ border-color: rgba(219, 20, 60, 0.5); /* background remains rgba(255,0,54,0.06) */ ``` -**Light mode hover:** +**Hover en modo claro:** ```css color: #8c0b26; @@ -279,7 +279,7 @@ border-color: rgba(219, 20, 60, 0.8); ### 3.3 Button — Ghost / Outlined -Ghost/outlined is implemented as a secondary button without the inset glow. Used in context where the element is inside a card or section with colored background: +La variante ghost/outlined se implementa como un botón secondary sin glow interno. Se usa cuando el elemento vive dentro de una card o una sección con fondo de color: ```css background: transparent; @@ -311,7 +311,7 @@ box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.4); outline: none; ``` -**Note on `releaseLink` inline variant** — same pattern but smaller padding (`0.4rem 1rem`) and used inside cards: +**Nota sobre la variante inline `releaseLink`**: sigue el mismo patrón, pero con un padding más pequeño (`0.4rem 1rem`) y se usa dentro de cards: ```css display: inline-flex; @@ -353,7 +353,7 @@ transition: box-shadow 0.2s ease; ``` -**Placeholder:** +**Marcador de posición:** ```css color: #6a6b6c; @@ -381,7 +381,7 @@ cursor: not-allowed; pointer-events: none; ``` -**Light mode:** +**Modo claro:** ```css background: #ffffff; @@ -389,7 +389,7 @@ border-color: rgba(0, 0, 0, 0.18); color: #0a0a0a; ``` -**Light mode focus:** +**Focus en modo claro:** ```css border-color: rgba(219, 20, 60, 0.5); @@ -400,7 +400,7 @@ box-shadow: 0 0 0 3px rgba(219, 20, 60, 0.15); ### 3.5 Input — Error / Warning / Success States -States change only the `border-color` and `box-shadow`. Background, padding, and font remain identical to default. +Estos estados cambian solo `border-color` y `box-shadow`. El fondo, el padding y la tipografía permanecen idénticos al estado por defecto. **Error:** @@ -423,7 +423,7 @@ border-color: rgba(34, 197, 94, 0.7); /* --color-success: #22c55e */ box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.12); ``` -**Error message text:** +**Texto del mensaje de error:** ```css color: #ff0036; /* dark */ @@ -447,14 +447,14 @@ min-width: 150px; z-index: 100; /* --z-dropdown */ ``` -**Light mode:** +**Modo claro:** ```css background: #ffffff; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); ``` -**Positioning:** the panel appears below the trigger with a small gap. `position: absolute; top: calc(100% + 4px); left: 0`. +**Posicionamiento:** el panel aparece debajo del trigger con un pequeño espacio. `position: absolute; top: calc(100% + 4px); left: 0`. --- @@ -474,28 +474,28 @@ text-decoration: none; display: block; ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: rgba(255, 255, 255, 0.07); color: #ffffff; ``` -**Hover (light):** +**Hover (claro):** ```css background: rgba(0, 0, 0, 0.05); color: #000000; ``` -**Active/selected (dark):** +**Active/seleccionado (oscuro):** ```css color: #ff0036; /* --color-brand-dark */ background: rgba(255, 0, 54, 0.08); ``` -**Active/selected (light):** +**Active/seleccionado (claro):** ```css color: #db143c; /* --color-brand-light */ @@ -506,7 +506,7 @@ background: rgba(219, 20, 60, 0.06); ### 3.8 Badge / Tag -**Brand / "New" — dark:** +**Marca / "Nuevo" — oscuro:** ```css background: #22c55e; /* success */ @@ -521,14 +521,14 @@ display: inline-block; vertical-align: middle; ``` -**"New" — light:** +**"Nuevo" — claro:** ```css background: #16a34a; color: #ffffff; ``` -**Brand pill badge (e.g. version tag, release tag):** +**Badge de marca tipo píldora (por ejemplo, etiqueta de versión o de release):** ```css display: inline-flex; @@ -546,7 +546,7 @@ font-weight: 600; letter-spacing: 0.02em; ``` -**Beta/warning pill badge:** +**Badge tipo píldora beta/de advertencia:** ```css background: color-mix(in srgb, #f59e0b 15%, transparent); @@ -565,7 +565,7 @@ text-transform: uppercase; ### 3.9 Card — Opaque -Used for feature cards, release list items, tech cards, pipeline steps, code blocks, and any structured content. +Se usa para cards de features, elementos de listas de releases, cards tecnológicas, pasos de pipeline, bloques de código y cualquier otro contenido estructurado. ```css background: rgba(255, 255, 255, 0.025); /* visually ~#0B131E in dark context */ @@ -580,7 +580,7 @@ transition: transform 0.3s ease; ``` -**`::before` gradient overlay (always present, triggers on hover):** +**Overlay de degradado en `::before` (siempre presente; se activa en hover):** ```css .card::before { @@ -612,14 +612,14 @@ box-shadow: transform: translateY(-6px); ``` -**Light mode base:** +**Base en modo claro:** ```css background: rgba(0, 0, 0, 0.02); border-color: rgba(0, 0, 0, 0.08); ``` -**Light mode hover:** +**Hover en modo claro:** ```css border-color: #db143c; /* var(--color-brand-light) */ @@ -627,7 +627,7 @@ box-shadow: 0 8px 40px rgba(255, 0, 54, 0.1); /* No transform: translateY in light mode — optional, not consistently applied */ ``` -**Content children inside card must have:** +**Los elementos de contenido dentro de la card deben tener:** ```css position: relative; @@ -638,7 +638,7 @@ z-index: 1; ### 3.10 Card — Frosted -Used only for explicitly floating CardContainer glass surfaces. Normal document-flow cards stay opaque. +Se usa solo para superficies tipo glass de `CardContainer` que flotan explícitamente. Las cards normales en el flujo del documento se mantienen opacas. ```css background: rgba(6, 12, 19, 0.38); /* --color-card-backdrop-dark */ @@ -648,7 +648,7 @@ border: 1px solid rgba(255, 0, 54, 0.5); /* --color-red-tint-border */ border-radius: 8px; /* or 12px for larger panels */ ``` -**Light mode:** +**Modo claro:** ```css background: rgba(255, 255, 255, 0.32); /* --color-card-backdrop-light */ @@ -657,7 +657,7 @@ backdrop-filter: blur(20px); border: 1px solid rgba(255, 0, 54, 0.5); /* --color-red-tint-border */ ``` -**CardContainer backdropBlur levels:** +**Niveles de `backdropBlur` en `CardContainer`:** ```css backdropBlur="sm"; /* --blur-card-sm: blur(10px) */ @@ -665,9 +665,9 @@ backdropBlur="md"; /* --blur-card-md: blur(20px) */ backdropBlur="lg"; /* --blur-card-lg: blur(36px) */ ``` -Use these only when the card is visually floating above other content. Leave `backdropBlur="none"` for normal content cards. +Úsalos solo cuando la card esté flotando visualmente por encima de otro contenido. Deja `backdropBlur="none"` para cards de contenido normal. -**Sticky CTA bar specific (floats below navbar after scroll):** +**Barra CTA fija (flota debajo de la navbar tras hacer scroll):** ```css background: rgba(27, 27, 29, 0.6); @@ -677,13 +677,13 @@ border-bottom: 1px solid rgba(255, 255, 255, 0.06); box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35); ``` -**CRITICAL:** Do NOT combine `backdrop-filter` with a gradient `background`. Choose one. +**CRÍTICO:** NO combines `backdrop-filter` con un `background` con degradado. Elige una sola opción. --- ### 3.11 Card — Tinted (Active) -Used for active sidebar items, active menu items, highlighted feature variants: +Se usa para elementos activos de la barra lateral, elementos activos del menú y variantes de features destacadas: ```css background: rgba(255, 0, 54, 0.08); /* --color-red-tint-low */ @@ -691,7 +691,7 @@ border: 1px solid rgba(255, 0, 54, 0.2); border-radius: 8px; ``` -**Active sidebar link specifically:** +**Enlace activo de la barra lateral:** ```css background: rgba(255, 0, 54, 0.1); /* --color-red-tint-mid */ @@ -701,7 +701,7 @@ border-radius: 8px; /* No additional border on sidebar links */ ``` -**Hover on tinted card:** +**Hover sobre la card tintada:** ```css border-color: rgba(255, 0, 54, 0.38); @@ -729,7 +729,7 @@ top: 0; z-index: 300; /* --z-navbar */ ``` -**Light mode:** +**Modo claro:** ```css background: rgba(255, 255, 255, 0.7); /* --color-navbar-light */ @@ -737,9 +737,9 @@ backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); ``` -**Logo image:** `width: 32px; height: 32px` — explicit size prevents CLS. +**Imagen del logotipo:** `width: 32px; height: 32px`: el tamaño explícito impide CLS. -**Nav links:** +**Enlaces de navegación:** ```css font-size: 0.85rem; @@ -749,11 +749,11 @@ transition: color 0.2s ease; text-decoration: none; ``` -**Nav link hover:** `color: #ffffff;` +**Hover de los enlaces de navegación:** `color: #ffffff;` -**Light mode nav links:** `color: #333333;` → `color: #000000;` hover. +**Enlaces de navegación en modo claro:** `color: #333333;` → `color: #000000;` en hover. -**Mobile sidebar panel:** +**Panel de la barra lateral móvil:** ```css background: rgba(27, 27, 29, 1); @@ -766,7 +766,7 @@ transition: transform 0.25s ease; ``` -**Mobile sidebar — show state:** +**Barra lateral móvil: mostrar estado:** ```css opacity: 1; @@ -775,7 +775,7 @@ z-index: 1000; height: 100dvh; ``` -**Mobile sidebar backdrop:** +**Fondo de la barra lateral móvil:** ```css background: rgba(0, 0, 0, 0.6); @@ -789,7 +789,7 @@ transition: opacity 0.25s ease; ### 3.13 Link — Inline -Links within body text (announcement bar, release notes, inline CTAs): +Enlaces dentro del cuerpo del texto (announcement bar, notas de release, CTA inline): ```css color: #ff4d6d; /* slightly lighter than brand for inline legibility */ @@ -808,9 +808,9 @@ color: #ff8099; border-bottom-color: rgba(255, 128, 153, 0.7); ``` -**Light mode inline link:** same pattern but use `#db143c` → `#c41136` hover. +**Link inline en modo claro:** sigue el mismo patrón, pero usa `#db143c` → `#c41136` en hover. -**Inline CTA link (featureCta — "Learn more →"):** +**Link inline CTA (`featureCta` — "Más información →"):** ```css color: var(--color-primary); /* #ff0036 dark / #db143c light */ @@ -823,7 +823,7 @@ transition: gap 0.2s ease; text-decoration: none; ``` -**Inline CTA hover:** `gap: 0.55rem;` — the arrow slides right. +**Hover del inline CTA:** `gap: 0.55rem;` — la flecha se desplaza hacia la derecha. --- @@ -842,14 +842,14 @@ text-decoration: none; display: block; ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: rgba(255, 255, 255, 0.05); /* --color-white-tint-faint */ color: #ffffff; ``` -**Active (dark):** +**Active (oscuro):** ```css background: rgba(255, 0, 54, 0.1); /* --color-red-tint-mid */ @@ -857,7 +857,7 @@ color: #ff0036; font-weight: 600; ``` -**Mobile sidebar nav link:** +**Enlace de navegación de la barra lateral móvil:** ```css padding: 0.6rem 1rem; @@ -873,9 +873,9 @@ transition: ### 3.15 Modal / Dialog -No existing Modal component in reference codebase. Use the established surface and overlay tokens: +No existe un componente Modal en el código de referencia. Usa los tokens ya definidos para superficie y overlay: -**Backdrop:** +**Fondo:** ```css position: fixed; @@ -908,14 +908,14 @@ transition: transform 0.25s ease; ``` -**Open state:** +**Estado abierto:** ```css opacity: 1; transform: translate(-50%, -50%) scale(1); ``` -**Light mode panel:** +**Panel en modo claro:** ```css background: #ffffff; @@ -925,38 +925,9 @@ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); --- -### 3.16 Drawer +### 3.16 Announcement Bar / Version Banner -Drawer is a Radix Dialog-backed off-canvas dialog. It uses the approved compound anatomy: `Drawer.Trigger`, `Drawer.Content`, `Drawer.Header`, `Drawer.Title`, `Drawer.Description`, `Drawer.Body`, `Drawer.Footer`, and `Drawer.Close`. `Portal`, `Overlay`, and `Backdrop` remain internal to `Drawer.Content`. - -**Accessibility and anatomy:** - -- `Drawer.Title` is required so the dialog has an accessible name. -- `Drawer.Description` is optional and should explain context when the title alone is not enough. -- Built-in icon-only `Drawer.Close` is named `Close drawer`; custom close controls must provide visible text or their own accessible label. -- Header and footer are non-scrolling; `Drawer.Body` is the internal scroll region for long content. - -**Placement and responsive behavior:** - -- `placement="start" | "end" | "top" | "bottom"`; default is `end`. -- `start` and `end` are logical placements. On `md+`, LTR maps start/end to left/right and RTL maps start/end to right/left. -- Below `md`, side placements adapt to effective bottom sheet layout. -- Side sizes reuse `max-w-modal-*`; top, bottom, and mobile bottom layouts use `max-h-drawer-*` utilities based on `--size-drawer-block-viewport`. -- Bottom and mobile-adapted drawers use safe-area padding for footer actions. - -**Dismissal and motion:** - -- `dismissible` controls outside/backdrop dismissal only. -- `closeOnEscape` controls Escape-key dismissal only. -- Explicit close controls remain available for non-dismissible drawers. -- Overlay fades and panel slides by effective placement using `opacity` and `transform`; never use `transition: all`. -- `motion-reduce` removes drawer entrance/exit motion while preserving focus management. - ---- - -### 3.17 Announcement Bar / Version Banner - -**Announcement bar (Docusaurus global bar — full width above navbar):** +**Announcement Bar** (barra global de Docusaurus, a ancho completo sobre la navbar): ```css border-bottom: 1px solid rgba(255, 0, 54, 0.35); @@ -966,7 +937,7 @@ letter-spacing: 0.01em; /* Hidden on mobile: display: none at max-width: 768px */ ``` -**Link inside bar:** +**Link dentro de la barra:** ```css color: #ff4d6d; @@ -978,14 +949,14 @@ transition: border-color 0.2s ease; ``` -**Link hover:** +**Hover del link:** ```css color: #ff8099; border-bottom-color: rgba(255, 128, 153, 0.7); ``` -**Version Banner (custom component — dark strip between bar and page):** +**Version Banner** (componente personalizado: franja oscura entre la barra y la página): ```css background-color: #0d0d0d; @@ -997,15 +968,15 @@ line-height: 1.5; /* Hidden on mobile: display: none at max-width: 768px */ ``` -**Links in version banner:** Same `#ff4d6d` / `#db143c` light mode pattern as inline links. +**Enlaces del version banner:** siguen el mismo patrón `#ff4d6d` / `#db143c` en modo claro que los links inline. --- -## 4. Glow System +## 4. Sistema de resplandor -### 4-Layer Pattern (Button Primary — canonical example) +### Patrón de 4 capas (Button Primary — ejemplo canónico) -The primary button glow has four layers with distinct purposes: +El glow del botón primary tiene cuatro capas, cada una con un propósito distinto: ```css box-shadow: @@ -1027,7 +998,7 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15); ``` -### Hover amplification: +### Amplificación en hover: ```css box-shadow: @@ -1040,22 +1011,22 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); /* inset: 0.20 vs 0.15 */ ``` -### Decorative glow timing and emphasis +### Temporización y énfasis del glow decorativo -| Element | Default decorative glow behavior | `emphasis="flat"` | +| Elemento | Comportamiento decorativo predeterminado del glow | `emphasis="flat"` | | ----------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | -| Button Primary | **Always-on** — 4-layer glow at rest, amplified on hover | Removes decorative glow, keeps focus ring | -| Button Secondary / Outlined | **Always-on** — soft contained glow at rest, amplified on hover | Removes decorative glow, keeps focus ring | -| IconButton Primary / Secondary / Outlined | Matches button semantics for the same variant family | Removes decorative glow, keeps focus ring | -| CTA Link `button` / `outlined` | Decorative glow by variant contract | Removes decorative glow, keeps focus ring | -| Chip | No decorative glow API; color/variant carries status semantics | N/A — focus/selected accessibility glow remains independent | -| Switch `emphasis="default"` | Decorative glow by emphasis contract | `emphasis="flat"` removes decorative glow, keeps focus ring | -| Feature Card | **Hover-only** — no glow at rest, box-shadow appears on hover | N/A unless a component-specific API is added | -| Nav Badge (GitHub stars) | **Hover-only** — amber ring appears only on hover | N/A unless a component-specific API is added | -| Logo icon (glowing) | **Always-on** — `filter: drop-shadow(0 0 20px rgba(255,0,54,0.4))` | Component-specific decision | -| Inline CTA links | **No glow** — color transition only | No effect | +| Button Primary | **Siempre activo**: glow de 4 capas en reposo, amplificado en hover | Elimina el glow decorativo y mantiene el anillo de focus | +| Button Secondary / Outlined | **Siempre activo**: glow suave y contenido en reposo, amplificado en hover | Elimina el glow decorativo y mantiene el anillo de focus | +| IconButton Primary / Secondary / Outlined | Sigue la misma semántica visual que los botones de la misma familia de variantes | Elimina el glow decorativo y mantiene el anillo de focus | +| CTA Link `button` / `outlined` | Glow decorativo según el contrato de su variante | Elimina el glow decorativo y mantiene el anillo de focus | +| Chip | No tiene API de glow decorativo; el color o la variante cargan la semántica de estado | N/A — el glow de focus/selección de accesibilidad sigue siendo independiente | +| Switch `emphasis="default"` | Glow decorativo según el contrato de énfasis | `emphasis="flat"` elimina el glow decorativo y mantiene el anillo de focus | +| Feature Card | **Solo en hover**: sin glow en reposo; `box-shadow` aparece en hover | N/A salvo que se añada una API específica del componente | +| Nav Badge (estrellas de GitHub) | **Solo en hover**: el anillo ámbar aparece únicamente al pasar el cursor | N/A salvo que se añada una API específica del componente | +| Icono del logo (con glow) | **Siempre activo** — `filter: drop-shadow(0 0 20px rgba(255,0,54,0.4))` | Decisión específica del componente | +| Links inline CTA | **Sin glow**: solo transición de color | Sin efecto | -### Secondary button glow (3-layer, contained): +### Glow del botón Secondary (3 capas, contenido): ```css box-shadow: @@ -1067,19 +1038,19 @@ box-shadow: inset 0 0 10px rgba(255, 0, 54, 0.04); ``` -No tight ring layer — secondary doesn't need a border simulation because it already has a real `border: 1.5px solid`. +No hay una capa de anillo ceñido: secondary no necesita simular un borde porque ya tiene un `border: 1.5px solid` real. --- -## 5. Gradient Border Technique +## 5. Técnica del borde degradado -### Why `border-image` fails with `border-radius` +### Por qué `border-image` falla con `border-radius` -`border-image` replaces the `border` rendering and ignores `border-radius`. A pill button (`border-radius: 9999px`) with `border-image` renders as a rectangle with gradient edge clips at the corners. There is no workaround for this in CSS — `border-image` is fundamentally incompatible with `border-radius`. +`border-image` reemplaza la representación `border` e ignora `border-radius`. Un botón tipo pastilla (`border-radius: 9999px`) con `border-image` se representa como un rectángulo con clips de borde degradados en las esquinas. No existe una solución alternativa para esto en CSS: `border-image` es fundamentalmente incompatible con `border-radius`. -### The `::before` pseudo-element technique +### Técnica con pseudo-elemento `::before` -The gradient border is created by positioning a pseudo-element behind the component that extends 1.5px in every direction using `inset: -1.5px`. The parent has `border: 1.5px solid transparent` and `background-clip: padding-box` to prevent the parent's background from showing through the border area. +El borde con degradado se crea colocando un pseudo-elemento detrás del componente y haciéndolo crecer 1.5px en cada dirección mediante `inset: -1.5px`. El elemento padre usa `border: 1.5px solid transparent` y `background-clip: padding-box` para evitar que el fondo del propio padre se vea a través del área del borde. ```css .gradient-border-component { @@ -1105,11 +1076,11 @@ The gradient border is created by positioning a pseudo-element behind the compon } ``` -### GPU compositing benefit +### Ventaja de composición en GPU -The `::before` gradient is a static painted layer. On hover, we transition only `opacity` on the `::before` (or swap the background with a higher-opacity version). Since `opacity` changes are handled by the GPU compositor — not the main thread — this avoids layout and paint work. Animating `background` directly on a gradient would repaint every frame. +El degradado de `::before` es una capa estática ya pintada. En hover solo se anima `opacity` sobre `::before` (o se sustituye el fondo por una versión con mayor opacidad). Como los cambios de `opacity` los resuelve el compositor de la GPU y no el hilo principal, se evita trabajo de layout y repintado. Animar `background` directamente sobre un degradado obligaría a repintar cada frame. -### Exact gradient values — Secondary button (ghost destello): +### Valores exactos del degradado: botón Secondary (resaltado ghost): ```css /* Tight directional gradient — white flash from top-left, red dominance mid, fades to transparent */ @@ -1121,99 +1092,99 @@ background: linear-gradient( ); ``` -### When to use gradient border +### Cuándo usar un borde con degradado -- Secondary / ghost buttons that need visual weight without solid fill -- Input fields in focus state (transition `::before` opacity from 0 to 1) -- Active cards with accent border -- Never on structural separators, table borders, or layout containers +- Botones secondary o ghost que necesitan peso visual sin relleno sólido +- Campos de input en estado de focus (transición de la opacidad de `::before` de 0 a 1) +- Cards activas con borde acentuado +- Nunca en separadores estructurales, bordes de tablas ni contenedores de layout. --- -## 6. Transition Rules +## 6. Reglas de transición -| Interaction type | Duration | Easing | Properties | +| Tipo de interacción | Duración | Easing | Propiedades | | ------------------------------------------ | --------------------- | -------------------------------- | ------------------------------------------ | -| Button hover (primary/secondary) | 250ms | `ease` | `box-shadow`, `background` | -| Button hover (secondary — includes border) | 250ms | `ease` | `box-shadow`, `background`, `border-color` | -| Card hover | 300ms | `ease` | `border-color`, `box-shadow`, `transform` | -| Card `::before` gradient reveal | 300ms | implicit `ease` | `opacity` | -| Dropdown / menu item hover | 150ms | `ease` | `background`, `color` | -| Inline link hover | 200ms | `ease` | `color`, `border-color` | -| Locale switcher / nav badge hover | 200ms | `ease` | `border-color`, `box-shadow` | -| GitHub stars badge parts | 200ms | `ease` | `background`, `color` | -| Modal / sidebar entrance | 250ms | `ease` | `opacity`, `transform` | -| Sticky bar entrance | 350ms | `ease` | `opacity`, `transform` | -| Scroll fade-in (IntersectionObserver) | 560ms | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `opacity`, `transform` | -| Pipeline hover expand | 400–450ms | `cubic-bezier(0.4, 0, 0.2, 1)` | `flex`, `max-width` | -| Pipeline right panel fade-in | 200ms (delayed 450ms) | `ease` | `opacity` | -| Nav link color | 200ms | `ease` | `color` | - -**Rule:** NEVER use `transition: all`. Always enumerate exact properties. - -**Permitted animatable properties:** `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`, `flex`, `max-width` (for expand patterns), `filter` (for icon glows). - -**NEVER animate:** `width`, `height`, `top`, `right`, `bottom`, `left`, `margin`, `padding` — these trigger layout reflow. +| Hover de Button (primary/secondary) | 250ms | `ease` | `box-shadow`, `background` | +| Hover de Button (secondary — incluye borde) | 250ms | `ease` | `box-shadow`, `background`, `border-color` | +| Hover de Card | 300ms | `ease` | `border-color`, `box-shadow`, `transform` | +| Revelado del degradado `::before` en Card | 300ms | `ease` implícito | `opacity` | +| Hover de Dropdown / item de menú | 150ms | `ease` | `background`, `color` | +| Hover de link inline | 200ms | `ease` | `color`, `border-color` | +| Hover de locale switcher / nav badge | 200ms | `ease` | `border-color`, `box-shadow` | +| Partes del badge de estrellas de GitHub | 200ms | `ease` | `background`, `color` | +| Entrada de modal / barra lateral | 250ms | `ease` | `opacity`, `transform` | +| Entrada de barra sticky | 350ms | `ease` | `opacity`, `transform` | +| Scroll fade-in (`IntersectionObserver`) | 560ms | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `opacity`, `transform` | +| Expansión hover de pipeline | 400–450ms | `cubic-bezier(0.4, 0, 0.2, 1)` | `flex`, `max-width` | +| Fade-in del panel derecho de pipeline | 200ms (retraso de 450ms) | `ease` | `opacity` | +| Color de enlaces de navegación | 200ms | `ease` | `color` | + +**Regla:** NO uses nunca `transition: all`. Enumera siempre las propiedades exactas. + +**Propiedades animables permitidas:** `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`, `flex`, `max-width` (para patrones de expansión), `filter` (para brillos de iconos). + +**No animes nunca:** `width`, `height`, `top`, `right`, `bottom`, `left`, `margin`, `padding`; todas ellas fuerzan reflow. --- -## 7. Accessibility Checklist +## 7. Lista de verificación de accesibilidad -### Buttons +### Botones -- [ ] Minimum height `44px` -- [ ] Focus ring: `box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.40)` dark / `0 0 0 3px rgba(219, 20, 60, 0.35)` light -- [ ] Focus ring merged with existing `box-shadow` — never replaces it -- [ ] Focus ring never hidden: no `outline: none` without alternative -- [ ] Disabled: `opacity: 0.4`, `cursor: not-allowed`, `pointer-events: none` — no color change -- [ ] Primary: white `#ffffff` text over red gradient — contrast passes in both modes -- [ ] Secondary dark: `color: #ffffff` over `rgba(255,0,54,0.06)` — visually dark background context; border defines the affordance -- [ ] Secondary light: `color: #cc0030` — NEVER `#ff0036` in light mode (insufficient contrast over white) -- [ ] Touch target remains at least `44px` for default action sizes; explicitly approved compact/dense variants may use reduced visual targets when documented and keyboard/focus accessible -- [ ] `role="button"` if implemented as non-`