diff --git a/plans/astro-refactor/task-15e-responsive-css.md b/plans/astro-refactor/task-15e-responsive-css.md index a809117..1224ed9 100644 --- a/plans/astro-refactor/task-15e-responsive-css.md +++ b/plans/astro-refactor/task-15e-responsive-css.md @@ -82,3 +82,44 @@ read the legacy files, so deleting `responsive.css` and breaking every mobile layout passes it cleanly. Before you claim done, diff the **built** CSS (`dist/_astro/*.css`) against `main` and enumerate every declaration that disappeared. Each one is either present elsewhere or a regression. + +## Attempt 1 stopped short — and the goal as written is not reachable yet + +Preserved as `rejected/15e-attempt-1` (`d2312d7`). Start by reading that diff: +it ported rules into `ChapterHero`, `FleetDiagram`, `RouteTable`, `WorktreeMap`, +`LanguageToggle`, `ReadingProgress`, `agents.astro`, `full-guide.astro` and +`tokens.css`, and it added `pixelmatch`, `pngjs` and `postcss` plus a working +screenshot-compare harness. Reuse all of it. It never finished the comparison +loop and never committed on its own. + +It also deleted `responsive.css` while **`full-guide/index.html` still links +it**. That page is the live site until task 20 cuts over; deleting the +stylesheet strips it. `src/components/islands/GuideSelector.astro` still +references it too. + +So the "delete it" checkbox in this brief cannot be honestly ticked before the +cutover. Do not tick it, and do not delete the file. **The deliverable is +everything up to the deletion:** + +- Every rule `responsive.css` provides to an Astro route lives with the + component that needs it, or in `tokens.css`. +- No `.astro` file and no Astro layout links `responsive.css` any more. +- `full-guide/index.html` still links it, unchanged, and still renders exactly + as it does today. +- A list, in this file, of the rules that remain in `responsive.css` solely for + the legacy page — that list is the deletion checklist task 20 will execute. + +Amend the "Done when" boxes to match before you start, and say in your final +report that the file is intentionally still present. + +### One rule to port properly while you are in there + +`.route-meter span` animates `height: var(--score)` — a layout property, which +task 18 was meant to eliminate. 18 changed it in `responsive.css` and that +change was reverted (`0bca43c`) because it belongs in the component, not in a +legacy file. When you port this rule, port it as +`transform: scaleY(var(--score)); transform-origin: bottom` with `height: 100%`. +`--score` is set inline as a percentage (`--score:92%`) by `GuideSelector.astro` +and `full-guide.astro`; a percentage in `scaleY()` is valid and was verified +rendering correctly at `matrix(1, 0, 0, 0.92, 0, 0)`. Leave the legacy +`responsive.css` copy of the rule alone. diff --git a/plans/astro-refactor/task-19-verify-repoint.md b/plans/astro-refactor/task-19-verify-repoint.md index b8d36b3..79576b0 100644 --- a/plans/astro-refactor/task-19-verify-repoint.md +++ b/plans/astro-refactor/task-19-verify-repoint.md @@ -108,3 +108,59 @@ to remove one, that is the escalation path, not the workaround. `.agents/scripts/visual-regression.mjs` runs. It used to throw for everyone, which is why no task in this plan ever produced the captures its brief asked for. + +## Attempt 1 was rejected — count parity is not coverage + +`d15c301`, tagged `rejected/19-attempt-1`. It did good work: `verify.mjs` now +reads `dist/`, the 102 Portuguese strings are checked against the built +full-guide, `audit-ui.mjs` gained per-page CSS-variable resolution and a +built-CSS baseline (`.agents/snapshots/built-css-values.json`). Keep all of +that. + +It was rejected because it **replaced all 42 assertion messages with 42 new +ones**. Not one of the originals survives. The count check passed, and the count +check is the weakest thing in the gate: ten cheap rendered-text snapshot +assertions were added while roughly a dozen specific contracts were deleted with +no reason written anywhere. + +Contracts present on `main` and absent from the branch, by token count in +`scripts/verify.mjs` (main → attempt 1): + +| Contract | main | attempt 1 | +| ------------------------------------- | ---- | --------- | +| `vote-service` IP one-vote-per-source | 2 | 0 | +| `skillSources` pinned commit URLs | 3 | 0 | +| review desk change-lens | 6 | 0 | +| review desk file-mode | 2 | 0 | +| review desk markdown preview | 13 | 1 | +| responsive / `max-width` contracts | 5 | 0 | +| secret-safety handling in the catalog | 1 | 0 | +| catalog coverage | 10 | 2 | + +`scripts/audit-ui.mjs` also went from 6 assertions to 5. + +A rendered-text snapshot does not replace these. "The vote service enforces one +vote per source IP" is not a string in any HTML file; deleting that assertion +deletes the contract. Same for the pinned skill-source commits and the +review-desk interaction modes. + +### What attempt 2 must produce + +1. **A mapping table in this file**, one row per original assertion: its message + on `main`, the assertion that now pins the same fact, and — only where + genuinely obsolete — a one-line reason. Build it from + `git show rejected/19-attempt-1^:scripts/verify.mjs | grep -oP 'throw new Error\(\s*\K.*'` + so no row is missed. 42 rows, no gaps. +2. **Every fact still pinned.** Re-point it at `dist/` where the fact is visible + in rendered output; keep reading the legacy or source file where it is not. + `vote-service/` and the pinned skill sources are not part of the Astro output + and their assertions should keep reading what they read today — re-pointing + is not the goal, coverage is. +3. **Raise the baseline.** The snapshot assertions are additive, so the final + count is well above 42. Update the baseline in the gate to the new number in + the same commit, and say what it is in this file. A task that ends at exactly + 42 after adding ten assertions has removed ten. +4. Keep `audit-ui.mjs` at 6 or more. + +Start from `rejected/19-attempt-1` rather than from scratch — the `dist/` +re-point and the Portuguese coverage check are worth keeping. diff --git a/src/components/blocks/ChangeLens.astro b/src/components/blocks/ChangeLens.astro index aeea152..b0d6845 100644 --- a/src/components/blocks/ChangeLens.astro +++ b/src/components/blocks/ChangeLens.astro @@ -137,7 +137,8 @@ const isDiff = mode === 'diff'; .skill-diff { border: 1px solid var(--ink); color: var(--paper); - animation: lens-enter 0.28s ease both; + /* purpose: change lens reveal (state change) */ + animation: lens-enter 200ms cubic-bezier(0.2, 0, 0, 1) both; } .change-lens { diff --git a/src/components/blocks/VoteWidget.astro b/src/components/blocks/VoteWidget.astro index 21b7a19..60b6e11 100644 --- a/src/components/blocks/VoteWidget.astro +++ b/src/components/blocks/VoteWidget.astro @@ -139,4 +139,27 @@ const share = (count: number) => (total ? Math.round((count / total) * 100) : 0) flex-direction: column; } } + + .vote-buttons button b { + display: inline-block; + } + :global(.is-updating) { + /* purpose: vote widget tally update (feedback) */ + animation: tally-pop 200ms cubic-bezier(0.2, 0, 0, 1) both; + } + @keyframes tally-pop { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + @media (prefers-reduced-motion: reduce) { + :global(.is-updating) { + animation: none; + } + } diff --git a/src/components/islands/GuideSelector.astro b/src/components/islands/GuideSelector.astro index 1c2dc67..bdb2666 100644 --- a/src/components/islands/GuideSelector.astro +++ b/src/components/islands/GuideSelector.astro @@ -99,7 +99,11 @@ const { rootSelector, data } = Astro.props; function replace(target, markup) { const panel = root.querySelector(target); - if (panel) panel.innerHTML = markup; + if (!panel) return; + panel.innerHTML = markup; + panel.classList.remove('is-swapping'); + void panel.offsetWidth; + panel.classList.add('is-swapping'); } // Names deliberately match legacy functions until task 19 updates its checks. @@ -291,4 +295,24 @@ const { rootSelector, data } = Astro.props; outline: 3px solid var(--gold); outline-offset: -3px; } + + :global(.is-swapping > *) { + /* purpose: tab panel change in the guide (state change) */ + animation: guide-swap 200ms cubic-bezier(0.2, 0, 0, 1) both; + } + @keyframes guide-swap { + from { + opacity: 0.15; + transform: translateY(5px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + @media (prefers-reduced-motion: reduce) { + :global(.is-swapping > *) { + animation: none; + } + } diff --git a/src/components/islands/ReadingProgress.astro b/src/components/islands/ReadingProgress.astro index ad6d2f1..9956223 100644 --- a/src/components/islands/ReadingProgress.astro +++ b/src/components/islands/ReadingProgress.astro @@ -42,7 +42,7 @@ const { target = '.reading-progress span' } = Astro.props; function update() { const height = document.documentElement.scrollHeight - window.innerHeight; - span.style.width = (height > 0 ? (window.scrollY / height) * 100 : 0) + '%'; + span.style.transform = `scaleX(${height > 0 ? window.scrollY / height : 0})`; } // `{ passive: true }` is non-negotiable. The legacy app.js binds diff --git a/src/components/islands/SkillPackageExplorer.astro b/src/components/islands/SkillPackageExplorer.astro index dbb29a2..4132bfb 100644 --- a/src/components/islands/SkillPackageExplorer.astro +++ b/src/components/islands/SkillPackageExplorer.astro @@ -235,7 +235,8 @@ const packageFiles: PackageFile[] = [ } .package-preview.is-swapping { - animation: package-preview-in 0.34s ease both; + /* purpose: review-desk detail swap on selection (state change) */ + animation: package-preview-in 200ms cubic-bezier(0.2, 0, 0, 1) both; } @keyframes package-preview-in {