Skip to content

DebateOwl visual restyle: tokens, fonts, tactile buttons and the owl - #228

Merged
Programcode merged 35 commits into
mainfrom
design/debateowl-restyle
Oct 26, 2026
Merged

Programcode merged 35 commits into
mainfrom
design/debateowl-restyle

Conversation

@Programcode

@Programcode Programcode commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

What this is

The DebateOwl visual restyle of DebateLab, built from ~/debateowl-design (decisions.md, the design system, tokens and the style guide). It changes how the app looks and moves. Every feature, route, label and string stays. The only copy change is that 31 button labels move from Title Case to sentence case, with the same words. The product is still called DebateLab everywhere; the rename is a separate PR.

This is a draft. Nothing is merged or deployed, and nothing touched production Supabase.

Screenshots

Before on top, after underneath. Each row shows desktop light, desktop dark, phone light and phone dark (1440px and 390px). The images live on the restyle-screenshots branch (delete it after this PR closes). The full set, 24 screens at both widths in both themes before and after, is in restyle-screenshots/ in the worktree.

Landing

Landing: before and after

Home

Home: before and after

Generate, with a result

Generate, with a result: before and after

Ask, with an answer

Ask, with an answer: before and after

Sparring setup

Sparring setup: before and after

Sparring round

Sparring round: before and after

Start-debate dialog

Start-debate dialog: before and after

Library

Library: before and after

More: 02-login, 52-settings, 53-timer, 05-not-found.

What changed

Tokens and type

  • The DebateOwl tokens (plume blue, beak gold, mint, coral, blue-tinted ink) are in src/styles/tokens.css, with dark values on .dark. The shadcn roles in src/index.css map onto them.
  • I checked contrast pair by pair. Every pair passes WCAG AA in both themes, including text on tints, muted text on grey fills, and the 3:1 non-text minimum for input borders.
  • The slate/blue/sky/cyan/emerald/green/red/rose/amber families the app names directly are redrawn in brand colours at matching lightness, so about 150 hardcoded classes land on brand without editing each one.
  • Headings and buttons use Fredoka, body text Nunito (600 and up), and timers JetBrains Mono. All three are self-hosted through Fontsource and replace Inter. The fallbacks are Arial scaled to each font's measured metrics, so the swap doesn't shift layout.
  • Light is the default theme. Dark and System stay in Settings and the header toggle, and both themes are redesigned.

Components

  • Buttons press like the style guide's. They have a solid ledge under the face that presses down in 70ms and springs back, a 1px hover lift, a 3px focus ring with a gold glow, a grey disabled face with no ledge, and bouncing "thinking" dots instead of spinners. A busy button keeps its colour.
  • Fields have 2px borders with a plume focus glow. Tabs are a segmented track. The switch carries a check in its thumb. Dialogs and sheets sit on a navy scrim and scale in with a little overshoot. Toasts have tinted icons.
  • Choice cards (Sparring side and pressure, Home utilities) are pressable tiles with a check badge.
  • Success is mint and always carries a check mark: verdict, subscription badges, the speech calculator, citations.

The owl

  • Poses (point, idea, skeptical, surprised, celebrating) are cut out of the mascot art as transparent WebP at 1x to 3x, with edge colour-to-alpha so there's no white halo on navy. Head-and-shoulders busts are the avatars. The traced head SVG is the logo, favicon and install icons.
  • It appears in:
    • the logo and startup screen;
    • every loading state: the tool-run panel's owl changes pose with the phase, idea while thinking and skeptical while checking sources;
    • empty states, the 404 and the error page;
    • the Ask coach avatar;
    • the Sparring opponent, perched on the round card and in the transcript.
  • Pose changes crossfade with a small spring (Framer Motion, already a dependency). Under reduced motion only the fade remains.

Motion

  • Everything new respects prefers-reduced-motion. A press still shows (the ledge goes flat) but nothing travels or scales. Route skeletons shimmer and only appear after 300ms, so fast loads don't flash.

