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/component-contributor/SKILL.md b/.atl/skills/component-contributor/SKILL.md index c2681516..92f663c5 100644 --- a/.atl/skills/component-contributor/SKILL.md +++ b/.atl/skills/component-contributor/SKILL.md @@ -34,7 +34,7 @@ Load by intent: | Radix primitive | `.atl/skills/component-contributor/references/radix-patterns.md` | | `className` merging | `.atl/skills/component-contributor/references/tailwind-merge.md` | | Contributor PR workflow | `.atl/skills/component-contributor/references/git-workflow.md` | -| Starting from a GitHub issue or board task | `.atl/skills/github-project-tasks/SKILL.md` — verify issue label `status:approved`, then run START WORK before implementation | +| Starting from a GitHub issue or board task | `.atl/skills/github-project-tasks/SKILL.md` — verify issue label `status:approved` and assignee ownership, then run START WORK before implementation | ## Workflow @@ -42,19 +42,21 @@ Follow these phases in order. Do not skip gates because a component looks simple **Non-negotiable approval gate:** implementation must not start under any circumstance unless the linked GitHub issue has the exact label `status:approved`. Chat approval, assumptions, offline mode, or a local copy of the spec do not satisfy this gate. +**Non-negotiable assignee gate:** before reading the implementation spec in detail, planning, creating a branch/worktree, mutating GitHub, or writing code from a linked issue, verify current assignees. If the issue is assigned to someone other than the contributor/user, stop and tell the user they must get explicit permission before reassigning it. + ### 0 — Contributor onboarding Only when working directly with a contributor: confirm they understand React + strict TypeScript, Tailwind v4 tokens, CVA, the 6-file pattern, Storybook as docs, and tests in `.test.tsx`. If not, teach briefly before proceeding. ### 1 — Approval gate, START WORK, then spec intake -If implementation will proceed from a GitHub issue or Project board card, first verify that the linked issue has the exact label `status:approved`. If it is missing, stop and ask for maintainer/project lead approval; do not read the implementation spec in detail, plan, or code. +If implementation will proceed from a GitHub issue or Project board card, first verify that the linked issue has the exact label `status:approved` and is not assigned to someone else. If the label is missing, stop and ask for maintainer/project lead approval; do not read the implementation spec in detail, plan, or code. If another assignee is present, stop before any action and tell the user they need explicit permission before reassigning the issue. -After the label is present, load `.atl/skills/github-project-tasks/SKILL.md` and run **START WORK** before spec intake, planning, or coding: assign the issue to the contributor/user, move Project status to `In progress`, and record the planned branch/worktree. Offline/no-network mode may only skip GitHub mutations after evidence confirms the issue already has `status:approved`; it never bypasses the approval gate. +After the label and assignee gates pass, load `.atl/skills/github-project-tasks/SKILL.md` and run **START WORK** before spec intake, planning, or coding: verify assignees, assign the issue to the contributor/user, move Project status to `In progress`, and record the planned branch/worktree. Offline/no-network mode may only skip GitHub mutations after evidence confirms the issue already has `status:approved` and is unassigned or assigned to the contributor/user; it never bypasses the approval or assignee gates. Then extract component name, tier, props, variants, states, accessibility behavior, reference URL, and design notes. If the spec lives in a GitHub issue, read issue comments too; validated specs may live there. -Stop and ask when the issue label `status:approved` is missing or cannot be verified, START WORK cannot be completed, or required behavior, accessibility, states, or variants are missing. Do not invent public API and do not begin implementation. +Stop and ask when the issue label `status:approved` is missing or cannot be verified, the issue is assigned to someone else without explicit reassignment permission, START WORK cannot be completed, or required behavior, accessibility, states, or variants are missing. Do not invent public API and do not begin implementation. ### 1.5 — Spec critique diff --git a/.atl/skills/component-contributor/references/stories.md b/.atl/skills/component-contributor/references/stories.md index 887978a6..0522abc8 100644 --- a/.atl/skills/component-contributor/references/stories.md +++ b/.atl/skills/component-contributor/references/stories.md @@ -20,7 +20,10 @@ Use this reference BEFORE writing or reviewing stories. Do not improvise Storybo - `## Description` — required for every component; describe what it does and when to use it. - `## Dependencies` — include only when the story/component uses other design-system components or external primitives; list each dependency and why it is used. - `## Usage Guide` — include only when usage is complex; explain composition, constraints, or non-obvious behavior. -- Story-level docs must be written as a JSDoc block immediately above each `export const StoryName`; do **not** render documentation cards, panels, helper text blocks, or usage notes inside the story canvas. +- Story-level docs must be written as a useful JSDoc block immediately above each `export const StoryName`; do **not** render documentation cards, panels, helper text blocks, or usage notes inside the story canvas. +- Each story must earn its place: demonstrate a distinct state, variant axis, composition constraint, accessibility behavior, or integration context. Do not add stories that duplicate coverage already provided by controls, args, or another story. +- Do **not** add a generic `DarkMode` story just to show the component in dark theme. Storybook already provides global dark/light switching via the toolbar. +- A dedicated dark-mode story is allowed only when it demonstrates behavior the global theme toggle cannot express, such as local dark-scope rendering, portal theme inheritance, or a theme-specific bug/regression case. State that reason in the story JSDoc. - Story render functions and decorators are examples only: they may provide layout needed to demonstrate the component, but not narrative documentation UI. - `Default` story args must not override the component `defaultVariants`. - Interactive components must include `Disabled` and interaction-focused stories as appropriate. @@ -59,7 +62,7 @@ export default meta; type Story = StoryObj; /** - * Shows the default component configuration using its default variants. + * Demonstrates the component with its built-in default variants so consumers can compare other stories against the baseline API. */ export const Default: Story = { args: { @@ -78,7 +81,9 @@ export const Default: Story = { - Is the component-level docs JSDoc block immediately above `const meta`? - Does the component-level JSDoc block include required `## Description`? - Are `## Dependencies` and `## Usage Guide` included only when applicable? -- Does each story have a concise JSDoc block immediately above its `export const StoryName`? +- Does each story JSDoc explain the scenario and why it matters instead of restating the story name or saying only "Shows the component"? +- Is every story necessary, with no duplicate coverage that controls, args, the global dark-mode toolbar, or another story already provide? +- Are generic theme-only `DarkMode` stories absent unless they document a local scope, portal inheritance, or regression case that the toolbar cannot express? - Are documentation cards, panels, helper text blocks, and usage notes absent from the story canvas? - Does `meta.parameters.docs` avoid `description.component`? - Are examples aligned with the canonical component API and public docs style? diff --git a/.atl/skills/component-spec-proposer/SKILL.md b/.atl/skills/component-spec-proposer/SKILL.md index 13692ca1..ad7e671b 100644 --- a/.atl/skills/component-spec-proposer/SKILL.md +++ b/.atl/skills/component-spec-proposer/SKILL.md @@ -36,21 +36,23 @@ Do not implement the component. Your job is to turn a vague task into a validate | Accessibility contract is vague or missing | Stop and ask; do not produce a ready-to-approve spec. | | Composite keyboard/focus behavior unclear | Ask for the intended pattern before validation. | | Expected a11y tests are missing | Add them before asking for approval. | +| Linked issue assigned to someone else | Stop before GitHub writes or implementation handoff; tell the user they need explicit permission before reassigning or taking over the issue. | | User approves proposal | Add the validated spec to the issue, then leave implementation blocked until a maintainer/project lead adds the issue label `status:approved`. | | User requests changes | Revise the proposal and ask for validation again. | ## Execution Steps -1. Read the GitHub issue, if provided: title, body, comments, assignees, and URL. If the rendered issue page does not expose the comment thread, fetch the issue comments via the GitHub API (`/repos/{owner}/{repo}/issues/{number}/comments`) or `gh api` before continuing. -2. Fetch and study the reference URL. Extract behavior, states, accessibility, anatomy, and examples. -3. Identify the semantic pattern: native element, Radix primitive, or WAI-ARIA/APG pattern. For composites, define roles, relationships, keyboard behavior, focus lifecycle, and announced states before proposing API details. -4. Compare against project rules from `component-contributor`, especially Phase 1 requirements. -5. Present a proposed spec using `references/spec-template.md` with concrete accessibility acceptance criteria and expected tests. -6. Include an `Assumptions to validate` section for choices not explicit in the issue/reference, especially screen reader, focus, or keyboard decisions. -7. Ask the user to approve, reject, or edit the proposal. Do not write to GitHub before approval. -8. After approval, append or update a GitHub issue comment headed `## Validated component spec` using the approved spec. -9. Locate the Project item for the issue only to confirm it exists; do not move Project Status to `In progress` from this skill. -10. Report the issue URL, project item ID, approval state, and next command/action: wait for the `status:approved` issue label, then run START WORK via `github-project-tasks`, then start `component-contributor`. +1. Read the GitHub issue metadata first, if provided: title, assignees, labels, and URL. Confirm the contributor/user before comparing assignees. If the issue is assigned to someone other than the contributor/user, stop before further workflow action or GitHub writes and tell the user they need explicit permission before reassigning or taking over the issue. +2. Read the GitHub issue body and comments, if provided. If the rendered issue page does not expose the comment thread, fetch the issue comments via the GitHub API (`/repos/{owner}/{repo}/issues/{number}/comments`) or `gh api` before continuing. +3. Fetch and study the reference URL. Extract behavior, states, accessibility, anatomy, and examples. +4. Identify the semantic pattern: native element, Radix primitive, or WAI-ARIA/APG pattern. For composites, define roles, relationships, keyboard behavior, focus lifecycle, and announced states before proposing API details. +5. Compare against project rules from `component-contributor`, especially Phase 1 requirements. +6. Present a proposed spec using `references/spec-template.md` with concrete accessibility acceptance criteria and expected tests. +7. Include an `Assumptions to validate` section for choices not explicit in the issue/reference, especially screen reader, focus, or keyboard decisions. +8. Ask the user to approve, reject, or edit the proposal. Do not write to GitHub before approval. +9. After approval, append or update a GitHub issue comment headed `## Validated component spec` using the approved spec. +10. Locate the Project item for the issue only to confirm it exists; do not move Project Status to `In progress` from this skill. +11. Report the issue URL, project item ID, approval state, and next command/action: wait for the `status:approved` issue label, then run START WORK via `github-project-tasks`, then start `component-contributor`. ## Output Contract @@ -79,7 +81,7 @@ After approval and GitHub update, return: **Spec**: Added to issue as `Validated component spec` **Project setup**: {team/category present or missing setup} **Approval gate**: Waiting for issue label `status:approved` -**Next**: After the issue has label `status:approved`, run START WORK via `github-project-tasks`, then run `component-contributor` for implementation. +**Next**: After the issue has label `status:approved` and is unassigned or assigned to the contributor/user, run START WORK via `github-project-tasks`, then run `component-contributor` for implementation. ``` ## References diff --git a/.atl/skills/component-spec-proposer/references/github-project-update.md b/.atl/skills/component-spec-proposer/references/github-project-update.md index 84378c4a..e80236ee 100644 --- a/.atl/skills/component-spec-proposer/references/github-project-update.md +++ b/.atl/skills/component-spec-proposer/references/github-project-update.md @@ -20,7 +20,7 @@ item_id=$(gh project item-list 1 \ ``` Do not move Project Status to `In progress` from `component-spec-proposer`. -That transition belongs to START WORK in `github-project-tasks`, after spec approval, after the linked issue has label `status:approved`, and immediately before implementation. +That transition belongs to START WORK in `github-project-tasks`, after spec approval, after the linked issue has label `status:approved`, after assignee ownership is verified, and immediately before implementation. If the issue is assigned to someone else, stop and require explicit permission before reassignment/takeover. Add the approved spec to the issue: @@ -32,4 +32,4 @@ gh issue comment NUMBER \ If a previous `Validated component spec` comment exists, prefer editing it manually or with the GitHub API instead of adding duplicates. -After writing the validated spec, report that the task is waiting for the issue label `status:approved`. Do not start `component-contributor` or move the Project item to `In progress` until that label is present. +After writing the validated spec, report that the task is waiting for the issue label `status:approved` and assignee ownership verification. Do not start `component-contributor` or move the Project item to `In progress` until both gates pass. diff --git a/.atl/skills/components-auditor/SKILL.md b/.atl/skills/components-auditor/SKILL.md index 4d58c237..ddf18671 100644 --- a/.atl/skills/components-auditor/SKILL.md +++ b/.atl/skills/components-auditor/SKILL.md @@ -52,6 +52,8 @@ Audit against `.atl/skills/_shared/component-contract.md`: Use the Storybook and testing references as the single source of truth. In particular: - story docs live in JSDoc above `const meta` and each story export; +- each story JSDoc explains the scenario and why it matters, not just the story name; +- story set is necessary and non-duplicative, including no generic theme-only `DarkMode` story when the global Storybook dark-mode toolbar covers the case; - `parameters.docs.description.component` is not used; - no manual `argTypes` unless a documented exception exists; - event args use `action(...)`; diff --git a/.atl/skills/github-project-tasks/SKILL.md b/.atl/skills/github-project-tasks/SKILL.md index 04c89722..10e37176 100644 --- a/.atl/skills/github-project-tasks/SKILL.md +++ b/.atl/skills/github-project-tasks/SKILL.md @@ -14,7 +14,7 @@ metadata: Use this skill for Stack-and-Flow GitHub issue + Project board work. It has four modes: - **CREATE** — create issue(s), add to Project, set fields. -- **START WORK** — after the linked issue has label `status:approved`, assign the issue, move the Project item to `In progress`, and record the branch/worktree plan before implementation starts. +- **START WORK** — after the linked issue has label `status:approved`, verify the assignee is empty or already the contributor/user, assign the issue, move the Project item to `In progress`, and record the branch/worktree plan before implementation starts. If the issue is assigned to someone else, stop before any mutation and require explicit permission to reassign it. - **END WORK** — comment validation/PR evidence and move the Project item to `Done` only after the task is genuinely complete. - **AUDIT** — detect malformed existing issues or board items. @@ -72,7 +72,8 @@ Option IDs: - Always write multi-line issue bodies to a temp file and pass `--body-file`. - Confirm task name, tier/type, reference URL when applicable, assignee, team, category, and milestone before CREATE. - Milestone is mandatory for CREATE. If it is missing, ask interactively before creating the issue; do not invent it. -- Before implementation starts from a GitHub issue, require the exact issue label `status:approved`, then run START WORK: assign the issue to the contributor/user and move the Project item to `In progress`. +- Before implementation starts from a GitHub issue, require the exact issue label `status:approved`, then run START WORK: verify current assignees, assign the issue to the contributor/user, and move the Project item to `In progress`. +- If a linked issue is already assigned to someone other than the contributor/user, stop before assignment, Project status changes, branch/worktree actions, planning, or implementation. Notify the user: `Issue #{number} is already assigned to @{assignee}; ask for explicit permission before reassigning it.` Continue only after explicit permission is provided in the current task context. - Before marking a task done, run END WORK: add validation/PR evidence and move the Project item to `Done` only when merged or explicitly approved by the maintainer/user. - Do not invent a missing reference URL; ask or research. @@ -134,7 +135,7 @@ $itemId = gh project item-add 1 ` ## Mode 2 — START WORK -Run this before implementation starts from an existing GitHub issue or board card, after the linked issue has label `status:approved`. Offline/no-network mode may skip GitHub mutations only after approval evidence confirms the label is present; it does not permit implementation without `status:approved`. +Run this before implementation starts from an existing GitHub issue or board card, after the linked issue has label `status:approved`. Offline/no-network mode may skip GitHub mutations only after evidence confirms the label is present and the assignee gate is satisfied; it does not permit implementation without `status:approved` or against an issue assigned to someone else without explicit reassignment permission. Inputs required: @@ -143,11 +144,12 @@ Inputs required: 3. GitHub username of the contributor/user doing the work. 4. Planned branch name. 5. Planned worktree path when a worktree will be used. +6. Explicit maintainer/user permission to reassign, only when the issue is already assigned to someone else. Steps: 1. Confirm the issue is the right task and the contributor/user is correct. -2. Verify the exact issue label `status:approved` is present. If it is missing, stop; do not move the Project item to `In progress`. +2. Verify the exact issue label `status:approved` is present. If it is missing, stop; do not assign the issue or move the Project item to `In progress`. ```powershell $approvalLabel = gh issue view {issue_number} ` @@ -158,7 +160,21 @@ $approvalLabel = gh issue view {issue_number} ` If `$approvalLabel` is empty, the approval gate is not satisfied. Stop; implementation must not start under any circumstance. -3. Assign the issue: +3. Verify assignee ownership before any mutation, branch/worktree action, planning, or implementation: + +```powershell +$assignees = gh issue view {issue_number} ` + --repo Stack-and-Flow/design-system ` + --json assignees ` + --jq '.assignees[].login' + +$ownedByContributor = $assignees | Select-String -SimpleMatch '{username}' +$assignedToOther = $assignees | Where-Object { $_ -and $_ -ne '{username}' } +``` + +If `$assignedToOther` is not empty and explicit maintainer/user permission to reassign is not present in the current task context, stop before mutating GitHub or starting work. Notify the user: `Issue #{number} is already assigned to @{assignee}; ask for explicit permission before reassigning it.` + +4. Assign the issue when it is unassigned, already assigned to `{username}`, or explicit reassignment permission was provided: ```powershell gh issue edit {issue_number} ` @@ -166,8 +182,8 @@ gh issue edit {issue_number} ` --add-assignee {username} ``` -4. Ensure the issue is on Project `1`. If not, add it with `gh project item-add`. -5. Resolve the Project item ID for existing cards: +5. Ensure the issue is on Project `1`. If not, add it with `gh project item-add`. +6. Resolve the Project item ID for existing cards: ```powershell $issueUrl = "https://github.com/Stack-and-Flow/design-system/issues/{issue_number}" @@ -180,7 +196,7 @@ $itemId = gh project item-list 1 ` If `$itemId` is empty after adding/checking the Project item, stop and report the blocker. -6. Move Project Status to `In progress`: +7. Move Project Status to `In progress`: ```powershell gh project item-edit ` @@ -190,8 +206,8 @@ gh project item-edit ` --single-select-option-id 47fc9ee4 ``` -7. Confirm Team and Category are set. If missing, set them using the option IDs above. -8. Report the work-start state: +8. Confirm Team and Category are set. If missing, set them using the option IDs above. +9. Report the work-start state: ```markdown ## Work Started @@ -199,6 +215,7 @@ gh project item-edit ` **Issue**: #{number} — {title} **Assignee**: @{username} **Approval gate**: issue label `status:approved` verified +**Assignee gate**: issue was unassigned, already assigned to @{username}, or explicit reassignment permission was recorded **Project status**: In progress **Team**: {team} **Category**: {category} @@ -206,7 +223,7 @@ gh project item-edit ` **Worktree**: `{path or "not used"}` ``` -Do not start implementation if the `status:approved` label is missing or unverified. Do not start implementation if assignment, item lookup, or `In progress` status fails, unless the user explicitly asks to continue offline/no-network after the approval label has been verified. +Do not start implementation if the `status:approved` label is missing or unverified. Do not start implementation if the assignee gate fails, assignment fails, item lookup fails, or `In progress` status fails, unless the user explicitly asks to continue offline/no-network after both the approval label and assignee gate have been verified. ## Branch and Worktree Naming @@ -346,9 +363,10 @@ For START WORK, return the `## Work Started` report shown in Mode 2, or: ## Work Start Skipped **Issue**: #{number} — {title} -**Reason**: offline/no-network requested or GitHub mutation failed after `status:approved` was verified +**Reason**: offline/no-network requested, issue already assigned to someone else without explicit reassignment permission, or GitHub mutation failed after `status:approved` was verified **Approval gate**: issue label `status:approved` verified; if not verified, implementation remains blocked -**Required follow-up**: assign issue, move Project status to `In progress`, confirm team/category +**Assignee gate**: {unassigned / already assigned to @{username} / assigned to @{assignee}; explicit reassignment permission required} +**Required follow-up**: get explicit permission before reassigning when assigned to someone else; then assign issue, move Project status to `In progress`, confirm team/category **Branch**: `{branch}` **Worktree**: `{path or "not used"}` ``` diff --git a/.atl/skills/github-project-tasks/references/issue-body-template.md b/.atl/skills/github-project-tasks/references/issue-body-template.md index e7520d13..42b0e29f 100644 --- a/.atl/skills/github-project-tasks/references/issue-body-template.md +++ b/.atl/skills/github-project-tasks/references/issue-body-template.md @@ -36,7 +36,8 @@ Out of scope: - [ ] Issue triaged with Team and Category fields set on the Project board, and GitHub milestone assigned. - [ ] Specification or plan recorded in this issue when behavior, API, accessibility, or tokens are affected. - [ ] Validated spec reviewed and linked issue labeled `status:approved` before implementation starts. -- [ ] START WORK completed after label `status:approved`: assignee set, Project status moved to `In progress`, branch/worktree recorded. +- [ ] Assignee ownership checked before START WORK; if assigned to someone else, explicit reassignment permission documented. +- [ ] START WORK completed after label `status:approved` and assignee gate: assignee set, Project status moved to `In progress`, branch/worktree recorded. - [ ] Implementation completed inside the approved scope. - [ ] Validation evidence recorded in the PR or issue. - [ ] PR opened and linked with `Closes #NNN`. @@ -45,7 +46,7 @@ Out of scope: ### Specification or plan -For component work, paste or link the approved `## Validated component spec` from `component-spec-proposer` before implementation starts. After the spec is defined, the contributor waits for the issue label `status:approved`; no START WORK or implementation happens before that label. +For component work, paste or link the approved `## Validated component spec` from `component-spec-proposer` before implementation starts. After the spec is defined, the contributor waits for the issue label `status:approved` and verifies assignee ownership; no START WORK or implementation happens before both gates pass. For non-component work, record: @@ -78,6 +79,7 @@ For non-component work, record: Filled during START WORK: - Approval marker: issue label status:approved +- Assignee gate: unassigned / assigned to contributor / explicit reassignment permission - Assignee: - Branch: - Worktree: diff --git a/.atl/skills/pr-reviewer/SKILL.md b/.atl/skills/pr-reviewer/SKILL.md index ba01d934..a6b20861 100644 --- a/.atl/skills/pr-reviewer/SKILL.md +++ b/.atl/skills/pr-reviewer/SKILL.md @@ -35,8 +35,10 @@ Run first. If any check fails, return **REJECTED** and do not continue to option | CI/build/test evidence missing or failing | Inspect CI output or run the agreed local commands. | | Package compatibility evidence missing for package-facing changes | When the diff changes package output, exports, generated declarations, peer ranges, CI/package distribution policy, or a React major version, require `pnpm run build` and `pnpm run verify:package` evidence. Tests/Storybook alone are insufficient for React major upgrades. | | No linked issue | PR description must contain `Closes #NNN` unless maintainer explicitly waives it. | +| 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`. | @@ -55,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 @@ -80,6 +83,7 @@ Do not duplicate the component checklist here; cite the audit evidence and only ### 4 — Git hygiene +- [ ] Linked issue assignee gate passed before branch/work started, or explicit permission to reassign/take over is documented. - [ ] Branch name follows issue-derived project convention when applicable: `{type}/{issue-number}-{slug}` (for example `feat/123-button`) or has an approved exception. - [ ] Commit messages and PR title follow Conventional Commit format. - [ ] Allowed types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`. @@ -112,6 +116,7 @@ Do not duplicate the component checklist here; cite the audit evidence and only - [CRITICAL|MAJOR] `file:line` — {problem} — Fix: {what to do} ### Evidence checked +- Linked issue assignee gate: {pass/fail/not applicable} - Component audit: {pass/fail/not applicable} - Visual review: {pass/fail/not applicable} - Typecheck/tests/build/storybook: {results} diff --git a/.atl/skills/worktree-location/SKILL.md b/.atl/skills/worktree-location/SKILL.md index 1dbfbb59..21262217 100644 --- a/.atl/skills/worktree-location/SKILL.md +++ b/.atl/skills/worktree-location/SKILL.md @@ -34,7 +34,9 @@ Instead: ## Branch and Worktree Naming -When work starts from a GitHub issue, use the same naming convention as `github-project-tasks` START WORK: +When work starts from a GitHub issue, first verify the `github-project-tasks` START WORK gates: the issue has `status:approved` and is unassigned or assigned to the contributor/user. If it is assigned to someone else, stop before creating a branch/worktree and require explicit permission before reassigning or taking it over. + +Then use the same naming convention as `github-project-tasks` START WORK: ```text branch: {type}/{issue-number}-{slug} diff --git a/.github/ISSUE_TEMPLATE/a11y.yml b/.github/ISSUE_TEMPLATE/a11y.yml index df79fd73..6c70e892 100644 --- a/.github/ISSUE_TEMPLATE/a11y.yml +++ b/.github/ISSUE_TEMPLATE/a11y.yml @@ -9,7 +9,7 @@ body: ## Accessibility Task Use this for WCAG, ARIA, keyboard navigation, focus management, screen reader behavior, or contrast issues. - Current flow: reproduce/audit -> define expected accessible behavior -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> keyboard/screen reader/axe evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: reproduce/audit -> define expected accessible behavior -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> keyboard/screen reader/axe evidence -> PR -> END WORK after merge or maintainer approval. Use `[FIX]` for accessibility defects and `[UPDATE]` for intentional accessibility improvements. @@ -106,7 +106,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/ci.yml b/.github/ISSUE_TEMPLATE/ci.yml index fcd860eb..630ab0a5 100644 --- a/.github/ISSUE_TEMPLATE/ci.yml +++ b/.github/ISSUE_TEMPLATE/ci.yml @@ -9,7 +9,7 @@ body: ## Infrastructure Task Use this for GitHub Actions, Vite, Biome, Lefthook, Storybook build, tests, release automation, or project tooling. - Current flow: define problem and risk -> plan exact config change -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> verify with local command or workflow run -> PR -> END WORK after merge or maintainer approval. + Current flow: define problem and risk -> plan exact config change -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> verify with local command or workflow run -> PR -> END WORK after merge or maintainer approval. - type: dropdown id: area @@ -89,7 +89,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/component.yml b/.github/ISSUE_TEMPLATE/component.yml index 5bcc3265..054cac92 100644 --- a/.github/ISSUE_TEMPLATE/component.yml +++ b/.github/ISSUE_TEMPLATE/component.yml @@ -9,7 +9,7 @@ body: ## New Component Task Use this for atoms, molecules, and organisms. New components must go through `component-spec-proposer` before implementation. - Current flow: reference and context -> validated component spec -> wait for issue label `status:approved` -> START WORK Project gate -> implementation -> component audit, visual review, accessibility evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: reference and context -> validated component spec -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implementation -> component audit, visual review, accessibility evidence -> PR -> END WORK after merge or maintainer approval. Set the title prefix to `[ATOMS]`, `[MOLECULES]`, or `[ORGANISMS]` based on the selected level. @@ -102,7 +102,7 @@ body: label: Workflow gates options: - label: Spec proposal must be approved before implementation starts. - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: Implementation must follow the 6-file component pattern. - label: Component audit, visual review, accessibility evidence, and focused tests are required before PR review. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/fix.yml b/.github/ISSUE_TEMPLATE/fix.yml index b36eb384..a5868cac 100644 --- a/.github/ISSUE_TEMPLATE/fix.yml +++ b/.github/ISSUE_TEMPLATE/fix.yml @@ -9,7 +9,7 @@ body: ## Bug Fix Task Use this when existing behavior is wrong or regressed. - Current flow: reproduce with evidence -> identify root cause/spec -> wait for issue label `status:approved` -> START WORK Project gate -> fix with regression test -> focused validation -> PR -> END WORK after merge or maintainer approval. + Current flow: reproduce with evidence -> identify root cause/spec -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> fix with regression test -> focused validation -> PR -> END WORK after merge or maintainer approval. - type: input id: affected-area @@ -87,7 +87,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/npm.yml b/.github/ISSUE_TEMPLATE/npm.yml index b8a36e3d..ebe454fa 100644 --- a/.github/ISSUE_TEMPLATE/npm.yml +++ b/.github/ISSUE_TEMPLATE/npm.yml @@ -9,7 +9,7 @@ body: ## NPM / Dependencies Task Use this for dependency updates, security fixes, peer dependency changes, package metadata, or dependency removals. - Current flow: research changelog and risk -> define update plan -> wait for issue label `status:approved` -> START WORK Project gate -> update -> verify build/tests/package consumption -> PR -> END WORK after merge or maintainer approval. + Current flow: research changelog and risk -> define update plan -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> update -> verify build/tests/package consumption -> PR -> END WORK after merge or maintainer approval. - type: dropdown id: change-type @@ -90,7 +90,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/storybook.yml b/.github/ISSUE_TEMPLATE/storybook.yml index 72e3988c..6ee56565 100644 --- a/.github/ISSUE_TEMPLATE/storybook.yml +++ b/.github/ISSUE_TEMPLATE/storybook.yml @@ -9,7 +9,7 @@ body: ## Storybook / Docs Task Use this for stories, MDX docs, controls, usage guidelines, visual examples, or Storybook configuration. - Current flow: identify documentation gap -> define required stories/docs -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> Storybook/manual visual evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: identify documentation gap -> define required stories/docs -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> Storybook/manual visual evidence -> PR -> END WORK after merge or maintainer approval. - type: input id: affected-area @@ -85,6 +85,8 @@ body: label: Storybook/docs gates options: - label: Stories follow project conventions and do not use Storybook `play` functions. + - label: Each story has useful JSDoc explaining the scenario and why it matters. + - label: Stories are non-redundant; generic `DarkMode` stories are avoided because Storybook has a global dark-mode toolbar. - label: Controls and args reflect the public API. - label: Visual states and edge cases are represented when relevant. - label: Accessibility notes are included for interactive examples when relevant. @@ -94,7 +96,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/tokens.yml b/.github/ISSUE_TEMPLATE/tokens.yml index e46da328..c96e0c5e 100644 --- a/.github/ISSUE_TEMPLATE/tokens.yml +++ b/.github/ISSUE_TEMPLATE/tokens.yml @@ -9,7 +9,7 @@ body: ## Design Tokens Task Use this for CSS custom properties, Tailwind token utilities, color, typography, spacing, radius, shadow, motion, or token documentation. - Current flow: audit token need and consumers -> define token/spec impact -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> contrast/visual/docs evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: audit token need and consumers -> define token/spec impact -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> contrast/visual/docs evidence -> PR -> END WORK after merge or maintainer approval. - type: dropdown id: token-type @@ -99,7 +99,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/update.yml b/.github/ISSUE_TEMPLATE/update.yml index 6a36588b..5968d1dc 100644 --- a/.github/ISSUE_TEMPLATE/update.yml +++ b/.github/ISSUE_TEMPLATE/update.yml @@ -9,7 +9,7 @@ body: ## Update or Refactor Task Use this for behavior extensions, API changes, refactors, and quality improvements that are not simple bug fixes. - Current flow: define motivation and scope -> record validated spec/plan when behavior changes -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> validation and audit evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: define motivation and scope -> record validated spec/plan when behavior changes -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> validation and audit evidence -> PR -> END WORK after merge or maintainer approval. - type: input id: affected-area @@ -129,7 +129,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5a484e11..304b6873 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,6 +27,7 @@ Closes # - [ ] Linked issue is present with `Closes #NNN` or maintainer approved an exception. - [ ] Linked issue has label `status:approved` before implementation starts. +- [ ] Linked issue assignee was checked before work started; if it was assigned to someone else, explicit reassignment permission is documented. - [ ] Work was started through the Project flow: assignee set, Project status `In progress`, branch/worktree recorded. - [ ] PR title follows Conventional Commit format: `(): `. - [ ] Commits follow the same commitlint-enforced format. diff --git a/README.en.md b/README.en.md index 01ba0da7..21affcc6 100644 --- a/README.en.md +++ b/README.en.md @@ -77,9 +77,9 @@ This project uses GitHub Issues + GitHub Projects as the source workflow. Short path: 1. Pick an issue from the [Project Board](https://github.com/orgs/Stack-and-Flow/projects/1). -2. Before implementing, verify that the spec is defined and the issue has the `status:approved` label. +2. Before implementing, verify that the spec is defined, the issue has the `status:approved` label, and the issue is not assigned to someone else. 3. Only then run **START WORK**: - - assign the issue to the contributor; + - verify assignees and assign the issue to the contributor; - move the Project item to `In progress`; - record the branch and worktree. 4. Use issue-based branch names: diff --git a/README.md b/README.md index 64f7858f..6b35776a 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,9 @@ Este proyecto usa GitHub Issues + GitHub Projects como flujo de trabajo. Ruta corta: 1. Elegí una issue del [Project Board](https://github.com/orgs/Stack-and-Flow/projects/1). -2. Antes de implementar, verificá que la spec esté definida y que la issue tenga el label `status:approved`. +2. Antes de implementar, verificá que la spec esté definida, que la issue tenga el label `status:approved` y que no esté asignada a otra persona. 3. Recién después ejecutá **START WORK**: - - asignar la issue al contributor; + - verificar assignees y asignar la issue al contributor; - mover el Project item a `In progress`; - registrar branch y worktree. 4. Usá branch issue-based: 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-`