Uh oh!
There was an error while loading. Please reload this page.
refactor(frontend): unify CSS token layer + add (public) route group (Phase 1) - #286
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ate states correct) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…plicate namespace Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rarity + glass-input Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng-layer host Moves landing + about/careers/privacy/terms under app/(public)/ (URLs unchanged). The layout applies a token-only .public-surface scope so content pages keep the warm paper canvas; the landing retains .landing-page for its mesh visual. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(public)/page.tsx, HowItWorks.tsx, Dialog.tsx: --brand-text1/2 -> --text/--text-dim, --radius-* -> --r-*, --ease-out/in-out -> --ease. Mechanical identifier renames only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ngle namespace Migrates the 3 remaining globals.css --ease-out consumers to --ease, then deletes the temporary :root brand aliases and the .public-surface/.landing-page namespace aliases. Zero retired-token references remain tree-wide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + dir hygiene) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds shared UI primitives, updates token and public-surface styling, migrates public and in-app screens to the new primitives, and adds documentation for audits, plans, specs, and handoffs. ChangesUI primitives and token migration
Design audits and implementation notes
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying with |
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs | frontend-staging | 9313888 | Commit Preview URL Branch Preview URL | Jul 02 2026, 04:42 AM |
…/page.tsx The route move shifted the landing page out from under its path-keyed suppression entry, un-suppressing 4 pre-existing grandfathered errors (no-html-link-for-pages, prefer-const x2, react-hooks/immutability). Re-homes the entry to the new path; no code behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rison Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Retire sage --accent -> brighter forest (--brand-forest-bright) for highlight/focus; merge --state-mastery + --grade-a into one --positive status green; add .btn--lg hero size for de-pilled CTAs. Three forest-family greens by role: forest(action) / accent(highlight) / positive(status). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Thin wrappers over the canonical .btn/.chip classes. Button enforces one shape (6px) with variant + size (incl. lg hero size); Toggle is the one segmented control; Chip/Badge collapse the pill/badge zoo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ives - Landing CTAs (Get Started x2, Sign up for Beta) -> <Button size=lg>, de-pilled to sharp 6px, infinite glow removed. - 5 Gradebook modal save/submit buttons -> <Button> (kills hard-coded borderRadius:6). - Study flashcard ratings 10px -> 6px (kept color-coding). - Tokenize orphan #1a5c2a wordmark -> var(--brand-forest) across 8 files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add optional per-option title to <Toggle>; replace the Learn setup mode pills with it. ModelToggle (Fast/Smart) intentionally left as-is — it has a sliding animation, per-option color semantics, and a tooltip that the generic Toggle would degrade. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Flair Badge carries the hue on border + soft bg, keeps text neutral (colored text fails 4.5:1 on several rarity tiers). TitleFlair now wraps Badge instead of inline styles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arted CTA De-pilled CTAs hug the text now (lg 13/26 -> 9/18). The closing 'Get Started' under the 'Ready to Start Growing?' hero uses a new xl size so it stays a prominent central focal point; navbar + hero beta stay tight. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bright accent The header button hard-coded background:var(--accent); after accent shifted to the brighter forest, it rendered brighter than every other primary button. Now a proper <Button variant=primary> (--brand-forest), matching the term pills and app buttons. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Family (b) control: a wrapping row of selectable pills for 'All' + N dynamic filters, wrapping the existing <Pill> (with per-option color/icon). Complements <Toggle> (family (a): fixed connected segmented control). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the custom accent-filled pill buttons with the shared <Toggle> (forest-filled active). Keeps SemesterChips' public API; also fixes the prior --accent button fill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Overview/Chat/Study match/Activity tab row now uses the shared <Toggle>. setTab wiring unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
month/week/day/table switch now uses the shared <Toggle>; drops a pre-existing unused Pill import. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
grid/list view switch uses the shared <Toggle>; the category filter row uses the shared <FilterPills>. Drops the now-unused Pill import. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
all/activity/social/milestone/special filter row uses shared <FilterPills>. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Topic filter (All + dynamic topics) uses shared <FilterPills>. The mode toggle (Study Guide/Flashcards) is left specialized for its Framer-Motion spring, matching the ModelToggle precedent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tier filter uses shared <FilterPills> with per-option color. The course filter (colored dots) stays specialized per the design decision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
refactor(frontend): shared UI primitives + green consolidation (Phase 2)
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/frontend-component-consistency-audit.md (1)
86-89: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winClarify
--accentdecision status.Since
globals.cssalready resolved--accenttovar(--brand-forest-bright), the "Sage--accent" decision appears decided in favor of retiring toward forest. Update this section to reflect the current state, or note if this audit intentionally captures the pre-decision deliberation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/frontend-component-consistency-audit.md` around lines 86 - 89, The “Sage `--accent`” decision is no longer undecided, since `globals.css` already points `--accent` to `var(--brand-forest-bright)`. Update the “Decision needed” section in the audit to reflect that the accent has been resolved toward forest, or explicitly label this as historical deliberation if the intent is to preserve the pre-decision discussion. Keep the wording consistent with the existing `globals.css` and `--accent` references so the status is unambiguous.
🧹 Nitpick comments (18)
docs/superpowers/specs/2026-06-30-token-unification-design.md (3)
72-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUpdate
--accentdescription to match final implementation.The spec states
--accent#8a9a5b(sage) stays, but the actualglobals.cssimplementation (per upstream context) has--accent: var(--brand-forest-bright)(#2D8F5C). The green collapse re-homed--accentinto the forest family. Update this section to reflect the final Phase 1 implementation where--accentwas re-pointed to the brighter forest highlight role, not kept as sage.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-06-30-token-unification-design.md` around lines 72 - 79, Update the “Green collapse” section to match the final `globals.css` implementation: `--accent` is no longer sage and should be described as re-pointed to `--brand-forest-bright` for the forest highlight role. Adjust the text around `--accent`, `--brand-forest`, and `--brand-glow` in this spec so it reflects the Phase 1 token mapping used by the final implementation and does not imply sage was retained.
81-95: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClarify
.landing-pageretirement scope.The spec states
.landing-page class is retired as a token host, but the actual implementation retains.landing-pagefor mesh background and utility classes (.landing-*), co-existing with.public-surfacefor token scoping. Update to:.landing-pageis retired as a token host; it persists as a visual/utility scope for landing-specific mesh and font utilities, while.public-surfacecarries the marketing-layer tokens for all public routes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-06-30-token-unification-design.md` around lines 81 - 95, Clarify the `(public)` token-scoping guidance so `layout.tsx` and related docs distinguish `.landing-page` from the token host: `landing-page` should no longer be described as carrying marketing tokens, but as the visual/utility scope for mesh and `.landing-*` classes, while `.public-surface` is the actual token host for the public routes. Update the spec text around `(public)/layout.tsx`, `.landing-page`, and `.public-surface` to reflect this split and keep the existing route-group migration intent clear.
58-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClarify
--brand-text2migration target in retirement table.The table says migrate to
var(--text-dim) / --text-mutedbut the implementation plan standardizes onvar(--text-dim)for all 34 occurrences. Either update the spec to match the plan's mechanical migration, or note that--text-mutedis reserved for a future semantic refinement pass.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-06-30-token-unification-design.md` around lines 58 - 69, The retirement table entry for `--brand-text2` is inconsistent with the implementation plan. Update the spec in this token-unification section to use a single migration target, preferably `var(--text-dim)` for all `--brand-text2` consumers, and remove the ambiguous `--text-muted` mention unless you explicitly document it as a future follow-up. Keep the guidance aligned with the surrounding token refs/actions in this table so the `--brand-text2` migration is mechanically clear.docs/superpowers/specs/2026-06-30-component-system-phase2-design.md (3)
75-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUpdate migration list to reflect ModelToggle decision.
The spec lists
ModelToggle.tsxas a Toggle migration target, but the handoff records the precedent thatModelTogglewas kept specialized for its sliding animation + Fast/Smart color semantics. Update this item to reflect the actual implementation decision, or move it to a "Deferred/Decided" section.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-06-30-component-system-phase2-design.md` around lines 75 - 79, The migration list still treats ModelToggle as a Toggle target even though the implementation decision was to keep ModelToggle specialized for its sliding animation and Fast/Smart color semantics. Update the spec entry that mentions ModelToggle so it matches the actual decision by removing it from the Toggle migration list and either marking it as kept specialized or moving it into a Deferred/Decided section alongside the relevant Learn.tsx toggle items.
48-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUpdate Toggle spec to include
sizeandtitle?in options.The handoff documents the final Toggle API as
options: {value,label,title?}[]withsize: sm|md. Add these to the spec for completeness, or note that the spec predates these additions.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-06-30-component-system-phase2-design.md` around lines 48 - 50, The Toggle spec is missing fields that are part of the final API, so update the `<Toggle>` documentation to reflect `size: sm|md` and `options` entries including optional `title?`. Use the existing `components/ui/Toggle.tsx` section to add these props, or explicitly note that the spec predates these additions so readers know the API evolved. Keep the description aligned with the referenced Toggle replacement usage sites.
36-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd
xlsize to Button spec or clarify discrepancy with handoff.The handoff document (
2026-06-30-selector-consolidation.md) referencessize: sm|md|lg|xl, but this spec only definessm|md|lg. Ifxlwas added post-spec, note it here; if the handoff is incorrect, update it to match.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/specs/2026-06-30-component-system-phase2-design.md` around lines 36 - 47, The Button sizing contract is inconsistent between this spec and the handoff reference, since ButtonProps only lists sm, md, and lg while the handoff expects xl as well. Update the Button spec to either explicitly add xl to the documented size options and related class mapping, or clearly note that xl is not supported and the handoff should be corrected. Keep the description aligned with components/ui/Button.tsx and the ButtonProps definition so the size contract is unambiguous.docs/superpowers/plans/2026-06-30-token-unification.md (3)
209-218: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor documentation inconsistency:
.glass-input:focusshadow color value.The plan specifies
rgba(27, 109, 66, 0.2)but the actual implementation inglobals.css:636usesrgba(27, 108, 66, 0.2)— matching the#1B6C42→ rgb(27,108,66) value of--brand-forest. Update the plan to match the canonical token value.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/plans/2026-06-30-token-unification.md` around lines 209 - 218, Update the plan entry for `.glass-input:focus` so the documented box-shadow color matches the canonical `--brand-forest` token value used in `globals.css` and the `glass-input:focus` rule. Replace the mismatched `rgba(27, 109, 66, 0.2)` reference with the same `rgba(27, 108, 66, 0.2)` value that the actual implementation uses, keeping the note aligned with the `--brand-forest` token and the `glass-input:focus` selector.
270-279: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUpdate layout class to match final implementation.
The plan shows
className="landing-page"but the PR objectives and actualglobals.cssimplementation use.public-surfaceas the primary marketing scope class (with.landing-pagekept for mesh/utility compatibility). Update the plan to use.public-surfaceand note that.landing-pageis applied additionally on the landing page itself for mesh-specific styling.-export default function PublicLayout({ children }: { children: React.ReactNode }) {- return <div className="landing-page">{children}</div>;-}+export default function PublicLayout({ children }: { children: React.ReactNode }) {+ return <div className="public-surface">{children}</div>;+}Or if the final implementation uses both, document that explicitly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/superpowers/plans/2026-06-30-token-unification.md` around lines 270 - 279, The plan’s public layout example uses the wrong scope class name, so update the documented `PublicLayout` wrapper to reflect the final marketing surface class used in `globals.css`. Reference `PublicLayout` and make the plan say the subtree should be wrapped with `public-surface`, with `landing-page` mentioned as an additional class only where mesh-specific styling is needed on the landing page itself.
298-304: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd explicit eslint verification step to route move task.
Phase 1 experienced eslint suppression path breaks after route moves (documented in
docs/superpowers/handoffs/2026-06-30-selector-consolidation.md§Gotchas). Addnpx eslint .to the verification commands in Task 4 Step 4:-```bash-cd /home/andresl/Projects/sapling/frontend-npm run build 2>&1 | tail -20-```+```bash+cd /home/andresl/Projects/sapling/frontend+npm run build 2>&1 | tail -20+npx eslint . 2>&1 | tail -10+``` <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@docs/superpowers/plans/2026-06-30-token-unification.mdaround lines 298 -
304, The Task 4 Step 4 verification block only checks the build and missed the
eslint suppression breakage seen after route moves. Update the verification
commands in the route move plan to include an explicit npx eslint . run
(alongside the existing build check) so the step validates both compilation and
linting after the marketing routes are moved.</details> <!-- cr-comment:v1:86e5113c4120979995d03269 --> </blockquote></details> <details> <summary>docs/superpowers/handoffs/2026-06-30-selector-consolidation.md (1)</summary><blockquote> `52-58`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _⚡ Quick win_ **Consider adding the eslint-suppressions gotcha to the implementation plan.** This gotcha was learned in Phase 1 but the token-unification plan (`2026-06-30-token-unification.md`) doesn't mention it in Task 4. Add a cross-reference note in the plan's Task 4 or a "Lessons learned" appendix for future agentic workers. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@docs/superpowers/handoffs/2026-06-30-selector-consolidation.mdaround lines
52 - 58, Add the eslint-suppressions lesson to the token-unification plan so
future work remembers that moving or renaming files with grandfathered lint
suppressions requires re-homing entries in frontend/eslint-suppressions.json.
Update Task 4 in 2026-06-30-token-unification.md, or add a short “Lessons
learned” appendix, and cross-reference the file-path-based suppression behavior
so agentic workers don’t miss it when changing routes or component locations.</details> <!-- cr-comment:v1:4510f7b7efa9308f3b0ad93a --> </blockquote></details> <details> <summary>frontend/src/components/SideNav.tsx (1)</summary><blockquote> `129-131`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Consider aligning `textShadow` with the new token if `--brand-forest` value changed.** The `textShadow` on Line 131 still hard-codes `rgba(26, 92, 42, 0.2)` (the old green). If `--brand-forest` now resolves to a different hex than `#1a5c2a`, the glow will mismatch the text color. Consider using `color-mix()` or a derived token if available. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@frontend/src/components/SideNav.tsxaround lines 129 - 131, The SideNav
styling still hard-codes the old green in the text glow, sotextShadowcan
drift from the updated--brand-forestcolor. Update theSideNavstyle block
to derive the shadow from the same token used bycolor(for example viacolor-mix()or an existing derived token) so the glow stays consistent with--brand-forest.</details> <!-- cr-comment:v1:b626e28a95ecb8bee7de5a57 --> </blockquote></details> <details> <summary>frontend/src/components/TopNav.tsx (1)</summary><blockquote> `189-191`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Consider aligning `textShadow` with the new token if `--brand-forest` value changed.** The `textShadow` on Line 191 still hard-codes `rgba(26, 92, 42, 0.2)` (the old green). If `--brand-forest` now resolves to a different hex, the glow will mismatch the text color. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@frontend/src/components/TopNav.tsxaround lines 189 - 191, The TopNav text
glow is still tied to the old green value instead of the updated brand token.
Update thetextShadowinTopNavto derive from the same--brand-forest
color (or a matching token/derived value) so the glow stays consistent if the
token changes, and keep the change localized to the style block containingtextShadow.</details> <!-- cr-comment:v1:9e0a077a82eeeb536fc10598 --> </blockquote></details> <details> <summary>docs/frontend-rhythm-audit.html (1)</summary><blockquote> `118-118`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Minor brightness value drift from canonical token.** The `.app-btn` hover uses `filter:brightness(1.06)` while `globals.css:206` specifies `brightness(1.05)` for `.btn--primary:hover`. For a document claiming to show the "source of truth," align this to the actual token value. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@docs/frontend-rhythm-audit.htmlat line 118, The.app-btn:hoverbrightness
value is off from the canonical token, so align the hover filter in the
document’s button styles to match the shared primary button token used by.btn--primary:hover. Update the hover rule in this HTML so it uses the samebrightness(1.05)value referenced by the source-of-truth stylesheet, keeping
the audit output consistent with the token definition.</details> <!-- cr-comment:v1:7ee7c49a0a7a45e89c9938e0 --> </blockquote></details> <details> <summary>docs/button-shape-comparison.html (1)</summary><blockquote> `100-100`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Qualify the "211 buttons" count if it's an estimate.** The lede states the app is "already 95% there (211 buttons)" — if this is a static count from a moment in time, consider adding a date or noting it may shift as the codebase evolves. If it's precise, no change needed. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@docs/button-shape-comparison.htmlat line 100, The lede in the button-shape
comparison page presents the “211 buttons” figure as a fixed fact, so qualify it
if it is only a snapshot. Update the wording in the lede content to either mark
the count as an estimate or add a time reference/snapshot note, using the
surrounding copy about “already 95% there” and the primary action button
comparison as the place to adjust.</details> <!-- cr-comment:v1:987b7211cb17959280d05d6d --> </blockquote></details> <details> <summary>docs/frontend-rhythm-audit.md (1)</summary><blockquote> `39-53`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _⚡ Quick win_ **Spot-check line-numbered references for drift.** The audit makes numerous precise line claims (`globals.css:60–64, 135–138, 146–149, 762–789`, etc.). During a multi-commit PR that restructures tokens and moves routes, these are likely to shift. Consider either: - Verifying all cited line numbers against the final committed state, or - Replacing absolute line numbers with symbol/selector references (e.g., `:root` token block, `.landing-page` block) that survive edits. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@docs/frontend-rhythm-audit.mdaround lines 39 - 53, The audit’s references
rely on fragile absolute line numbers that may change as the token blocks move,
so update the cited locations to stable selector/symbol references instead.
Recheck the:rootand.landing-pagetoken sections inglobals.css, and
replace the line-range citations with those block/selector names (or other
durable identifiers) so the drift notes still point to the correct definitions
after subsequent edits.</details> <!-- cr-comment:v1:59c5d6f829b656ebe3384127 --> </blockquote></details> <details> <summary>frontend/src/components/ui/Button.tsx (1)</summary><blockquote> `18-21`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Consider typing `ref` explicitly for React 19 ref-as-prop support.** `React.ButtonHTMLAttributes<HTMLButtonElement>` does not include `ref`, so consumers can't pass `ref={...}` to `<Button>` without a TS error, even though React 19 supports ref-as-prop at runtime. Adding `ref?: React.Ref<HTMLButtonElement>` to the type would future-proof this primitive for callers needing DOM access (e.g., autofocus, imperative scroll/focus). <details> <summary>♻️ Suggested typing addition</summary> ```diff }: React.ButtonHTMLAttributes<HTMLButtonElement> & { variant?: Variant; size?: Size; + ref?: React.Ref<HTMLButtonElement>; }) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/ui/Button.tsx` around lines 18 - 21, The Button component props type currently omits ref, so callers get a TS error when using ref-as-prop. Update the Button component signature to explicitly include ref support alongside React.ButtonHTMLAttributes<HTMLButtonElement>, and make sure the exported Button primitive accepts React.Ref<HTMLButtonElement> while preserving the existing variant and size props.
frontend/src/components/ui/Toggle.tsx (1)
30-55: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winGroup semantics dropped from prior tablist implementation.
Each option is a standalone
aria-pressedbutton; there's norole="radiogroup"/role="tablist"(or equivalent) on the wrapper conveying that these options are mutually exclusive. The diff notes this replaces an implementation that had explicit tablist/tab/aria styling, so this is a semantic downgrade for assistive tech, though the control remains operable (each button still exposes its own label and pressed state).Worth a follow-up to add
role="radiogroup"+aria-label, withrole="radio"/aria-checkedon options (orrole="tablist"/role="tab"if that fits the calling contexts better), since this is now a broadly-adopted shared primitive.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/ui/Toggle.tsx` around lines 30 - 55, The Toggle shared primitive lost the group-level semantics from the previous tablist behavior. Update the wrapper in Toggle so it exposes a mutual-exclusion container role such as radiogroup or tablist with an accessible label, and change each option button to the matching child role/state (radio with aria-checked, or tab with tablist semantics) while preserving the existing onChange and visual styling logic.
frontend/src/components/Gradebook/EditWeightsModal.tsx (1)
257-257: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCancel button not migrated to shared
Button.The
Cancelbutton stays a bare native<button>whileSavenow uses the sharedButton, giving them different sizing/styling. Same pattern repeats inLetterScaleEditor.tsx(line 96) andCourse.tsx(line 171). Consider migratingCancelto<Button variant="secondary" size="sm">for visual consistency in modal footers.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/components/Gradebook/EditWeightsModal.tsx` at line 257, The modal footer still uses a native Cancel <button> in EditWeightsModal, which leaves it visually inconsistent with the shared Button used for Save. Update the Cancel action to use the shared Button component with the secondary/sm styling so it matches the existing footer pattern, and apply the same migration in LetterScaleEditor and Course where the bare Cancel buttons remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/changes-tour.html`:
- Around line 64-66: The legend entry for the accent token is mismatched in the
changes tour markup: the swatch in the changes-tour legend is using the
forest-bright hex while still labeling it as --accent. Update the legend item in
the changes-tour HTML so the dot color and label match the canonical token
system, either by changing the swatch to the sage accent value or by renaming
the label to --forest-bright, and verify the surrounding legend entries remain
consistent with the token names used elsewhere.
In `@docs/frontend-component-consistency-audit.md`:
- Around line 35-53: The `--accent` description in this audit is stale and still
reflects the old sage value, while the current token is already defined as the
brighter forest variant in `globals.css`. Update the `--accent` entry in this
document to match the current token definition and comment, or explicitly label
the section as historical/pre-unification baseline so it does not conflict with
the live design system state. Use the `--accent` token and the `globals.css`
definition as the reference points when revising the wording.
In `@frontend/src/components/ui/FilterPills.tsx`:
- Around line 30-40: The Pill button used by FilterPills currently behaves like
a default submit button and does not expose its active state to assistive tech.
Update the Pill component to render as a non-submitting button by setting
type="button", and add a pressed-state ARIA attribute driven by its
active/selected prop so the state is announced correctly. Focus the fix in the
Pill component itself, since FilterPills only passes active and onClick through
to Pill.
In `@frontend/src/components/ui/Toggle.tsx`:
- Around line 20-29: The shared Toggle container currently renders as an
inline-flex box without wrapping, which can cause long or dynamic option lists
to overflow horizontally. Update the Toggle component’s outer container in
Toggle.tsx to restore wrapping behavior by adding flex-wrap (or equivalent
wrapping styles) alongside the existing inline-flex styling, using the Toggle
primitive itself so callers like SemesterChips keep their options flowing onto
new lines when needed.
---
Outside diff comments:
In `@docs/frontend-component-consistency-audit.md`:
- Around line 86-89: The “Sage `--accent`” decision is no longer undecided,
since `globals.css` already points `--accent` to `var(--brand-forest-bright)`.
Update the “Decision needed” section in the audit to reflect that the accent has
been resolved toward forest, or explicitly label this as historical deliberation
if the intent is to preserve the pre-decision discussion. Keep the wording
consistent with the existing `globals.css` and `--accent` references so the
status is unambiguous.
---
Nitpick comments:
In `@docs/button-shape-comparison.html`:
- Line 100: The lede in the button-shape comparison page presents the “211
buttons” figure as a fixed fact, so qualify it if it is only a snapshot. Update
the wording in the lede content to either mark the count as an estimate or add a
time reference/snapshot note, using the surrounding copy about “already 95%
there” and the primary action button comparison as the place to adjust.
In `@docs/frontend-rhythm-audit.html`:
- Line 118: The `.app-btn:hover` brightness value is off from the canonical
token, so align the hover filter in the document’s button styles to match the
shared primary button token used by `.btn--primary:hover`. Update the hover rule
in this HTML so it uses the same `brightness(1.05)` value referenced by the
source-of-truth stylesheet, keeping the audit output consistent with the token
definition.
In `@docs/frontend-rhythm-audit.md`:
- Around line 39-53: The audit’s references rely on fragile absolute line
numbers that may change as the token blocks move, so update the cited locations
to stable selector/symbol references instead. Recheck the `:root` and
`.landing-page` token sections in `globals.css`, and replace the line-range
citations with those block/selector names (or other durable identifiers) so the
drift notes still point to the correct definitions after subsequent edits.
In `@docs/superpowers/handoffs/2026-06-30-selector-consolidation.md`:
- Around line 52-58: Add the eslint-suppressions lesson to the token-unification
plan so future work remembers that moving or renaming files with grandfathered
lint suppressions requires re-homing entries in
frontend/eslint-suppressions.json. Update Task 4 in
2026-06-30-token-unification.md, or add a short “Lessons learned” appendix, and
cross-reference the file-path-based suppression behavior so agentic workers
don’t miss it when changing routes or component locations.
In `@docs/superpowers/plans/2026-06-30-token-unification.md`:
- Around line 209-218: Update the plan entry for `.glass-input:focus` so the
documented box-shadow color matches the canonical `--brand-forest` token value
used in `globals.css` and the `glass-input:focus` rule. Replace the mismatched
`rgba(27, 109, 66, 0.2)` reference with the same `rgba(27, 108, 66, 0.2)` value
that the actual implementation uses, keeping the note aligned with the
`--brand-forest` token and the `glass-input:focus` selector.
- Around line 270-279: The plan’s public layout example uses the wrong scope
class name, so update the documented `PublicLayout` wrapper to reflect the final
marketing surface class used in `globals.css`. Reference `PublicLayout` and make
the plan say the subtree should be wrapped with `public-surface`, with
`landing-page` mentioned as an additional class only where mesh-specific styling
is needed on the landing page itself.
- Around line 298-304: The Task 4 Step 4 verification block only checks the
build and missed the eslint suppression breakage seen after route moves. Update
the verification commands in the route move plan to include an explicit npx
eslint . run (alongside the existing build check) so the step validates both
compilation and linting after the marketing routes are moved.
In `@docs/superpowers/specs/2026-06-30-component-system-phase2-design.md`:
- Around line 75-79: The migration list still treats ModelToggle as a Toggle
target even though the implementation decision was to keep ModelToggle
specialized for its sliding animation and Fast/Smart color semantics. Update the
spec entry that mentions ModelToggle so it matches the actual decision by
removing it from the Toggle migration list and either marking it as kept
specialized or moving it into a Deferred/Decided section alongside the relevant
Learn.tsx toggle items.
- Around line 48-50: The Toggle spec is missing fields that are part of the
final API, so update the `<Toggle>` documentation to reflect `size: sm|md` and
`options` entries including optional `title?`. Use the existing
`components/ui/Toggle.tsx` section to add these props, or explicitly note that
the spec predates these additions so readers know the API evolved. Keep the
description aligned with the referenced Toggle replacement usage sites.
- Around line 36-47: The Button sizing contract is inconsistent between this
spec and the handoff reference, since ButtonProps only lists sm, md, and lg
while the handoff expects xl as well. Update the Button spec to either
explicitly add xl to the documented size options and related class mapping, or
clearly note that xl is not supported and the handoff should be corrected. Keep
the description aligned with components/ui/Button.tsx and the ButtonProps
definition so the size contract is unambiguous.
In `@docs/superpowers/specs/2026-06-30-token-unification-design.md`:
- Around line 72-79: Update the “Green collapse” section to match the final
`globals.css` implementation: `--accent` is no longer sage and should be
described as re-pointed to `--brand-forest-bright` for the forest highlight
role. Adjust the text around `--accent`, `--brand-forest`, and `--brand-glow` in
this spec so it reflects the Phase 1 token mapping used by the final
implementation and does not imply sage was retained.
- Around line 81-95: Clarify the `(public)` token-scoping guidance so
`layout.tsx` and related docs distinguish `.landing-page` from the token host:
`landing-page` should no longer be described as carrying marketing tokens, but
as the visual/utility scope for mesh and `.landing-*` classes, while
`.public-surface` is the actual token host for the public routes. Update the
spec text around `(public)/layout.tsx`, `.landing-page`, and `.public-surface`
to reflect this split and keep the existing route-group migration intent clear.
- Around line 58-69: The retirement table entry for `--brand-text2` is
inconsistent with the implementation plan. Update the spec in this
token-unification section to use a single migration target, preferably
`var(--text-dim)` for all `--brand-text2` consumers, and remove the ambiguous
`--text-muted` mention unless you explicitly document it as a future follow-up.
Keep the guidance aligned with the surrounding token refs/actions in this table
so the `--brand-text2` migration is mechanically clear.
In `@frontend/src/components/Gradebook/EditWeightsModal.tsx`:
- Line 257: The modal footer still uses a native Cancel <button> in
EditWeightsModal, which leaves it visually inconsistent with the shared Button
used for Save. Update the Cancel action to use the shared Button component with
the secondary/sm styling so it matches the existing footer pattern, and apply
the same migration in LetterScaleEditor and Course where the bare Cancel buttons
remain.
In `@frontend/src/components/SideNav.tsx`:
- Around line 129-131: The SideNav styling still hard-codes the old green in the
text glow, so `textShadow` can drift from the updated `--brand-forest` color.
Update the `SideNav` style block to derive the shadow from the same token used
by `color` (for example via `color-mix()` or an existing derived token) so the
glow stays consistent with `--brand-forest`.
In `@frontend/src/components/TopNav.tsx`:
- Around line 189-191: The TopNav text glow is still tied to the old green value
instead of the updated brand token. Update the `textShadow` in `TopNav` to
derive from the same `--brand-forest` color (or a matching token/derived value)
so the glow stays consistent if the token changes, and keep the change localized
to the style block containing `textShadow`.
In `@frontend/src/components/ui/Button.tsx`:
- Around line 18-21: The Button component props type currently omits ref, so
callers get a TS error when using ref-as-prop. Update the Button component
signature to explicitly include ref support alongside
React.ButtonHTMLAttributes<HTMLButtonElement>, and make sure the exported Button
primitive accepts React.Ref<HTMLButtonElement> while preserving the existing
variant and size props.
In `@frontend/src/components/ui/Toggle.tsx`:
- Around line 30-55: The Toggle shared primitive lost the group-level semantics
from the previous tablist behavior. Update the wrapper in Toggle so it exposes a
mutual-exclusion container role such as radiogroup or tablist with an accessible
label, and change each option button to the matching child role/state (radio
with aria-checked, or tab with tablist semantics) while preserving the existing
onChange and visual styling logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: fd3a88a8-8c68-4b91-9549-fefcfe116af4
📒 Files selected for processing (47)
docs/button-shape-comparison.htmldocs/changes-tour.htmldocs/frontend-component-consistency-audit.mddocs/frontend-rhythm-audit.htmldocs/frontend-rhythm-audit.mddocs/superpowers/followups/2026-06-30-token-unification-followups.mddocs/superpowers/handoffs/2026-06-30-selector-consolidation.mddocs/superpowers/plans/2026-06-30-token-unification.mddocs/superpowers/specs/2026-06-30-component-system-phase2-design.mddocs/superpowers/specs/2026-06-30-token-unification-design.mdfrontend/eslint-suppressions.jsonfrontend/src/app/(public)/about/page.tsxfrontend/src/app/(public)/careers/[slug]/ApplyForm.tsxfrontend/src/app/(public)/careers/[slug]/page.tsxfrontend/src/app/(public)/careers/jobs.tsfrontend/src/app/(public)/careers/page.tsxfrontend/src/app/(public)/layout.tsxfrontend/src/app/(public)/page.tsxfrontend/src/app/(public)/privacy/page.tsxfrontend/src/app/(public)/terms/page.tsxfrontend/src/app/globals.cssfrontend/src/components/Dialog.tsxfrontend/src/components/Gradebook/AssignmentModal.tsxfrontend/src/components/Gradebook/EditWeightsModal.tsxfrontend/src/components/Gradebook/LetterScaleEditor.tsxfrontend/src/components/Gradebook/SemesterChips.tsxfrontend/src/components/Gradebook/SyllabusUploadFlow.tsxfrontend/src/components/HowItWorks.tsxfrontend/src/components/SideNav.tsxfrontend/src/components/SignInModal.tsxfrontend/src/components/TitleFlair.tsxfrontend/src/components/TopNav.tsxfrontend/src/components/screens/Achievements.tsxfrontend/src/components/screens/Calendar.tsxfrontend/src/components/screens/Gradebook/Course.tsxfrontend/src/components/screens/Gradebook/Landing.tsxfrontend/src/components/screens/Learn.tsxfrontend/src/components/screens/Library.tsxfrontend/src/components/screens/Social.tsxfrontend/src/components/screens/Study.tsxfrontend/src/components/screens/Tree.tsxfrontend/src/components/ui/Badge.tsxfrontend/src/components/ui/Button.tsxfrontend/src/components/ui/Chip.tsxfrontend/src/components/ui/FilterPills.tsxfrontend/src/components/ui/Toggle.tsxfrontend/src/components/ui/index.ts
| <span class="sw"><span class="dot" style="background:#1B6C42"></span>--brand-forest · primary action</span> | ||
| <span class="sw"><span class="dot" style="background:#2D8F5C"></span>--accent · highlight (was sage)</span> | ||
| <span class="sw"><span class="dot" style="background:#3a7d4e"></span>--positive · status (mastery/grade-A)</span> |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the --accent token color in the legend.
The legend labels #2D8F5C as --accent · highlight (was sage), but this hex is --forest-bright in the canonical token system. --accent is the distinct sage token (#8a9a5b per globals.css and the PR objective to keep it separate from the forest family). Either:
- Replace the dot color with
#8a9a5band keep the--accentlabel, or - Correct the label to
--forest-bright · hover/bright.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/changes-tour.html` around lines 64 - 66, The legend entry for the accent
token is mismatched in the changes tour markup: the swatch in the changes-tour
legend is using the forest-bright hex while still labeling it as --accent.
Update the legend item in the changes-tour HTML so the dot color and label match
the canonical token system, either by changing the swatch to the sage accent
value or by renaming the label to --forest-bright, and verify the surrounding
legend entries remain consistent with the token names used elsewhere.
| ## 2. Greens — 5 active, two pairs indistinguishable | ||
| 12 greens exist (8 tokens + 4 hard-coded); **5 are in active semantic use**: | ||
| | Green | Token | Uses | Role | Problem | | ||
| |---|---|---|---|---| | ||
| | `#1B6C42` | `--brand-forest` | 45 | primary brand / action / rarity-uncommon | — | | ||
| | `#8a9a5b` | `--accent` (sage) | **125** | UI accents, reactions, focus, "Upload syllabus" btn | **the most-used "green" is sage, not the brand forest** — this is the main "greens feel inconsistent" culprit | | ||
| | `#3e8030` | `--c-sage` = `--grade-a` | 4 | grade-A display | **9 hex points from forest** — indistinguishable; on gradebook it reads as the brand green | | ||
| | `#4a7d5c` | `--state-mastery` | 3 | dashboard mastery | barely used; a 4th near-forest green | | ||
| | `#1a5c2a` | *(hard-coded, no token)* | 12 | landing logo, TopNav | **not in the token system** — brand drift risk | | ||
| **The core issue:** "a green affordance" renders as forest in one place, sage in another, grade-green in a third — because the greens are split by *accidental history*, not by *role*. The 125-use sage `--accent` makes the app's de-facto "main green" a muted yellow-green that clashes with the forest brand. | ||
| **Proposed green-by-role collapse (3 roles):** | ||
| 1. **Brand / primary action** → `--brand-forest` (one green for all primary buttons, active nav, brand marks). Tokenize the hard-coded `#1a5c2a` into it. | ||
| 2. **Positive status** (mastery, grade-A, success) → **one** status-green. Merge `--grade-a`/`--c-sage` and `--state-mastery` into a single `--positive` (distinct enough from forest to read as "status", or just = forest if we want them unified). | ||
| 3. **Decorative accent** → decide sage's fate: either keep `--accent` sage as a deliberately *different* hue (not green-family) so it stops competing with forest, or retire it toward forest. Recommend: **shift accent off the green family** (it's currently a near-green that muddies everything) OR rename it so its role is explicit. | ||
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update stale --accent token description.
The audit describes --accent as sage #8a9a5b, but globals.css already defines --accent: var(--brand-forest-bright) (#2D8F5C) with the comment "sage retired → brighter forest." This document appears to capture pre-Phase 1 state while being added in the Phase 1 changeset. Either update to current values or mark explicitly as historical/pre-unification baseline.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/frontend-component-consistency-audit.md` around lines 35 - 53, The
`--accent` description in this audit is stale and still reflects the old sage
value, while the current token is already defined as the brighter forest variant
in `globals.css`. Update the `--accent` entry in this document to match the
current token definition and comment, or explicitly label the section as
historical/pre-unification baseline so it does not conflict with the live design
system state. Use the `--accent` token and the `globals.css` definition as the
reference points when revising the wording.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Nav 'Get Started': keep the lg 14px label but reduce the box padding (per-button override, leaves the shared .btn--lg used elsewhere alone). - Hero 'Sign up for Beta Testing': lg -> xl so it grows in both text (16px) and box, making it the dominant hero CTA. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…overview Fills gaps in the NEXT_PUBLIC_LOCAL_MODE fixtures (frontend/src/lib/localData.ts) so the "Local Dev" account renders real data for UI testing: - gradebook per-course detail (weighted categories, graded + ungraded assignments, drop-lowest) for c1/c2/c3, consistent with the /summary cards - room "CS Study Group" overview: 3 members with knowledge graphs + AI summary, plus chat messages, activity feed, and a populated directory - interactive stubs (send/react/edit/delete/leave/kick/match) + gradescope status stub so the tabs don't warn/error Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Jose-Gael-Cruz-Lopez
left a comment
There was a problem hiding this comment.
Review of the token-unification refactor. Both code fixes below are already pushed in #297 (a stacked PR into this branch).
1. (Major) Toggle overflow regression — see inline comment on Toggle.tsx.
2. (Minor) Pill bare <button> — Pill.tsx (not in this PR's diff, so commenting here): it renders <button onClick> with no type (defaults to submit, so a Pill inside any <form> submits it) and no pressed state for assistive tech. #297 adds type="button" + aria-pressed={active}.
On CodeRabbit's --accent comments (not bugs):globals.css defines --accent: var(--brand-forest-bright) (#2D8F5C), so the changes-tour.html legend is correct and the audit doc is intentionally describing the pre-change state. No change needed.
Heads-up: the Canopy Engineering Style Guide still documents --accent:#8a9a5b (sage) in its token block + palette table — it'll be stale once this merges. I've proposed the update in Canopy.
| return ( | ||
| <div | ||
| style={{ | ||
| display: "inline-flex", |
There was a problem hiding this comment.
Major — overflow regression on dynamic lists. This container is inline-flex with no flex-wrap. On main, SemesterChips (the one caller passing an unbounded semesters list) rendered an explicit display:flex; flex-wrap:wrap tablist — so as semesters accumulate each term (and #280 ingests more BU terms), this now overflows horizontally instead of wrapping on Gradebook + course-planner.
Fixed in #297: an opt-in wrap prop (default off, so fixed-set segmented controls like 2D/3D and teaching modes are unaffected) that SemesterChips sets.
Addresses CodeRabbit review on #286: - Toggle: flexWrap so SemesterChips' dynamic list wraps instead of overflowing horizontally (no effect on fixed-option callers). - Pill: type="button" (stops enclosing-form submit) and aria-pressed to expose active state to assistive tech. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/src/lib/localData.ts (1)
206-260: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
drop_lowestconfigured but never exercised in mock data.
c1-hwandc3-hwboth setdrop_lowest: 1, but theircategory_gradevalues equal the plain average of all graded assignments in the category (e.g. c1-hw:(89+84)/2 = 86.5matchescategory_grade: 0.865; c3-hw:(93+88)/2 = 90.5matches0.905), anddropped_assignment_idsis[]for every course. So the drop is never reflected in either the computed grade or the badge list, meaning the "dropped assignment" UI state — which this new mock data set out to make testable — is never actually exercised.💡 Suggested fix
assignments: [ gA('gb-c1-1', 'c1', 'c1-hw', 'Problem Set 5 — Series', 'homework', 100, 89, -18), gA('gb-c1-2', 'c1', 'c1-hw', 'Problem Set 6 — Convergence', 'homework', 100, 84, -9), ... ], - dropped_assignment_ids: [],+ dropped_assignment_ids: ['gb-c1-2'],Adjust
category_gradeaccordingly (e.g. to reflect only the non-dropped assignment) if the UI trusts the numeric field independently of the badge list.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/lib/localData.ts` around lines 206 - 260, The mock courses in localData.ts define drop_lowest on c1-hw and c3-hw but never actually simulate a dropped item. Update the seeded data so the affected categories’ category_grade values reflect the dropped-lowest behavior, and populate dropped_assignment_ids with the assignment id(s) that should be dropped. Keep the changes aligned in the course objects for c1 and c3 so the grade display and dropped-assignment badges exercise the same state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@frontend/src/lib/localData.ts`:
- Around line 206-260: The mock courses in localData.ts define drop_lowest on
c1-hw and c3-hw but never actually simulate a dropped item. Update the seeded
data so the affected categories’ category_grade values reflect the
dropped-lowest behavior, and populate dropped_assignment_ids with the assignment
id(s) that should be dropped. Keep the changes aligned in the course objects for
c1 and c3 so the grade display and dropped-assignment badges exercise the same
state.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 29bc1902-2f52-48db-9e6f-2a6e7c74578c
📒 Files selected for processing (3)
frontend/src/components/Pill.tsxfrontend/src/components/ui/Toggle.tsxfrontend/src/lib/localData.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/components/ui/Toggle.tsx
Frontend token unification — Phase 1 (the foundation)
Collapses the two parallel CSS design systems in
globals.cssinto one. Previously the pre-auth surface re-declared core semantic tokens (--border,--text*,--shadow-*,--dur-*) inside.landing-pagewith cooler/faster values, so the same class name rendered differently on either side of sign-in — the root cause of "the get-started/beta flow feels like a different product." This was documented tech debt (globals.css:726: "to be revisited and consolidated… in a follow-up pass").What changed
:rootis the single source of truth and is unchanged. The pre-auth surface no longer shadows any core token.--display-hero,--surface-hero,--brand-glow,--bg-mesh) scoped via a new.public-surfaceroute-group layout — never redefines a:roottoken.--brand-primary #2e7d52,--brand-success,--brand-teal, …) down to--brand-forest(+ bright + derived glow).--accentsage stays as a distinct role.(public)route group. Landing + about/careers/privacy/terms moved underapp/(public)/— URLs unchanged (route groups are URL-transparent); mirrors the(shell)group.Verification
npm run build; route manifest confirms all public URLs unchanged./dashboardand the app shell are provably unchanged — no:rootcore token value or(shell)file was touched. The only app-reachable delta is--rarity-uncommon→--brand-forest(intended green collapse)./about,/careers— warm + intact.Scope & deferred work
This PR is the token layer only. Component shape/motion re-skins (beta pill + infinite glow, hero-card de-dup, onboarding/pending re-home, motion normalization, dead-code deletion) and the
components/directory flattening are intentionally deferred and filed as follow-up issues. Seedocs/superpowers/followups/2026-06-30-token-unification-followups.md.Docs
docs/frontend-rhythm-audit.md(+.html)docs/superpowers/specs/2026-06-30-token-unification-design.mddocs/superpowers/plans/2026-06-30-token-unification.md🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes / Improvements
Documentation