Things to know

  • Signed-out pages are now always light. Before, a signed-out visitor followed the OS setting. Public pages have no theme toggle, so "light by default" means a dark-OS visitor sees a light landing page. Signed-in users keep their own choice everywhere. The dark screenshots of public pages show what a signed-in dark user sees.
  • The owl appears in two places beyond the brief's list. It points at the product preview in the landing hero, and it sits on the Sparring verdict, celebrating a win or holding up one point otherwise. Both are easy to drop.
  • No streak exists in the app, so no feather icon ships.
  • Empty-state actions are now primary buttons (they were outline). Sparring's Start round is the screen's one gold button.
  • Poses are WebP, not PNG (transparent, 1x to 3x, 8 to 47KB each). The app and favicon icons are PNG.
  • Install icons are larger. icon-512.png went from 29KB to 166KB and the maskable one to 120KB, both precached at install, because no PNG optimiser was available here. Run them through one before release.
  • The static guide pages (/debatelab-pricing and the others) keep their dark layout but move from violet and cyan to navy, plume and gold.
  • The OG image is unchanged. hero-visual.jpg still shows the old UI.

Verification

Ran:

  • npm run verify:full at 5afdcf0f. Every step passes except three e2e specs, which fail the same way on unchanged origin/main (I checked out origin/main in a temporary worktree and ran them):

    • loading-performance.spec.ts:63, where locator('header') matches both the app header and the page header;
    • navigation-performance.spec.ts:344, which counts subscription reads;
    • search-quality.spec.ts:7, which expects a "Researched sources" heading where the app renders a <summary>.

    Across desktop and mobile, 282 passed, 6 failed (those three, once per viewport) and 5 skipped. home-navigation.spec.ts:90 was flaky once under load and passed 3/3 in isolation.

  • The rest of verify:full: unit tests 651/651, collaboration 30/30, Edge Functions 470/470, build and site checks, the offline service-worker check, smoke e2e 47/47.

  • npm run verify (the credential-free ladder with smoke e2e) at the head, c9cf5ddf, passes. The two commits after 5afdcf0f change only the verify-debatelab recipes and two CSS details: bold text in rendered answers moves to 800, and the toast close button is themed.

  • verify-debatelab drive all (fake mode, desktop and mobile Chromium) on the local stack: 133 passed, 4 skipped, 9 failed. Eight of the failures were the ask-bubble and billing-state recipes, which assumed a new account follows the OS colour scheme; they now switch the account to System first (followSystemTheme) and pass on both viewports (ask-bubble 2/2, billing-states 14/14), including ask-bubble's AA contrast check in light and dark. The ninth, gen-export, timed out waiting for a download under load and passed 2/2 on rerun.

  • By hand: every screen at 390 and 1440 in light and dark, the dialogs, popovers, selects and onboarding tour, a full Sparring round to the verdict, Ask with a streamed answer, and Generate running and done. Hungarian at 390px shows no clipping.

Not run:

  • the agentic suite (it needs model calls; I updated the recorded flows' button names by hand rather than re-recording);
  • live-mode recipes;
  • WebKit;
  • staging;
  • anything involving Stripe, ElevenLabs or Google.
  • GitHub Actions on this PR. I opened it and stopped, so I have not checked CI.

🤖 Generated with Claude Code

Programcode and others added 14 commits October 24, 2026 13:36
Ports the DebateOwl design tokens (plume blue, beak gold, mint success,
coral, ink) into src/styles/tokens.css with dark values on .dark, and maps
the shadcn roles onto them at AA contrast in both themes. Fredoka (headings,
buttons) and Nunito (body) are self-hosted through Fontsource with
metric-matched Arial fallbacks, replacing Inter. The palette families the
app names directly are redrawn in brand colours. The theme defaults to
light; System and Dark stay one tap away.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Transparent WebP cutouts of the owl's poses (point, idea, skeptical,
surprised, celebrating) at 1x to 3x plus head-and-shoulders busts, cut from
the mascot art with edge colour-to-alpha so they sit cleanly on navy. The
traced head SVG becomes the app mark, favicon and install icons. Owl,
OwlAvatar and OwlMark crossfade between poses and respect reduced motion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tactile buttons with a pressable ledge, hover lift, 3px focus ring with a
gold glow, disabled and loading states; 2px fields with a plume focus glow;
segmented tabs; switch with a check in the thumb; navy-scrim dialogs and
sheets; toasts with tinted icons; owl empty states and loaders; owl mark in
every header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thirty English button labels and the flow sheet's print button (in all
three languages) move from Title Case to sentence case, as the DebateOwl
style asks. The words are unchanged. Tests, e2e specs, verify-debatelab
recipes and feature notes, docs and the recorded agentic flows that name
these buttons follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every bare spinner is gone: buttons show the bouncing thinking dots, and
page and section waits show the owl. The tool-run panel's owl changes pose
with the phase (an idea while thinking, skeptical while checking sources).
The Ask coach and the Sparring opponent are the owl, with the opponent
perched on the round card and pose changes between thinking and speaking.
Sparring's side and pressure pickers become pressable tiles with a check
badge, and Start round is the screen's one gold button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The landing CTAs become tactile ledge buttons, the teal gradients become
the owl's plume and gold glows, section headings and prices move to
Fredoka, and the owl points visitors at the product preview. Home's tool
rows get pressable icon tiles; the utility links become tiles. Library's
empty and no-match states show the owl, and route skeletons shimmer after
300ms instead of flashing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 404 and the route error boundary show the surprised owl and tactile
buttons. The free tools' call to action is a real button again (prose link
colours had painted its label blue on blue). Generate, Attack, Brainstorm
and Factoids submit buttons stay blue with thinking dots while they run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The verdict shows the owl celebrating a win (or holding up one point to
work on), a mint Winner badge with a check, and Fredoka score tiles; a loss
reads in the plume tint, never red. The tour tooltip, its buttons and its
scrim follow the new tokens, and History's tab track keeps its shape when
it wraps on a phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every mint success state carries a check (subscription badges, the speech
calculator's fitting slots, the verdict), success and amber text move to
their AA-strength steps, and the scorecard transcript shows the owl
opponent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Speaking clocks use tabular JetBrains Mono figures, as the style guide's
timer does. The offline service-worker check now expects the header logo to
be the precached owl mark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…coloured

Entrance animations added by the restyle only play with motion allowed,
so reduced motion shows them still (the Sparring setup check expects no
animation at all). The owl poses that offline pages show are precached
with the shell. The static guide pages move from violet and cyan to the
navy, plume and gold palette, in the stylesheet and its generator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New accounts start light now, so the ask-bubble and billing-state recipes
pick System in Settings (followSystemTheme) before emulating each colour
scheme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 166 files, which is 16 over the limit of 150.

To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 12eaab1 and e5c6efc.

Files ignored due to path filters: 73
  • docs/screenshots/menu-layout/after-ask-empty-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-error-en-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-error-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-filled-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-filled-es-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-filled-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-filled-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-loading-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-options-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-options-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-ask-sidebar-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-empty-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-error-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-filled-en-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-filled-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-filled-es-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-filled-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-filled-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-loading-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-regenerating-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-saved-en-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-saved-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-saved-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-gen-saved-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-share-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/after-share-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-empty-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-error-en-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-error-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-filled-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-filled-es-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-filled-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-filled-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-loading-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-options-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-options-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-ask-sidebar-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-empty-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-error-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-filled-en-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-filled-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-filled-es-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-filled-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-filled-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-loading-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-regenerating-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-saved-en-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-saved-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-saved-hu-dark.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-gen-saved-hu-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-share-en-light.jpg is excluded by !**/*.jpg
  • docs/screenshots/menu-layout/before-share-hu-dark.jpg is excluded by !**/*.jpg
  • package-lock.json is excluded by !**/package-lock.json
  • public/apple-touch-icon.png is excluded by !**/*.png
  • public/favicon-72.png is excluded by !**/*.png
  • public/favicon.ico is excluded by !**/*.ico
  • public/favicon.png is excluded by !**/*.png
  • public/icon-1024.png is excluded by !**/*.png
  • public/icon-192.png is excluded by !**/*.png
  • public/icon-512.png is excluded by !**/*.png
  • public/icon-maskable-512.png is excluded by !**/*.png
  • public/owl-mark.svg is excluded by !**/*.svg
  • src/assets/owl/owl-arguing.svg is excluded by !**/*.svg
  • src/assets/owl/owl-celebrating.svg is excluded by !**/*.svg
  • src/assets/owl/owl-coach.svg is excluded by !**/*.svg
  • src/assets/owl/owl-idea.svg is excluded by !**/*.svg
  • src/assets/owl/owl-point.svg is excluded by !**/*.svg
  • src/assets/owl/owl-reading.svg is excluded by !**/*.svg
  • src/assets/owl/owl-skeptical.svg is excluded by !**/*.svg
  • src/assets/owl/owl-sleepy.svg is excluded by !**/*.svg
  • src/assets/owl/owl-surprised.svg is excluded by !**/*.svg
  • src/assets/owl/owl-thinking.svg is excluded by !**/*.svg
  • src/assets/owl/owl-timekeeper.svg is excluded by !**/*.svg
Files selected for processing: 166
  • .claude/skills/verify-debatelab/SKILL.md
  • .claude/skills/verify-debatelab/features/README.md
  • .claude/skills/verify-debatelab/features/account-data.md
  • .claude/skills/verify-debatelab/features/ai-tools.md
  • .claude/skills/verify-debatelab/features/auth-demo-login.md
  • .claude/skills/verify-debatelab/features/case-generation.md
  • .claude/skills/verify-debatelab/features/current-debate.md
  • .claude/skills/verify-debatelab/features/library-sources.md
  • .claude/skills/verify-debatelab/features/live-generation.md
  • .claude/skills/verify-debatelab/recipes/account-data.spec.ts
  • .claude/skills/verify-debatelab/recipes/account.spec.ts
  • .claude/skills/verify-debatelab/recipes/ai-tools.spec.ts
  • .claude/skills/verify-debatelab/recipes/billing-states.spec.ts
  • .claude/skills/verify-debatelab/recipes/billing.spec.ts
  • .claude/skills/verify-debatelab/recipes/case-generation.spec.ts
  • .claude/skills/verify-debatelab/recipes/current-debate.spec.ts
  • .claude/skills/verify-debatelab/recipes/fixtures.ts
  • .claude/skills/verify-debatelab/recipes/library.spec.ts
  • .claude/skills/verify-debatelab/recipes/live-generation.spec.ts
  • .claude/skills/verify-debatelab/recipes/model-defaults.spec.ts
  • .claude/skills/verify-debatelab/recipes/usage-limits.spec.ts
  • agentic/replay/126b78cf76461974e31c525473531fea764059779def23ffec087cecc00a0950.json
  • agentic/replay/23755b48030e2ba88ae7593c0e65506ecd8b0b7d98a4006cfda221eda5edb068.json
  • agentic/replay/729490fb7619dcddf35c0c60cedc58d2bc05aff8f07aad051c9ef2cd457f9799.json
  • agentic/replay/a7ab22475ff220f06530d1b208935a31518cb6002dad033bbe5549c162f9df6e.json
  • agentic/replay/c6cf102fb2172d14552e85bf19abb2d80a6075794717cc7c0c2cd0610bb9fe37.json
  • agentic/replay/cec2ee4bacb9750f2fa98e3124caf500077ddc18df231c58d9c29724467af6ac.json
  • agentic/replay/d837eeb2b0665a23180f65fb205e2ea67f8b44f1a1a6a400067d474f1b21cb5f.json
  • agentic/replay/e0c912b52a6de1dadb5287bb54346d1fac813a9d7ac70a1742898dc3abdf4a99.json
  • agentic/replay/e753f1e71c4d4ed90310f668e44ebdc847f876ca5ec6d2ade3d672c29aedcaf9.json
  • agentic/replay/f6d6a30f85648dfe2446aa2888ca7fba9df68b2746461d556a193ac4ed89d357.json
  • docs/architecture.md
  • docs/operations.md
  • docs/standards/async-and-state.md
  • docs/testing.md
  • e2e/animation-polish.spec.ts
  • e2e/first-run.spec.ts
  • e2e/full-stack/account-data.spec.ts
  • e2e/full-stack/account-deletion.spec.ts
  • e2e/full-stack/ai-tools.spec.ts
  • e2e/full-stack/auth.spec.ts
  • e2e/full-stack/billing.spec.ts
  • e2e/full-stack/case-generation.spec.ts
  • e2e/full-stack/current-debate.spec.ts
  • e2e/full-stack/debate-context.spec.ts
  • e2e/full-stack/first-run.spec.ts
  • e2e/live/models.spec.ts
  • e2e/live/research.spec.ts
  • e2e/loading-performance.spec.ts
  • e2e/model-matrix/generate.spec.ts
  • e2e/production/canary.spec.ts
  • e2e/results-overflow.spec.ts
  • e2e/staging/authed-flows.spec.ts
  • index.html
  • package.json
  • public/manifest.webmanifest
  • public/seo-pages.css
  • public/sw.js
  • public/theme-init.js
  • scripts/generate_seo_content.py
  • scripts/test-service-worker-offline.mjs
  • src/App.tsx
  • src/components/LanguageSwitcher.tsx
  • src/components/OfflineIndicator.tsx
  • src/components/ThemeProvider.tsx
  • src/components/ThemeToggle.tsx
  • src/components/admin/AdminAnnouncements.tsx
  • src/components/auth/RequireAuth.tsx
  • src/components/brand/Owl.tsx
  • src/components/features/ExportToolbar.tsx
  • src/components/features/ask/AskChat.tsx
  • src/components/features/attack/AttackForm.tsx
  • src/components/features/attack/AttackResults.tsx
  • src/components/features/brainstorm/BrainstormForm.tsx
  • src/components/features/brainstorm/BrainstormResults.tsx
  • src/components/features/debate/CurrentDebateMenu.tsx
  • src/components/features/debate/DebateDialogs.tsx
  • src/components/features/debate/DebateForm.tsx
  • src/components/features/debate/DebateMotionGate.tsx
  • src/components/features/debate/UnsortedWork.tsx
  • src/components/features/export/GoogleDriveAuthModal.tsx
  • src/components/features/factoids/FactoidsForm.tsx
  • src/components/features/factoids/FactoidsResults.tsx
  • src/components/features/generate/GenerateForm.tsx
  • src/components/features/generate/GenerateResults.tsx
  • src/components/features/onboarding/DebateOwlIntro.tsx
  • src/components/features/onboarding/OnboardingTour.tsx
  • src/components/features/practice/RoundClock.tsx
  • src/components/features/sparring/SparringRound.tsx
  • src/components/features/sparring/SparringScorecard.tsx
  • src/components/features/sparring/SparringSetup.tsx
  • src/components/features/subscription/PricingModal.tsx
  • src/components/features/subscription/SubscriptionStatus.tsx
  • src/components/features/tools/live-draft.tsx
  • src/components/features/tools/tool-links.tsx
  • src/components/features/tools/tool-run.tsx
  • src/components/features/voice/OpponentVoiceBar.tsx
  • src/components/free-tools/DebateTimer.tsx
  • src/components/free-tools/SpeechTimeCalculator.tsx
  • src/components/free-tools/ToolPageLayout.tsx
  • src/components/landing/DeepDive.tsx
  • src/components/landing/Features.tsx
  • src/components/landing/FinalCTA.tsx
  • src/components/landing/Footer.tsx
  • src/components/landing/Hero.tsx
  • src/components/landing/HowItWorks.tsx
  • src/components/landing/Navbar.tsx
  • src/components/landing/Pricing.tsx
  • src/components/landing/UseCases.tsx
  • src/components/landing/WhatsNew.tsx
  • src/components/layout/AppLayout.tsx
  • src/components/layout/PageHeader.tsx
  • src/components/layout/PublicPageShell.tsx
  • src/components/ui/alert-dialog.tsx
  • src/components/ui/alert.tsx
  • src/components/ui/badge.tsx
  • src/components/ui/button.tsx
  • src/components/ui/card.tsx
  • src/components/ui/checkbox.tsx
  • src/components/ui/dialog.tsx
  • src/components/ui/empty-state.tsx
  • src/components/ui/input.tsx
  • src/components/ui/label.tsx
  • src/components/ui/loading-spinner.tsx
  • src/components/ui/popover.tsx
  • src/components/ui/progress.tsx
  • src/components/ui/select.tsx
  • src/components/ui/sheet.tsx
  • src/components/ui/slider.tsx
  • src/components/ui/sonner.tsx
  • src/components/ui/switch.tsx
  • src/components/ui/tabs.tsx
  • src/components/ui/textarea.tsx
  • src/components/ui/tooltip.tsx
  • src/embed/debate-timer.tsx
  • src/hooks/use-toast.ts
  • src/index.css
  • src/lib/debateowl-intro.ts
  • src/lib/stores/settings-store.ts
  • src/locales/en.json
  • src/locales/es.json
  • src/locales/hu.json
  • src/locales/tools/en.json
  • src/locales/tools/es.json
  • src/locales/tools/hu.json
  • src/main.tsx
  • src/pages/AdminPage.tsx
  • src/pages/AuthCallbackPage.tsx
  • src/pages/CrossfirePage.tsx
  • src/pages/GeneratePage.tsx
  • src/pages/HistoryPage.tsx
  • src/pages/HomePage.tsx
  • src/pages/LibraryPage.tsx
  • src/pages/LoginPage.tsx
  • src/pages/NotFound.tsx
  • src/pages/SettingsPage.tsx
  • src/pages/SharedPage.tsx
  • src/pages/TimerPage.tsx
  • src/styles/tokens.css
  • src/test/a11y/names-and-headings.test.tsx
  • src/test/billing/pricing-modal-redirect.test.tsx
  • src/test/components/EnvironmentSwitcher.test.tsx
  • src/test/components/SubscriptionStatus.test.tsx
  • src/test/generate/generate-form-role.test.tsx
  • src/test/onboarding/debateowl-intro.test.tsx
  • vite.config.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing.

Comment @coderabbitai help to get the list of available commands.

Programcode and others added 4 commits October 24, 2026 15:43
…themed

Rendered answers set strong text and minor headings at 800, since the
typography plugin's 600 now equals the body weight. Sonner's close button
takes the card colours instead of its own black circle in dark mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captured on design/debateowl-restyle at c9cf5dd with the local verify
stack (fake provider), 10 viewports from 375 px phones to 1920 px desktop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ask: Options sits at the end of the General/Clarify row instead of a row of
its own, so one row of controls stays above the message box. On a phone it
shows its icon (the label stays its accessible name), because the Hungarian
label does not fit beside both modes.

Generate: the top row reads Save, Undo, then Discuss, Flowcharts and Open in
Crossfire. On a phone both rows stretch into even pairs and the Export tag
takes its own line. ExportToolbar gets an opt-in evenRows for this, so
Attack, Brainstorm and Factoids are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same 10 viewports and states as the before set, captured on the local
verify stack (fake provider).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Programcode and others added 4 commits October 24, 2026 13:55
Ask Options join the mode row; Generate actions in purpose order
From 640px up, a Generate toolbar row that fits on one line stays one
natural, left-aligned line. A row that has to wrap is cut into lines whose
button counts differ by at most one (3+2, not 4+1), and each line's buttons
grow in proportion to their labels until the line is full. The Export tag
keeps its own width at the start of its line. Phones keep the even pairs
from #229.

The split is measured, because where a row breaks depends on the language
and on whether Save or "Saved to History" is showing. It stays behind the
opt-in evenRows prop, so Attack, Brainstorm and Factoids are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The five existing poses come from the c-trace set and six new ones are
hand-traced in the same style: thinking, reading, timekeeper, arguing,
coach and sleepy. Each file is 13 to 21 kB and replaces the 26 glossy
WebP cutouts. The avatar crops the full pose with CSS instead of
shipping separate bust files. The offline precache picks up the poses
that the offline pages show.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Home points at Start debate. Generate thinks while it writes and looks
surprised when the run fails. History's empty states sleep, the Library
reads, and the Debate Timer title holds a stopwatch. The Sparring
opponent argues, and the Ask coach gives a thumbs-up. Case Saved
celebrates beside its check. The 404 and the won ballot already had the
right pose.

Owls beside text stay decorative. The coach and opponent avatars get alt
text in English, Hungarian and Spanish. No other copy changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Programcode

Copy link
Copy Markdown
Owner Author

The owls at intensity B are in draft #232, which stacks on this branch. It adds the logo plus one owl on each key screen, and every owl is now an SVG, including six newly traced poses. Before on top, after below, light on the left and dark on the right.

Every pose

Every pose on light and dark

Home

Home at 1440: before and after

History, empty (375 px)

History empty at 375: before and after

Sparring opponent

Sparring opponent at 1440: before and after

All placements at five widths, plus the test results, are in #232.

Programcode and others added 4 commits October 24, 2026 18:59
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DebateOwl owls at intensity B: the logo plus one owl per key screen
Twelve viewports per image: phones, iPad portrait and landscape including
820x1180 and 1180x820, and desktop. EN, HU and ES, light and dark, the
saved state, and the shared case page. Before is aa92de4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-rows

Generate toolbar: balanced rows at tablet and desktop widths
Programcode and others added 8 commits October 26, 2026 20:27
The owl says hello and introduces DebateOwl as the new look of
DebateLab. Two more steps follow: what changed (the look, the owl
guide, everything still where it was) and the slow move to the
DebateOwl name. The hello takes about 3 seconds. Under reduced
motion it shows its last frame and starts no timers.

It opens once per browser inside the signed-in app, after the
layout loads, and runs before the onboarding tour. Closing it any
way (Skip, Got it, Esc, the X, the backdrop) writes
debateowl_intro_seen_v1 to localStorage. There is no profile column
for UI flags, so localStorage is the only store, as with the tour.

Playwright (VITE_E2E) and the verify stack (VITE_LOCAL_PREVIEW)
never open it. ?intro=show forces it and ?intro=skip suppresses it.
The production canary seeds the flag. The owl's personal name is the
empty owlName key; while it stays empty the owl says "Hi there!".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	public/seo-pages.css
#	scripts/generate_seo_content.py
#	src/components/free-tools/ToolPageLayout.tsx
#	src/locales/en.json
The owl's introduction and the rename notice now share one dialog, so
nobody sees two popups. Over about 6.6 seconds the owl says its lines
into a speech bubble, one beat per pose: it introduces itself as
DebateOwl, says DebateLab has a new look, bobs over thinking dots as it
promises company while things load, and gives a thumbs-up beside the
mint check for the same tools as before. The notice ("DebateLab is
slowly becoming DebateOwl") sits under the bubble from the start.

Got it is the one way out; Esc and the backdrop still close it and
mark it seen. Skip animation jumps to the last frame without closing.
Reduced motion shows that frame at once.

The owl's name moves to OWL_NAME in src/lib/debateowl-intro.ts, a
constant rather than a locale key, since it is the same in every
language. While it is empty the owl calls itself DebateOwl.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No name has been chosen, so the owl introduces itself as DebateOwl in
every language and OWL_NAME stays empty. The test for a set name uses
an obvious placeholder instead of a made-up name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OWL_NAME is now "Ollie", still the one place the name lives. The owl
introduces itself as "Hi, I'm Ollie, the DebateOwl owl!", in Spanish
"¡Hola, soy Ollie, el búho de DebateOwl!" and in Hungarian "Szia, Ollie
vagyok, a DebateOwl baglya!". The product name stays DebateOwl.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test:sw drives a production build, where the one-time DebateOwl
welcome opens and covered the Tools page the test clicks. It now seeds
debateowl_intro_seen_v1 next to the tour flag, as the canary does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At 390 px the greeting left "owl!" alone on its second line. It now
balances across both lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One-time DebateOwl welcome with Ollie and the rename notice
@Programcode
Programcode marked this pull request as ready for review October 26, 2026 21:08
Copilot AI balanced review requested due to automatic review settings October 26, 2026 21:08
@Programcode
Programcode merged commit bbe42d9 into main Oct 26, 2026
3 of 13 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants