diff --git a/.beans.yml b/.beans.yml
deleted file mode 100644
index 3affd93ba..000000000
--- a/.beans.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-beans:
- path: .beans
- prefix: sendou.ink-
- id_length: 4
- default_status: todo
- default_type: task
diff --git a/.beans/image-1.png b/.beans/image-1.png
deleted file mode 100644
index e4278c6c2..000000000
Binary files a/.beans/image-1.png and /dev/null differ
diff --git a/.beans/image.png b/.beans/image.png
deleted file mode 100644
index 6dec97abf..000000000
Binary files a/.beans/image.png and /dev/null differ
diff --git a/.beans/sendou.ink-0izp--rename-commandpalette-to-globalsearch.md b/.beans/sendou.ink-0izp--rename-commandpalette-to-globalsearch.md
deleted file mode 100644
index 97296f562..000000000
--- a/.beans/sendou.ink-0izp--rename-commandpalette-to-globalsearch.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-# sendou.ink-0izp
-title: Rename CommandPalette to GlobalSearch
-status: todo
-type: task
-created_at: 2026-01-11T13:51:15Z
-updated_at: 2026-01-11T13:51:15Z
-parent: sendou.ink-6eko
----
-
-The CommandPalette component is used more as a global search feature than a command palette. Rename it to better reflect its purpose.
-
-## Checklist
-
-- [ ] Rename `CommandPalette.tsx` to `GlobalSearch.tsx`
-- [ ] Rename `CommandPalette.module.css` to `GlobalSearch.module.css`
-- [ ] Update all CSS class names from `commandPalette` to `globalSearch`
-- [ ] Update all imports and references across the codebase
-- [ ] Run checks to ensure nothing is broken
\ No newline at end of file
diff --git a/.beans/sendou.ink-0n0n--search-category-icons-not-shown-on-mobile.md b/.beans/sendou.ink-0n0n--search-category-icons-not-shown-on-mobile.md
deleted file mode 100644
index 1445e545c..000000000
--- a/.beans/sendou.ink-0n0n--search-category-icons-not-shown-on-mobile.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-# sendou.ink-0n0n
-title: Search category icons not shown on mobile
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T13:53:16Z
-updated_at: 2026-01-11T18:43:48Z
-parent: sendou.ink-6eko
----
-
-On narrow screens, the search/command palette category tabs (Users, Teams, Organizations, Tournaments) only show text labels without their icons. Icons should be visible on mobile to maintain visual consistency and improve scannability.
-
-## Details
-
-- The tabs currently show text-only on narrow screens
-- Icons help users quickly identify categories
-- Should match desktop behavior where icons are shown alongside text
-
-## Fix
-
-Added CSS in `CommandPalette.module.css`:
-
-1. Added `flex-shrink: 0` to `picture` and `img` elements inside `.searchTypeRadio` to prevent icons from being compressed/hidden on narrow screens
-2. Added `flex-wrap: wrap` to `.searchTypeRadioGroup` to allow tabs to wrap to a new line on very narrow screens instead of overflowing
\ No newline at end of file
diff --git a/.beans/sendou.ink-0n4h--add-any-tournament-to-my-events.md b/.beans/sendou.ink-0n4h--add-any-tournament-to-my-events.md
deleted file mode 100644
index 7ada93dec..000000000
--- a/.beans/sendou.ink-0n4h--add-any-tournament-to-my-events.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-0n4h
-title: Add any tournament to My Events
-status: draft
-type: feature
-created_at: 2026-01-11T12:55:45Z
-updated_at: 2026-01-11T12:55:45Z
-parent: sendou.ink-u4ag
----
-
-Allow users to add any tournament to their My Events page, not just tournaments they are organizing or have joined as a participant. This enables spectators to keep track of tournaments they want to follow or watch.
\ No newline at end of file
diff --git a/.beans/sendou.ink-0q9m--my-calendar-page-and-components.md b/.beans/sendou.ink-0q9m--my-calendar-page-and-components.md
deleted file mode 100644
index b2e73b957..000000000
--- a/.beans/sendou.ink-0q9m--my-calendar-page-and-components.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-# sendou.ink-0q9m
-title: My Events page and components
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-11T11:45:35Z
-updated_at: 2026-01-11T12:50:56Z
-parent: sendou.ink-om3i
----
-
-## Summary
-
-Build the `/my-events` page with list view and event card components.
-
-## Details
-
-**Page requirements:**
-- Route: `/my-events`
-- Login required (redirect if not authenticated)
-- List view grouped by day (chronological)
-- Empty state with links to /calendar and /scrims
-
-**Event card info:**
-- Name (tournament name or scrim opponent)
-- Time
-- Status
-- Check-in window (for tournaments)
-- Click navigates directly to tournament/scrim page
-
-**Component sharing:**
-- Build components that can be reused by sidebar Events section
-- Handle both tournament and scrim event types
-
-## Checklist
-
-- [ ] Add route to routes.ts
-- [ ] Create page component with loader
-- [ ] Create event list component (grouped by day)
-- [ ] Create event card component (handles tournament + scrim)
-- [ ] Implement empty state with links
-- [ ] Add translations
-- [ ] Style with CSS modules
\ No newline at end of file
diff --git a/.beans/sendou.ink-0sk2--remove-trusted-users-management-ui-from-settings.md b/.beans/sendou.ink-0sk2--remove-trusted-users-management-ui-from-settings.md
deleted file mode 100644
index 9a0e42228..000000000
--- a/.beans/sendou.ink-0sk2--remove-trusted-users-management-ui-from-settings.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-# sendou.ink-0sk2
-title: Remove trusted users management UI from settings
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-13T11:25:10Z
-updated_at: 2026-01-13T11:25:15Z
-parent: sendou.ink-255r
-blocking:
- - sendou.ink-kluy
----
-
-## Overview
-
-Delete the "Trusted Users" section from SendouQ settings page. This UI is replaced by the /friends page.
-
-## Files to Modify
-
-### app/features/sendouq-settings/routes/q.settings.tsx
-- Remove `` component usage (line ~86)
-- Delete `TrustedUsers` function component (lines ~611-680)
-
-### app/features/sendouq-settings/actions/q.settings.server.ts
-- Remove `REMOVE_TRUST` case from switch (lines ~44-49)
-
-### app/features/sendouq-settings/q-settings-schemas.server.ts
-- Remove `REMOVE_TRUST` schema from union (lines ~68-71)
-
-### app/features/sendouq-settings/loaders/q.settings.server.ts
-- Remove `trusted` from loader data
-
-### app/features/sendouq-settings/QSettingsRepository.server.ts
-- Remove `findTrustedUsersByGiverId` function
-- Remove `deleteTrustedUser` function
-- (Keep other functions until full trust deprecation)
-
-## i18n Keys to Remove
-
-From `q` namespace:
-- `q:settings.trusted.header`
-- `q:settings.trusted.confirm`
-- `q:settings.trusted.trustedExplanation`
-- `q:settings.trusted.noTrustedExplanation`
-- `q:settings.trusted.teamExplanation`
-
-## Checklist
-
-- [ ] Remove TrustedUsers component from q.settings.tsx
-- [ ] Remove REMOVE_TRUST action handler
-- [ ] Remove REMOVE_TRUST schema
-- [ ] Remove trusted from loader
-- [ ] Remove repository functions (findTrustedUsersByGiverId, deleteTrustedUser)
-- [ ] Remove i18n keys
-- [ ] Run `npm run i18n:sync`
-- [ ] Verify settings page still works
\ No newline at end of file
diff --git a/.beans/sendou.ink-0uyd--database-schema-for-friends-system.md b/.beans/sendou.ink-0uyd--database-schema-for-friends-system.md
deleted file mode 100644
index e5044d337..000000000
--- a/.beans/sendou.ink-0uyd--database-schema-for-friends-system.md
+++ /dev/null
@@ -1,55 +0,0 @@
----
-# sendou.ink-0uyd
-title: Database schema for friends system
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-13T09:31:56Z
-updated_at: 2026-01-14T19:14:51Z
-parent: sendou.ink-255r
-blocking:
- - sendou.ink-iulp
----
-
-## Overview
-
-Create database migrations for the friends system tables.
-
-## Tables to Create
-
-### Friendship
-```sql
-CREATE TABLE Friendship (
- id INTEGER PRIMARY KEY,
- userOneId INTEGER NOT NULL REFERENCES User(id),
- userTwoId INTEGER NOT NULL REFERENCES User(id),
- createdAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
- UNIQUE(userOneId, userTwoId)
-);
-CREATE INDEX idx_friendship_user_one ON Friendship(userOneId);
-CREATE INDEX idx_friendship_user_two ON Friendship(userTwoId);
-```
-Invariant: userOneId < userTwoId to prevent duplicate relationships.
-
-### FriendRequest
-```sql
-CREATE TABLE FriendRequest (
- id INTEGER PRIMARY KEY,
- senderId INTEGER NOT NULL REFERENCES User(id),
- receiverId INTEGER NOT NULL REFERENCES User(id),
- createdAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
- UNIQUE(senderId, receiverId)
-);
-CREATE INDEX idx_friend_request_receiver ON FriendRequest(receiverId);
-```
-
-### SendouQ group changes
-
-We also need to add support for invites in SQ without the user being in the queue. TBD what the table design looks like
-
-## Checklist
-
-- [x] Create migration file
-- [x] Add tables to `app/db/tables.ts`
-- [x] Run migration and verify schema
-- [x] Add to test database
diff --git a/.beans/sendou.ink-0ze4--weapons-pages.md b/.beans/sendou.ink-0ze4--weapons-pages.md
deleted file mode 100644
index c859f22fe..000000000
--- a/.beans/sendou.ink-0ze4--weapons-pages.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-# sendou.ink-0ze4
-title: Weapons pages
-status: draft
-type: epic
-created_at: 2026-01-11T12:10:47Z
-updated_at: 2026-01-11T12:10:47Z
----
-
-## Summary
-
-Individual weapon pages (`/weapons/`) with comprehensive weapon data, stats, and links to related content.
-
-## Data Source
-
-Parse weapon parameters from https://github.com/Leanny/splat3 into a format easy to use within sendou.ink.
-
-## Features
-
-### Parameter Comparison Table
-
-- **Rows** = parameters (raw keys from Leanny's data, supports translation that can be filled out over time)
-- **Columns** = weapons in same category (e.g., Jr page shows all shooters)
-- **Current weapon pinned** in the table for easy comparison
-- **Patch history inline**: each cell shows current value + indicator if changed, expandable to see full history (which patch + date)
-
-### Leaderboard & Popularity Stats
-
-- **Top XP holder** for the weapon (name + XP) with link to full leaderboard
-- **Popularity** (top 500 appearances) - shown both:
- - Overall across all weapons
- - Within the weapon's category
-- Data already exists in sendou.ink database
-
-### Rich Previews (5 items each)
-
-- **5 recent vods** of the weapon
-- **5 popular builds** for the weapon
-- **5 art pieces** tagged by the weapon
-
-### Simple Links
-
-- Free agents using this weapon
-- Build analyzer link
-- Object damage calculator link
-
-## Navigation
-
-- No landing page at `/weapons`
-- No category pages
-- Users access individual weapon pages directly via menu (weapon mega menu)
-
-## Technical Notes
-
-- Individual weapon pages already exist as placeholders (e.g., `/weapons/splattershot-jr`)
-- Leaderboard and popularity data already available in database
\ No newline at end of file
diff --git a/.beans/sendou.ink-10ai--implement-prestige-calculation.md b/.beans/sendou.ink-10ai--implement-prestige-calculation.md
deleted file mode 100644
index f00b43156..000000000
--- a/.beans/sendou.ink-10ai--implement-prestige-calculation.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-# sendou.ink-10ai
-title: Implement prestige calculation
-status: todo
-type: feature
-created_at: 2026-01-12T09:21:18Z
-updated_at: 2026-01-12T09:21:18Z
-parent: sendou.ink-ylq5
----
-
-Implement the tournament prestige calculation based on research findings.
-
-## Requirements
-
-- Calculate prestige from registered teams' seeding power
-- Available at registration time (not just after results)
-- Works for both upcoming and historical tournaments
-
-## Implementation Notes
-
-- Create function in /app/features/tournament/ or /app/features/mmr/
-- Query top N teams' avgSeedingSkillOrdinal
-- Apply formula from design task
-- Return prestige score/tier
-
-## Usage
-
-- Called by stream aggregation service for ranking
-- May be displayed on tournament pages (future)
-- May be stored for historical tracking (future)
-
-## Dependencies
-
-- Prestige formula design (sendou.ink-XXX)
\ No newline at end of file
diff --git a/.beans/sendou.ink-18y6--inconsistent-notification-dot-colors.md b/.beans/sendou.ink-18y6--inconsistent-notification-dot-colors.md
deleted file mode 100644
index 36b9f90d9..000000000
--- a/.beans/sendou.ink-18y6--inconsistent-notification-dot-colors.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-# sendou.ink-18y6
-title: Inconsistent notification dot colors
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T19:22:01Z
-updated_at: 2026-01-12T16:04:11Z
-parent: sendou.ink-6eko
----
-
-The notification dot color is inconsistent between:
-- The notification bell / user menu tab indicator
-- The dots shown in the actual notification popover
-
-These should use consistent styling.
\ No newline at end of file
diff --git a/.beans/sendou.ink-1kb8--show-times-on-mobile-my-calendar-panel.md b/.beans/sendou.ink-1kb8--show-times-on-mobile-my-calendar-panel.md
deleted file mode 100644
index 8fdffbffe..000000000
--- a/.beans/sendou.ink-1kb8--show-times-on-mobile-my-calendar-panel.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-# sendou.ink-1kb8
-title: Show times on mobile Events panel
-status: completed
-type: task
-priority: normal
-tags:
- - my-events-epic
-created_at: 2026-01-11T09:48:18Z
-updated_at: 2026-01-11T13:24:31Z
-parent: sendou.ink-6eko
----
-
-## Summary
-
-The mobile Events panel currently only shows tournament names without any time information. Add day headers and event times to help players know when things are happening.
-
-## Current state
-
-Panel shows a flat list of tournaments with just:
-- Tournament logo
-- Tournament name
-
-## Proposed design
-
-Group events by day with headers, then show time per event:
-
-```
-Today
- 3:00 PM PICNIC #2
- 7:00 PM In The Zone 22
-
-Tomorrow
- 2:00 PM Paddling Pool 253
- 5:00 PM Swim or Sink 101
-```
-
-## Checklist
-
-- [x] Add day header groupings (Today, Tomorrow, weekday names, or dates)
-- [x] Show event start time next to each entry
-- [x] Ensure times display in user's local timezone
-- [x] Test with events spanning multiple days
\ No newline at end of file
diff --git a/.beans/sendou.ink-1l22--css-rework-for-modern-practices-and-theming-access.md b/.beans/sendou.ink-1l22--css-rework-for-modern-practices-and-theming-access.md
deleted file mode 100644
index df6c04f3c..000000000
--- a/.beans/sendou.ink-1l22--css-rework-for-modern-practices-and-theming-access.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-# sendou.ink-1l22
-title: CSS rework for modern practices and theming accessibility
-status: in-progress
-type: epic
-priority: normal
-created_at: 2026-01-11T09:33:26Z
-updated_at: 2026-01-11T09:34:23Z
----
-
-## Why
-
-The existing CSS architecture needed modernization to support:
-
-1. **Consistency** - Standardized design tokens and variable naming conventions
-2. **Modern CSS practices** - Leveraging newer CSS features for better maintainability
-3. **Accessibility for user-defined themes** - Making it easy for users to customize themes while maintaining readability and contrast requirements
-
-## What's been done
-
-- Redefined all styles in `vars.css` with a consistent naming convention
-- Established design tokens for colors, spacing, typography, and other properties
-- Created a foundation that supports user theme customization while preserving accessibility
-
-## Goals
-
-- All components use CSS variables from `vars.css` consistently
-- Theme customization is straightforward and accessible
-- Color contrast and other accessibility requirements are maintained across all themes
-- Reduced CSS specificity conflicts and improved maintainability
-
-## Completion criteria
-
-All child tickets resolved and the new CSS variable system is fully adopted across the codebase.
\ No newline at end of file
diff --git a/.beans/sendou.ink-1qfh--fix-notification-button-and-indicator-dot-overlay.md b/.beans/sendou.ink-1qfh--fix-notification-button-and-indicator-dot-overlay.md
deleted file mode 100644
index cae7fc8c0..000000000
--- a/.beans/sendou.ink-1qfh--fix-notification-button-and-indicator-dot-overlay.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# sendou.ink-1qfh
-title: Fix notification button and indicator dot overlay
-status: scrapped
-type: bug
-priority: normal
-created_at: 2026-01-11T09:37:03Z
-updated_at: 2026-01-11T12:53:25Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-The notification bell icon and the unread indicator dot are displayed side by side instead of the dot being overlayed on top of the bell icon.
-
-## Screenshot
-
-The blue notification dot appears next to the bell icon rather than positioned as an overlay badge on the icon.
-
-## Expected behavior
-
-The notification indicator dot should be positioned as an overlay on the bell icon (typically top-right corner), following standard notification badge UI patterns.
-
-## Acceptance criteria
-
-- Notification dot is positioned as an overlay on the bell icon
-- Dot placement follows common UI conventions (e.g., top-right corner)
-- Works correctly on both desktop sidebar and mobile layouts
\ No newline at end of file
diff --git a/.beans/sendou.ink-24f6--analyze-tournament-seeding-data-distribution.md b/.beans/sendou.ink-24f6--analyze-tournament-seeding-data-distribution.md
deleted file mode 100644
index ac7691c50..000000000
--- a/.beans/sendou.ink-24f6--analyze-tournament-seeding-data-distribution.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-# sendou.ink-24f6
-title: Analyze tournament seeding data distribution
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-12T09:21:17Z
-updated_at: 2026-01-12T09:21:23Z
-parent: sendou.ink-ylq5
-blocking:
- - sendou.ink-h9ht
----
-
-Research task: Analyze existing tournament data to understand seeding skill distributions.
-
-## Goals
-
-- Understand the range and distribution of avgSeedingSkillOrdinal values
-- Identify what distinguishes 'stacked' tournaments from casual ones
-- Find natural breakpoints for prestige tiers
-- Compare team counts vs skill levels
-
-## Data to Analyze
-
-- All finalized tournaments (RANKED and UNRANKED)
-- Top 8 teams' average seeding skill ordinal
-- Distribution across different tournament sizes
-
-## Output
-
-- Report with findings
-- Recommendations for baseline comparison value
-- Suggested tier boundaries (if discrete tiers make sense)
-
-## Implementation Notes
-
-- Can use db-prod.sqlite3 for real data
-- Write analysis script or SQL queries
-- Consider visualizing distributions
\ No newline at end of file
diff --git a/.beans/sendou.ink-255r--friends-feature.md b/.beans/sendou.ink-255r--friends-feature.md
deleted file mode 100644
index f53b56011..000000000
--- a/.beans/sendou.ink-255r--friends-feature.md
+++ /dev/null
@@ -1,128 +0,0 @@
----
-# sendou.ink-255r
-title: Friends feature
-status: todo
-type: epic
-priority: normal
-created_at: 2026-01-11T09:27:40Z
-updated_at: 2026-01-13T09:31:29Z
----
-
-## Overview
-
-Friends functionality for sendou.ink, replacing the current "Trusted" system. Enables users to see their friends in one place and quickly find what they're looking for (SendouQ group, tournament).
-
-## Core Concepts
-
-### Relationship Model
-- **Mutual friendship**: User A sends request → User B accepts → both are friends
-- **Friends = Trusted**: Friendship automatically grants all current trust permissions (quick-add to groups, scrim pickups)
-- **Soft limit**: ~200 friends maximum per user
-
-### Display Priority Hierarchy
-The sidebar and /friends page show users from multiple relationship sources, prioritized as:
-
-1. **Explicit friends** (highest priority) - Users you've mutually friended
-2. **Team members** - Members of teams you belong to
-3. **Shared association members** (lowest priority) - Members of organizations/associations you share, including Plus server members
-
-Within each tier, users with activity (SendouQ/tournaments) are shown first.
-
-### Activity Visibility
-- SendouQ group status (group count like "2/4")
-- Tournament registration/participation
-- No online/last seen tracking - just activities
-- All connections see your activity (no privacy controls for MVP)
-
-### Permission Model
-- **Trusted permissions** (quick-add to groups without invite): Friends only
-- **Quick invite** (send invite notification): All connections (friends, teammates, associations)
-- Teammates and association members receive invite and must accept
-
-### Migration from Trust System
-- If A trusts B AND B trusts A → auto-create friendship
-- One-way trust relationships → deleted
-- TrustRelationship table eventually deprecated
-
-## Features
-
-### Friend Requests
-- Send from: user profile page, invite link join flow (checkbox like current trust)
-- Notifications: in-app only (notification bell/dropdown)
-- States: pending outgoing, pending incoming, accepted, declined
-
-### Sidebar Display
-- Mixed list (no grouping by relationship type)
-- Quota system: X slots for SendouQ activity, Y slots for tournament activity
-- Priority: explicit friends → team members → association members
-- Within each tier: active first, then most recent interaction
-- Each entry shows: avatar, name, activity subtitle, badge
-- "See all" link to /friends page
-
-### /friends Page
-- **Grouped sections** with headers (unlike sidebar)
-- **Pending requests section**: incoming and outgoing requests
-- **Friends section**: explicit friends with activity status
-- **Teammates section**: team members (with team name context)
-- **Connections section**: association/Plus members
-- **Management**: unfriend, search/filter across all sections
-- **Mutual friends**: show mutual friends count/list on profiles
-
-### Quick Invite to SendouQ
-- "Invite friend" button in SendouQ group lobby
-- Can invite any connection (friends, teammates, associations)
-- Sends notification to selected user(s)
-- User can accept to join group directly
-- Only friends can be directly added (trusted); others must accept invite
-
-### Mutual Friends Display
-- Show on user profiles
-- Count of mutual friends
-- Preview of mutual friend avatars/names
-
-## Database Schema
-
-### New Tables
-
-```sql
--- Friendship (mutual relationship)
-CREATE TABLE Friendship (
- // ...
-);
--- Invariant: userOneId < userTwoId to prevent duplicates
-
--- Friend Request
-CREATE TABLE FriendRequest (
- // ...
-);
-
-### Existing Tables Used
-- `TeamMember` - for teammate relationships
-- `AssociationMember` - for association members
-- `PlusTier` - for Plus server membership
-
-## Future Enhancements (out of scope)
-
-- Private messaging between friends
-- Friend activity feed (tournament placements, rank changes)
-- Friend categories/groups
-- Block list
-- LFG status visible to friends
-- Email notifications for friend requests
-- Privacy controls per connection type
-- Tournament team forming (see sendou.ink-5x6m)
-
-## Completion Criteria
-
-- [ ] Database schema and migrations created
-- [ ] FriendRepository with all CRUD operations
-- [ ] Friend request flow (send, accept, decline, cancel)
-- [ ] Sidebar shows real friends/teammates/connections with activity
-- [ ] /friends page with grouped sections and management
-- [ ] Profile page friend button and mutual friends
-- [ ] Quick invite to SendouQ group (all connections)
-- [ ] Group invite accept/decline flow for non-friends
-- [ ] Migration script for trust → friendship
-- [ ] Update all trust-dependent features to use friendship
-- [ ] Remove/deprecate TrustRelationship table
-- [ ] Tests for friend operations
diff --git a/.beans/sendou.ink-2oby--fix-handleradiogroupkeydown-in-commandpalette.md b/.beans/sendou.ink-2oby--fix-handleradiogroupkeydown-in-commandpalette.md
deleted file mode 100644
index bb0761cbb..000000000
--- a/.beans/sendou.ink-2oby--fix-handleradiogroupkeydown-in-commandpalette.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-# sendou.ink-2oby
-title: Fix handleRadioGroupKeyDown in CommandPalette
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T08:58:55Z
-updated_at: 2026-01-13T18:49:27Z
-parent: sendou.ink-6eko
----
-
-The handleRadioGroupKeyDown function is not working. Location: app/components/layout/CommandPalette.tsx:151
\ No newline at end of file
diff --git a/.beans/sendou.ink-368p--measure-and-optimize-weapon-params-json-performanc.md b/.beans/sendou.ink-368p--measure-and-optimize-weapon-params-json-performanc.md
deleted file mode 100644
index 634b3ca7e..000000000
--- a/.beans/sendou.ink-368p--measure-and-optimize-weapon-params-json-performanc.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-# sendou.ink-368p
-title: Measure and optimize weapon params JSON performance
-status: todo
-type: task
-created_at: 2026-01-13T15:23:48Z
-updated_at: 2026-01-13T15:23:48Z
-parent: sendou.ink-0ze4
----
-
-The weapon params are loaded from a large JSON file and calculated at request time. Tasks:
-
-## Checklist
-- [ ] Measure the current performance penalty of loading/parsing the big JSON at request time
-- [ ] Investigate if caching or pre-computation could improve performance
-- [ ] Implement optimizations if the perf impact is significant
\ No newline at end of file
diff --git a/.beans/sendou.ink-36dp--check-if-pagination-styles-can-be-improved.md b/.beans/sendou.ink-36dp--check-if-pagination-styles-can-be-improved.md
deleted file mode 100644
index d62277a3f..000000000
--- a/.beans/sendou.ink-36dp--check-if-pagination-styles-can-be-improved.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-36dp
-title: Check if pagination styles can be improved
-status: completed
-type: task
-created_at: 2026-01-11T12:35:22Z
-updated_at: 2026-01-11T12:35:22Z
-parent: sendou.ink-1l22
----
-
-Review the current pagination component styling and identify potential improvements that align with the CSS rework goals (modern practices, theming, accessibility).
diff --git a/.beans/sendou.ink-36pm--add-weapon-mega-menu-to-mobile-design.md b/.beans/sendou.ink-36pm--add-weapon-mega-menu-to-mobile-design.md
deleted file mode 100644
index e7ea34388..000000000
--- a/.beans/sendou.ink-36pm--add-weapon-mega-menu-to-mobile-design.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-# sendou.ink-36pm
-title: Add weapon mega menu to mobile design
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T09:31:09Z
-updated_at: 2026-01-11T18:58:39Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-The desktop layout has a weapon mega menu in the top navigation bar that allows users to quickly access weapon-specific pages. This menu is missing from the mobile design, which uses bottom tab navigation instead.
-
-## Context
-
-Mobile users currently lack quick access to weapon-related content that desktop users have via the top menu bar category dropdowns.
-
-## Possible approaches
-
-- Add weapon navigation to the mobile menu modal
-- Create a dedicated weapons section accessible from mobile tabs
-- Integrate weapon categories into the existing mobile menu structure
-
-## Acceptance criteria
-
-- Mobile users can access the same weapon navigation options as desktop users
-- Navigation is intuitive and follows the established mobile design patterns
\ No newline at end of file
diff --git a/.beans/sendou.ink-3hgl--fix-black-background-on-datetime-inputs-in-chrome.md b/.beans/sendou.ink-3hgl--fix-black-background-on-datetime-inputs-in-chrome.md
deleted file mode 100644
index 2094ff444..000000000
--- a/.beans/sendou.ink-3hgl--fix-black-background-on-datetime-inputs-in-chrome.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# sendou.ink-3hgl
-title: Fix black background on date/time inputs in Chrome
-status: todo
-type: bug
-created_at: 2026-01-11T12:36:28Z
-updated_at: 2026-01-11T12:36:28Z
-parent: sendou.ink-1l22
----
-
-Some native input types (time, datetime-local, week, month) display with black backgrounds or styling issues in Chrome. Need to investigate the root cause and apply a consistent fix across all affected input types.
-
-## Details
-- Affected inputs: time, datetime-local, week, month (and possibly others)
-- Browser: Chrome
-- The icons and placeholder text appear correctly but there seems to be a color scheme conflict
-
-## Checklist
-- [ ] Identify which CSS rules cause the black background
-- [ ] Check if it's related to color-scheme property or browser defaults
-- [ ] Apply a fix that works for all affected input types at once
-- [ ] Test in Chrome and other browsers
\ No newline at end of file
diff --git a/.beans/sendou.ink-3k3u--friend-request-api-routes.md b/.beans/sendou.ink-3k3u--friend-request-api-routes.md
deleted file mode 100644
index c811b2668..000000000
--- a/.beans/sendou.ink-3k3u--friend-request-api-routes.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-# sendou.ink-3k3u
-title: Friend request API routes
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-13T09:32:19Z
-updated_at: 2026-01-13T10:18:25Z
-parent: sendou.ink-255r
-blocking:
- - sendou.ink-f1rm
----
-
-## Overview
-
-Implement action handlers for friend request operations following the codebase's action pattern.
-
-## File
-
-`app/features/friends/actions/friends.ts` (same route as /friends page)
-
-## Action Pattern
-
-Uses `_action` field in form submissions with switch case:
-
-```typescript
-export const action: ActionFunction = async ({ request }) => {
- const user = await requireUser(request);
- const data = await parseRequestPayload({ request });
-
- switch (data._action) {
- case "SEND_REQUEST": {
- // Send friend request
- // Validate: not already friends, no pending request, under limit
- // Create FriendRequest record
- // Create notification for receiver
- return json({ success: true });
- }
- case "ACCEPT_REQUEST": {
- // Accept incoming friend request
- // Validate: request exists, user is receiver
- // Delete FriendRequest, create Friendship
- // Create notification for sender
- return json({ success: true });
- }
- case "DECLINE_REQUEST": {
- // Decline incoming friend request
- // Validate: request exists, user is receiver
- // Delete FriendRequest
- return json({ success: true });
- }
- case "CANCEL_REQUEST": {
- // Cancel outgoing friend request
- // Validate: request exists, user is sender
- // Delete FriendRequest
- return json({ success: true });
- }
- case "UNFRIEND": {
- // Remove friendship
- // Validate: friendship exists
- // Delete Friendship record
- return json({ success: true });
- }
- default:
- throw new Response("Invalid action", { status: 400 });
- }
-};
-```
-
-## Form Data
-
-```typescript
-// SEND_REQUEST
-{ _action: "SEND_REQUEST", targetUserId: number }
-
-// ACCEPT_REQUEST
-{ _action: "ACCEPT_REQUEST", requestId: number }
-// or
-{ _action: "ACCEPT_REQUEST", senderId: number }
-
-// DECLINE_REQUEST
-{ _action: "DECLINE_REQUEST", requestId: number }
-
-// CANCEL_REQUEST
-{ _action: "CANCEL_REQUEST", requestId: number }
-
-// UNFRIEND
-{ _action: "UNFRIEND", friendId: number }
-```
-
-## Validation
-
-- `SEND_REQUEST`:
- - Target user exists
- - Not already friends
- - No pending request in either direction
- - Sender under friend limit (~200)
-
-- `ACCEPT_REQUEST`:
- - Request exists
- - Current user is the receiver
- - Both users under friend limit
-
-- `UNFRIEND`:
- - Friendship exists
- - Current user is part of the friendship
-
-## Notifications
-
-- `SEND_REQUEST` → notify receiver "X sent you a friend request"
-- `ACCEPT_REQUEST` → notify original sender "X accepted your friend request"
-
-## Checklist
-
-- [ ] Add action handler to friends.tsx
-- [ ] SEND_REQUEST action with validation
-- [ ] ACCEPT_REQUEST action
-- [ ] DECLINE_REQUEST action
-- [ ] CANCEL_REQUEST action
-- [ ] UNFRIEND action
-- [ ] Integration with notification system
-- [ ] Error handling and user feedback
-- [ ] Tests for each action
diff --git a/.beans/sendou.ink-3qrp--improve-mobile-menu-grid-alignment-and-prevent-lab.md b/.beans/sendou.ink-3qrp--improve-mobile-menu-grid-alignment-and-prevent-lab.md
deleted file mode 100644
index 16b329f20..000000000
--- a/.beans/sendou.ink-3qrp--improve-mobile-menu-grid-alignment-and-prevent-lab.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-# sendou.ink-3qrp
-title: Improve mobile menu grid alignment and prevent label wrapping
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T09:42:29Z
-updated_at: 2026-01-11T18:31:05Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-On mobile, the menu grid has alignment issues and some page labels are breaking into two or three lines, creating an inconsistent and cluttered appearance.
-
-## Screenshot
-
-Labels breaking to multiple lines:
-- "Build Analyzer" (2 lines)
-- "User Search" (2 lines)
-- "Top Search" (2 lines)
-- "Tier List Maker" (3 lines)
-- "Plus Server" (2 lines)
-- "Leaderboards" wrapping
-
-Meanwhile other labels like "Settings", "SendouQ", "Builds", "Scrims", "LFG" etc. fit on one line.
-
-## Expected behavior
-
-- Menu items should be consistently aligned
-- Labels should ideally fit on a single line
-- If wrapping is unavoidable, it should be limited to two lines maximum
-
-## Possible solutions
-
-- Reduce number of columns to give more horizontal space per item
-- Use shorter label names where possible
-- Adjust font size for labels
-- Use text truncation with ellipsis for long labels
-
-## Acceptance criteria
-
-- Menu grid is visually balanced and aligned
-- No labels break to three lines
-- Minimize two-line labels where possible
-- Consistent spacing between menu items
\ No newline at end of file
diff --git a/.beans/sendou.ink-4m0t--add-stream-curator-role-to-permissions.md b/.beans/sendou.ink-4m0t--add-stream-curator-role-to-permissions.md
deleted file mode 100644
index 877122e2a..000000000
--- a/.beans/sendou.ink-4m0t--add-stream-curator-role-to-permissions.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-# sendou.ink-4m0t
-title: Add STREAM_CURATOR role to permissions
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-12T09:20:30Z
-updated_at: 2026-01-12T09:21:32Z
-parent: sendou.ink-r6ry
-blocking:
- - sendou.ink-x535
----
-
-Add new STREAM_CURATOR permission role to allow users to add stream links to calendar events.
-
-## Requirements
-
-- New role in existing permissions system
-- Granted by staff (same flow as 'is artist' role)
-- Allows adding stream link(s) to calendar events user created
-- Scoped to own events only
-
-## Checklist
-
-- [ ] Create migration to add `isStreamCurator` column to User table (Boolean, default 0)
-- [ ] Add `"STREAM_CURATOR"` to Role type in `/app/modules/permissions/types.ts`
-- [ ] Add mapping in `/app/modules/permissions/mapper.server.ts` userRoles function: `if (user.isStreamCurator) roles.push("STREAM_CURATOR")`
-- [ ] Add `makeStreamCuratorByUserId(userId)` function in `/app/features/admin/AdminRepository.server.ts`
-- [ ] Add `"STREAM_CURATOR"` action case in `/app/features/admin/actions/admin.server.ts`
-- [ ] Add `GiveStreamCurator` component in `/app/features/admin/routes/admin.tsx` (visible to staff)
-
-## Implementation Pattern
-
-Follow existing pattern from `isArtist`:
-
-```typescript
-// AdminRepository.server.ts
-export function makeStreamCuratorByUserId(userId: number) {
- return db
- .updateTable("User")
- .set({ isStreamCurator: 1 })
- .where("User.id", "=", userId)
- .execute();
-}
-```
-
-```typescript
-// admin.tsx - add to AdminActions, visible to isStaff
-{isStaff ? : null}
-```
\ No newline at end of file
diff --git a/.beans/sendou.ink-5d8q--show-notification-dot-on-mobile-you-tab.md b/.beans/sendou.ink-5d8q--show-notification-dot-on-mobile-you-tab.md
deleted file mode 100644
index 07cf5297f..000000000
--- a/.beans/sendou.ink-5d8q--show-notification-dot-on-mobile-you-tab.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-# sendou.ink-5d8q
-title: Show notification dot on mobile You tab
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T13:06:55Z
-updated_at: 2026-01-11T19:13:22Z
-parent: 6eko
----
-
-## Problem
-
-The desktop sidebar shows a notification indicator dot when there are unseen notifications, but the mobile "You" tab in the bottom navigation does not have this indicator.
-
-## Expected behavior
-
-The mobile "You" tab should display a notification dot when there are unseen notifications, matching the desktop behavior.
-
-## Location
-
-- Mobile tab bar: `app/components/MobileNav.tsx` (MobileTabBar component)
-- Desktop notification indicator for reference: `app/components/layout/index.tsx`
\ No newline at end of file
diff --git a/.beans/sendou.ink-5x6m--tournament-team-forming.md b/.beans/sendou.ink-5x6m--tournament-team-forming.md
deleted file mode 100644
index f4c7612b5..000000000
--- a/.beans/sendou.ink-5x6m--tournament-team-forming.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-# sendou.ink-5x6m
-title: Tournament team forming
-status: draft
-type: epic
-created_at: 2026-01-13T06:49:55Z
-updated_at: 2026-01-13T06:49:55Z
----
-
-## Overview
-
-Reuse the `SendouQ` class to allow for SendouQ-like UI to create tournaments teams.
-
-## Context
-
-- Depends on: Friends feature (sendou.ink-255r)
-
-## Potential Features
-
-- Can join the "queue" either solo or with a team
-- When registering solo, toggle whether they want to stay around as a sub if doesn't have time to form a team before reg closes
-
-## Notes
-
-This is a placeholder epic. Scope to be defined after Friends feature is complete.
diff --git a/.beans/sendou.ink-5ysz--add-weapon-parameter-translations-to-i18n.md b/.beans/sendou.ink-5ysz--add-weapon-parameter-translations-to-i18n.md
deleted file mode 100644
index 6137bc6d7..000000000
--- a/.beans/sendou.ink-5ysz--add-weapon-parameter-translations-to-i18n.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-# sendou.ink-5ysz
-title: Add weapon parameter translations to i18n
-status: todo
-type: task
-created_at: 2026-01-11T12:22:15Z
-updated_at: 2026-01-11T12:22:15Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Add weapon parameter keys to the existing i18n translation system so raw parameter names can be displayed in human-readable form.
-
-## Requirements
-
-- Add new translation namespace or extend existing `weapons` namespace
-- Map raw Leanny parameter keys to readable names
-- Initially can be partial - untranslated keys display as-is
-- Support incremental addition of translations over time
-
-## Example
-
-```json
-{
- "params": {
- "DamageParam_ValueMax": "Max Damage",
- "DamageParam_ValueMin": "Min Damage",
- "MoveSpeed": "Movement Speed"
- }
-}
-```
-
-## Technical Notes
-
-- Run `npm run i18n:sync` after adding new English translations
-- Keys should match exactly what comes from Leanny's data
-- We should have a way to know in the table which keys have translation and which don't for conditional rendering
diff --git a/.beans/sendou.ink-6eko--desktop-sidebar-and-mobile-tabs-layout.md b/.beans/sendou.ink-6eko--desktop-sidebar-and-mobile-tabs-layout.md
deleted file mode 100644
index 115bbd1a5..000000000
--- a/.beans/sendou.ink-6eko--desktop-sidebar-and-mobile-tabs-layout.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-# sendou.ink-6eko
-title: Desktop sidebar and mobile tabs layout
-status: in-progress
-type: epic
-priority: normal
-created_at: 2026-01-11T08:58:29Z
-updated_at: 2026-01-11T09:34:23Z
-blocking:
- - sendou.ink-1l22
----
-
-## Why
-
-The previous layout had several limitations holding back the player experience:
-
-1. **Poor mobile UX** - Navigation wasn't optimized for mobile players
-2. **Hard to navigate** - No global search, sidebar only appeared on front page making it difficult to find features
-3. **Slow path to matches** - Competitive players had too many clicks to join matches or check their tournament status
-4. **No foundation for scheduling** - Future features like team scheduling and league match scheduling need a persistent navigation structure
-5. **Streams not visible** - Community streams weren't highlighted, missing opportunity to showcase active players
-
-## Goals
-
-- Make it easy for competitive players to get into matches fast (1-click access to active matches/tournaments)
-- Provide persistent navigation across all pages via sidebar (desktop) and bottom tabs (mobile)
-- Add global search via command palette to quickly find users, teams, organizations, and tournaments
-- Lay foundation for upcoming features: friend group quick-join, team scheduling, league scheduling
-- Better highlight community content like streams
-
-## What's been built
-
-- **Desktop**: Fixed sidebar with user profile, tournament calendar, friends list, streams + top menu bar with category dropdowns
-- **Mobile**: Bottom tab bar with modal panels for menu, friends, tournaments, and user profile
-- **Command palette**: Global search (Cmd/Ctrl+K) for users, teams, organizations, tournaments
-- **Breadcrumb navigation**: Context-aware page hierarchy
-- **Quick match access**: Tournament and SendouQ match status prominently displayed
-
-## Completion criteria
-
-All child tickets resolved.
\ No newline at end of file
diff --git a/.beans/sendou.ink-6i41--move-settings-to-same-row-as-user-avatar-in-mobile.md b/.beans/sendou.ink-6i41--move-settings-to-same-row-as-user-avatar-in-mobile.md
deleted file mode 100644
index 8091425a4..000000000
--- a/.beans/sendou.ink-6i41--move-settings-to-same-row-as-user-avatar-in-mobile.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-# sendou.ink-6i41
-title: Move Settings to same row as user avatar in mobile user tab
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T09:40:48Z
-updated_at: 2026-01-11T13:11:56Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-On mobile, in the user tab modal, the Settings option is positioned at the bottom of the panel. It should instead be on the same row as the user avatar and name.
-
-## Current behavior
-
-- User avatar + name (Sendou) on one row
-- Notifications section
-- Settings at the bottom (separate location)
-
-## Expected behavior
-
-- User avatar + name + Settings on the same row
-- Notifications section below
-
-## Acceptance criteria
-
-- Settings button/link is positioned on the same row as the user avatar and name
-- Layout is balanced and visually clean
-- Settings remains easily accessible
\ No newline at end of file
diff --git a/.beans/sendou.ink-7omz--try-stage-banner-style-for-tournament-matches.md b/.beans/sendou.ink-7omz--try-stage-banner-style-for-tournament-matches.md
deleted file mode 100644
index b28ff6519..000000000
--- a/.beans/sendou.ink-7omz--try-stage-banner-style-for-tournament-matches.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-# sendou.ink-7omz
-title: Try stage banner style for tournament matches
-status: todo
-type: task
-created_at: 2026-01-11T19:25:36Z
-updated_at: 2026-01-11T19:25:36Z
-parent: sendou.ink-1l22
----
-
-## Description
-
-Experiment with using "stage banner" style images for tournament match displays instead of the regular sized stage images. Stage banner images are available in Lean's splat3 assets repository and might provide a better visual appearance.
-
-## Context
-
-Currently, tournament matches use regular stage images (`stageImageUrl`) as background for the `FancyStageBanner` component (in `app/features/tournament-bracket/components/StartedMatch.tsx`). The banner dimensions are 10rem tall with `background-size: cover`.
-
-Lean's repository may have wider/more panoramic stage banners that could better fit this banner-style layout without as much cropping.
-
-## Tasks
-
-- [ ] Locate stage banner images from Lean's splat3 repository
-- [ ] Compare visual appearance with current stage images
-- [ ] If they look better, add banner images to static assets
-- [ ] Update `stageImageUrl` or create new `stageBannerUrl` utility
-- [ ] Update `FancyStageBanner` component to use banner images
-
-## Files
-
-- `app/features/tournament-bracket/components/StartedMatch.tsx:290-292` - stageNameToBannerImageUrl function
-- `app/features/tournament-bracket/tournament-bracket.module.css:57-71` - stageBanner styling
-- `app/utils/urls.ts:493-494` - stageImageUrl function
\ No newline at end of file
diff --git a/.beans/sendou.ink-8vei--create-weapon-stats-summary-component.md b/.beans/sendou.ink-8vei--create-weapon-stats-summary-component.md
deleted file mode 100644
index 1ae4b8865..000000000
--- a/.beans/sendou.ink-8vei--create-weapon-stats-summary-component.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-# sendou.ink-8vei
-title: Create weapon stats summary component
-status: todo
-type: task
-created_at: 2026-01-11T12:22:34Z
-updated_at: 2026-01-11T12:22:34Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create a React component that displays weapon leaderboard and popularity statistics.
-
-## Features
-
-- **Top XP holder** - Player name + XP value, links to full leaderboard
-- **Popularity stats** - Top 500 appearances shown in two contexts:
- - Overall rank across all weapons
- - Rank within the weapon's category
-
-## Data Sources
-
-- XP data: `XPLeaderboard.server.ts` - `weaponXPLeaderboard(weaponId)`
-- Popularity: `XRankPlacement` table queries
-
-## Props
-
-- `topPlayer` - { name, xp, playerId }
-- `popularity` - { overallRank, categoryRank, appearances }
-- `weaponId` - for leaderboard link
-
-## Technical Notes
-
-- Use existing player link components if available
-- Leaderboard link goes to `/leaderboards?type=XP-WEAPON-{weaponId}`
-- Caching for performance?
diff --git a/.beans/sendou.ink-9cpl--create-streams-page-route-and-basic-layout.md b/.beans/sendou.ink-9cpl--create-streams-page-route-and-basic-layout.md
deleted file mode 100644
index c758a980b..000000000
--- a/.beans/sendou.ink-9cpl--create-streams-page-route-and-basic-layout.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-# sendou.ink-9cpl
-title: Create /streams page route and basic layout
-status: todo
-type: feature
-priority: normal
-created_at: 2026-01-12T09:19:55Z
-updated_at: 2026-01-12T12:07:16Z
-parent: sendou.ink-r6ry
-blocking:
- - sendou.ink-kph0
- - sendou.ink-u6b2
- - sendou.ink-ae15
----
-
-Create the new /streams page that will serve as the central hub for all community streams.
-
-## Requirements
-
-- Add route at /streams
-- Two-section layout: Live streams and Upcoming streams
-- Desktop: Single column (can iterate on two-column later)
-- Mobile: Single column stacked layout
-- Support query params for filtering
-
-## Query Params
-
-- `?source=sendouq` - Filter to only SendouQ streams
-- `?source=tournament` - Filter to only tournament streams
-- `?tournament=:id` - Filter to specific tournament (for redirect from `/to/:id/streams`)
-
-## Checklist
-
-- [ ] Add route to `routes.ts`: `route("/streams", "features/streams/routes/streams.tsx")`
-- [ ] Create `/app/features/streams/routes/streams.tsx`
-- [ ] Create loader that calls aggregation service
-- [ ] Create stream card component
-- [ ] Implement "Live" section with live streams
-- [ ] Implement "Upcoming" section with upcoming calendar events
-- [ ] Add empty state for when no streams are live
-- [ ] Add filter tabs/dropdown for source filtering
-- [ ] Add i18n translations
-
-## Stream Card Design
-
-Each stream card should show:
-- Thumbnail/avatar image
-- Stream title or streamer name
-- Source indicator (SendouQ badge, Tournament name, Event name)
-- Subtitle (round name, match info, scheduled time)
-- LIVE badge or scheduled time
-- Click to expand Twitch embed (if Twitch)
-- External link for non-Twitch streams
-
-## Empty State
-
-When no streams are live:
-- Show friendly message: "No live streams right now"
-- Show upcoming streams section more prominently
-- Consider showing recent VODs (future enhancement)
-
-## Implementation Notes
-
-- Create in `/app/features/streams/` folder
-- Loader calls aggregation service (sendou.ink-nw8b)
-- Twitch streams can embed inline (sendou.ink-r717)
-- Non-Twitch streams (YouTube, etc.) open in new tab
-
-## Dependencies
-
-- sendou.ink-nw8b: Stream aggregation service (for data)
-- sendou.ink-r717: Twitch embed component (for playback)
diff --git a/.beans/sendou.ink-a9gl--add-twitch-channel-field-to-calendarevent.md b/.beans/sendou.ink-a9gl--add-twitch-channel-field-to-calendarevent.md
deleted file mode 100644
index f6106e628..000000000
--- a/.beans/sendou.ink-a9gl--add-twitch-channel-field-to-calendarevent.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-# sendou.ink-a9gl
-title: Add stream links field to CalendarEvent
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-12T09:20:30Z
-updated_at: 2026-01-12T09:21:32Z
-parent: sendou.ink-r6ry
-blocking:
- - sendou.ink-x535
----
-
-Add database table for storing stream links associated with calendar events.
-
-## Requirements
-
-- Support multiple stream links per event (Twitch, YouTube, etc.)
-- Links are just URLs - platform-agnostic
-- Only STREAM_CURATOR users can add links to their own events
-
-## Data Model
-
-New join table `CalendarEventStream`:
-
-| Column | Type | Description |
-|--------|------|-------------|
-| id | number | Primary key |
-| calendarEventId | number | FK to CalendarEvent |
-| url | string | Full URL to stream (e.g., `https://twitch.tv/username`) |
-
-## Checklist
-
-- [ ] Create migration `0XXX-calendar-event-stream.ts` with CalendarEventStream table
-- [ ] Add `CalendarEventStream` interface to `/app/db/tables.ts`
-- [ ] Add TypeScript types in calendar feature types file
-- [ ] Create repository functions: `addStreamToEvent`, `removeStreamFromEvent`, `getStreamsForEvent`
-
-## Implementation Notes
-
-- Keep it simple: just store the URL as-is
-- No validation against external APIs (just basic URL format check)
-- Display can extract platform from URL (twitch.tv, youtube.com, etc.) if needed for icon
-- First version only support Twitch and YouTube links/embeds, might be expanded later (so store the full stream URL to the DB)
-- Max links per event: consider a reasonable limit (e.g., 5)
diff --git a/.beans/sendou.ink-ae15--add-streams-link-to-sidebar-and-mobile-menu.md b/.beans/sendou.ink-ae15--add-streams-link-to-sidebar-and-mobile-menu.md
deleted file mode 100644
index 8d138370c..000000000
--- a/.beans/sendou.ink-ae15--add-streams-link-to-sidebar-and-mobile-menu.md
+++ /dev/null
@@ -1,55 +0,0 @@
----
-# sendou.ink-ae15
-title: Add /streams link to sidebar and mobile menu
-status: todo
-type: task
-created_at: 2026-01-12T09:20:56Z
-updated_at: 2026-01-12T09:20:56Z
-parent: sendou.ink-r6ry
----
-
-Add navigation link to the new /streams page.
-
-## Requirements
-
-- Add link in sidebar streams section (below the top 3 streams)
-- Add to mobile menu in appropriate location
-- Link text: "All streams" (or localized equivalent)
-
-## Checklist
-
-- [ ] Add link in desktop sidebar after stream cards (`/app/components/layout/index.tsx`)
-- [ ] Add link in mobile menu streams section (`/app/components/MobileNav.tsx`)
-- [ ] Add i18n translation key: `common:nav.allStreams` = "All streams"
-- [ ] Run `npm run i18n:sync` after adding translation
-- [ ] Style link consistently with other section links
-
-## Implementation
-
-Desktop sidebar (in layout/index.tsx):
-```tsx
-}>Streams
-{streams.map(stream => )}
-All streams →
-```
-
-Mobile menu (in MobileNav.tsx):
-```tsx
-// In MenuOverlay streams section
-{streams.map(stream => ...)}
-All streams
-```
-
-OR
-
-inline link (the header becomes link) prompt user for resolution (TBD)
-
-## Notes
-
-- Should appear after the stream cards, not before
-- Use right arrow or chevron icon to indicate "see more"
-- Same pattern will be used for "Events" and "Friends" sections later
-
-## Dependencies
-
-- sendou.ink-9cpl: /streams page must exist first
diff --git a/.beans/sendou.ink-aq1e--create-weapon-art-preview-component.md b/.beans/sendou.ink-aq1e--create-weapon-art-preview-component.md
deleted file mode 100644
index 7eec0c0c5..000000000
--- a/.beans/sendou.ink-aq1e--create-weapon-art-preview-component.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-# sendou.ink-aq1e
-title: Create weapon art preview component
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T12:22:54Z
-updated_at: 2026-01-14T13:48:27Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create a React component that displays 5 art pieces tagged with the weapon.
-
-## Features
-
-- Show 5 art pieces tagged with the weapon's slug
-- Each art shows: thumbnail, artist name
-- "View all" link to art page filtered by weapon tag
-
-## Data Source
-
-- `ArtRepository` with tag filter
-- Tag = weapon slug (canonical tag, e.g., "splattershot-jr")
-
-## Props
-
-- `artPieces` - array of 5 art objects
-- `weaponSlug` - for tag filtering and "view all" link
-
-## Technical Notes
-
-- Art uses existing tag system - weapon slug is the canonical tag
-- Reuse existing art display components if available
\ No newline at end of file
diff --git a/.beans/sendou.ink-bp4w--quick-invite-to-sendouq-group.md b/.beans/sendou.ink-bp4w--quick-invite-to-sendouq-group.md
deleted file mode 100644
index 0e31f4aeb..000000000
--- a/.beans/sendou.ink-bp4w--quick-invite-to-sendouq-group.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-# sendou.ink-bp4w
-title: Replace trusted quick invite with friends quick invite
-status: todo
-type: task
-created_at: 2026-01-13T09:33:09Z
-updated_at: 2026-01-13T09:33:09Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Anywhere where user can currently quick invite their trusted users, now same can be done for friends (SendouQ, tournaments)
diff --git a/.beans/sendou.ink-bti2--fix-duplicate-notifications-header-in-mobile-user.md b/.beans/sendou.ink-bti2--fix-duplicate-notifications-header-in-mobile-user.md
deleted file mode 100644
index 052141ac7..000000000
--- a/.beans/sendou.ink-bti2--fix-duplicate-notifications-header-in-mobile-user.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-# sendou.ink-bti2
-title: Fix duplicate Notifications header in mobile user tab
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T09:39:53Z
-updated_at: 2026-01-11T13:02:44Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-On mobile, the user tab modal shows the "Notifications" header twice in a row - once as a section header and again immediately below it with a refresh button.
-
-## Screenshot
-
-The "You" modal displays:
-- User profile (Sendou)
-- 🔔 Notifications (first instance)
-- 🔔 Notifications + refresh button (second instance)
-- Notification list items
-
-## Expected behavior
-
-The Notifications header should only appear once.
-
-## Acceptance criteria
-
-- Only one Notifications header is displayed in the mobile user tab
-- Refresh functionality is preserved
-- Layout remains clean and properly structured
\ No newline at end of file
diff --git a/.beans/sendou.ink-bxxe--improve-expanded-row-border-alignment-style.md b/.beans/sendou.ink-bxxe--improve-expanded-row-border-alignment-style.md
deleted file mode 100644
index cb39f678c..000000000
--- a/.beans/sendou.ink-bxxe--improve-expanded-row-border-alignment-style.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-bxxe
-title: Improve expanded row border alignment style
-status: todo
-type: task
-created_at: 2026-01-13T15:23:48Z
-updated_at: 2026-01-13T15:23:48Z
-parent: sendou.ink-0ze4
----
-
-Review the expanded row styling in the weapons page params table and see if the border alignment can be improved for a cleaner visual appearance.
\ No newline at end of file
diff --git a/.beans/sendou.ink-cml6--investigate-visual-regression-test-failures.md b/.beans/sendou.ink-cml6--investigate-visual-regression-test-failures.md
deleted file mode 100644
index 54753412e..000000000
--- a/.beans/sendou.ink-cml6--investigate-visual-regression-test-failures.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-cml6
-title: Investigate visual regression test failures
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T15:06:10Z
-updated_at: 2026-01-11T15:09:14Z
----
-
-Investigate visual regression test failures and update fixtures if they seem expected based on the current css-rework-sidenav branch changes.
\ No newline at end of file
diff --git a/.beans/sendou.ink-d6vh--my-calendar-data-layer.md b/.beans/sendou.ink-d6vh--my-calendar-data-layer.md
deleted file mode 100644
index 26a676d87..000000000
--- a/.beans/sendou.ink-d6vh--my-calendar-data-layer.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-# sendou.ink-d6vh
-title: My Events data layer
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-11T11:45:35Z
-updated_at: 2026-01-11T12:51:07Z
-parent: sendou.ink-om3i
----
-
-## Summary
-
-Create the data fetching layer for the My Events page that combines tournaments and scrims into a unified event list.
-
-## Details
-
-**Data sources to combine:**
-- Tournaments user is registered for
-- Tournaments user is organizing
-- Scrims with scheduled matches
-- Scrims in looking-for-match state
-
-**Output:**
-- Single sorted list of events (chronological)
-- Each event needs: name, time, status, type (tournament/scrim)
-- Tournament events need: check-in window info, handle two-day tournaments
-- Filter to upcoming events only (no past)
-
-## Technical approach
-
-- Create loader at `/my-events` route
-- Repository functions to fetch user tournaments and scrims
-- Merge and sort by start time
-- Design data structure that works for both page and sidebar (shared)
-
-## Checklist
-
-- [ ] Create repository function for user's upcoming tournaments
-- [ ] Create repository function for user's upcoming scrims
-- [ ] Create unified event type/interface
-- [ ] Create loader that combines and sorts events
-- [ ] Verify data structure works for sidebar consumption
\ No newline at end of file
diff --git a/.beans/sendou.ink-eb17--add-ad-slots-to-new-layout.md b/.beans/sendou.ink-eb17--add-ad-slots-to-new-layout.md
deleted file mode 100644
index 92e018a9e..000000000
--- a/.beans/sendou.ink-eb17--add-ad-slots-to-new-layout.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-# sendou.ink-eb17
-title: Add ad slots to new layout
-status: draft
-type: task
-created_at: 2026-01-11T09:29:25Z
-updated_at: 2026-01-11T09:29:25Z
-parent: sendou.ink-6eko
----
-
-## Task
-
-Define and implement ad slot placements for the new sidebar/mobile layout.
-
-## To Define
-
-- Where should ads appear? (sidebar, content area, mobile panels?)
-- Ad sizes and formats
-- How do ads interact with sidebar collapse?
-- Mobile-specific ad placements
-- Integration with existing ad provider
\ No newline at end of file
diff --git a/.beans/sendou.ink-ekv0--collapse-sidenav-button-flashes-on-mobile-page-loa.md b/.beans/sendou.ink-ekv0--collapse-sidenav-button-flashes-on-mobile-page-loa.md
deleted file mode 100644
index 573e63e91..000000000
--- a/.beans/sendou.ink-ekv0--collapse-sidenav-button-flashes-on-mobile-page-loa.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-ekv0
-title: Collapse sidenav button flashes on mobile page load
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-15T19:16:35Z
-updated_at: 2026-01-17T06:04:49Z
----
-
-The collapse sidenav button should not be visible on mobile at all, but it currently flashes briefly during page load before being hidden. It should not show even for a fraction of a second.
\ No newline at end of file
diff --git a/.beans/sendou.ink-f1rm--notifications-with-action-buttons.md b/.beans/sendou.ink-f1rm--notifications-with-action-buttons.md
deleted file mode 100644
index b9527f772..000000000
--- a/.beans/sendou.ink-f1rm--notifications-with-action-buttons.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-# sendou.ink-f1rm
-title: Notifications with action buttons
-status: todo
-type: task
-created_at: 2026-01-13T10:13:18Z
-updated_at: 2026-01-13T10:13:18Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Extend the notification system to support inline action buttons. First use case: accept/decline friend requests directly from notification dropdown.
-
-## Current State
-
-Notifications are display-only - users must navigate to another page to take action.
-
-## Requirements
-
-### Generic Action Support
-Notifications should support optional action buttons:
-- Primary action (e.g., "Accept")
-- Secondary action (e.g., "Decline")
-- Actions trigger API calls without page navigation
-- Notification updates/dismisses after action
-
-### Friend Request Actions
-First implementation:
-- Friend request notification shows "Accept" and "Decline" buttons
-- Accept → creates friendship, dismisses notification
-- Decline → deletes request, dismisses notification
-
-## Database Changes
-
-Extend notification schema (if needed):
-```sql
--- Option A: Store action metadata in notification
-ALTER TABLE Notification ADD COLUMN actionType TEXT;
-ALTER TABLE Notification ADD COLUMN actionData TEXT; -- JSON
-
--- Option B: Derive actions from notification type
--- No schema change, handle in code based on notification type
-```
-
-## UI Components
-
-### NotificationItem
-- Conditionally render action buttons based on notification type
-- Loading state during action
-- Success/error feedback
-- Optimistic UI update
-
-### Action Types (extensible)
-```typescript
-type NotificationAction = {
- type: "FRIEND_REQUEST";
- actions: ["accept", "decline"];
-} |
-// not part of this task, but for future can also be group_invite etc.
-{
- type: "GROUP_INVITE";
- actions: ["accept", "decline"];
-} // ... future types
-```
-
-## API
-
-New /notifications actions route.
-
-## Future Use Cases
-
-- Group invites (accept/decline)
-- Tournament team invites
-- Match ready check
-- Scrim requests
-
-## Checklist
-
-- [ ] Design notification action data model
-- [ ] Update NotificationItem component with action buttons
-- [ ] Action API endpoint or reuse existing endpoints
-- [ ] Loading/success/error states
-- [ ] Implement for friend requests
-- [ ] Update notification after action (dismiss or mark complete)
-- [ ] Mobile-friendly action buttons
-- [ ] Tests for notification actions
diff --git a/.beans/sendou.ink-g01q--explore-more-comfortable-way-to-close-mobile-tab-m.md b/.beans/sendou.ink-g01q--explore-more-comfortable-way-to-close-mobile-tab-m.md
deleted file mode 100644
index 8d8c458e6..000000000
--- a/.beans/sendou.ink-g01q--explore-more-comfortable-way-to-close-mobile-tab-m.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-# sendou.ink-g01q
-title: Explore more comfortable way to close mobile tab menu panels
-status: todo
-type: task
-created_at: 2026-01-15T19:19:30Z
-updated_at: 2026-01-15T19:19:30Z
----
-
-The X button to close mobile tab menu panels is positioned far out of reach, making it uncomfortable to use.
-
-## Potential solution
-React Aria's Sheet component might be a good approach: https://react-aria.adobe.com/examples/sheet
-
-This would allow swipe-to-dismiss gestures which are more ergonomic on mobile.
-
-## Trade-offs
-- Pro: Better UX with swipe gestures
-- Con: Requires pulling in a new dependency (Motion)
\ No newline at end of file
diff --git a/.beans/sendou.ink-gdrp--update-trust-dependent-features-to-use-friendship.md b/.beans/sendou.ink-gdrp--update-trust-dependent-features-to-use-friendship.md
deleted file mode 100644
index 75ef134a4..000000000
--- a/.beans/sendou.ink-gdrp--update-trust-dependent-features-to-use-friendship.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-# sendou.ink-gdrp
-title: Update trust-dependent features to use friendship
-status: todo
-type: task
-created_at: 2026-01-13T09:33:32Z
-updated_at: 2026-01-13T09:33:32Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Update all code that uses TrustRelationship to use Friendship instead.
-
-## Files to Update
-
-### SendouQ Group Adding
-- `app/features/sendouq/actions/q.preparing.server.ts` - ADD_TRUSTED action
-- `app/features/sendouq/components/MemberAdder.tsx` - Uses useTrusted hook
-- `app/hooks/swr.ts` - useTrusted() hook → useFriends()
-- `app/features/sendouq/routes/trusters.ts` - Trusters API → Friends API
-
-### Tournament Join
-- `app/features/tournament/actions/to.$id.join.server.ts` - Trust checkbox on join
-- `app/features/tournament/loaders/to.$id.register.server.ts` - trusterPlayers query
-- Change "trust" checkbox to "add as friend" checkbox
-
-### Scrim Pickups
-- `app/features/scrims/actions/scrims.new.server.ts` - Validates trusted for pickup
-- Update to check friendship instead
-
-### Settings
-- `app/features/sendouq-settings/routes/q.settings.tsx` - Trusted users list
-- `app/features/sendouq-settings/QSettingsRepository.server.ts` - Trust queries
-- Replace with friends list/management
-
-### Cleanup Routine
-- `app/routines/deleteOldTrusts.ts` - Delete after migration complete
-
-## Checklist
-
-- [ ] Update SendouQ ADD_TRUSTED to use friends
-- [ ] Update MemberAdder component
-- [ ] Replace useTrusted hook with useFriends
-- [ ] Update tournament join flow
-- [ ] Update scrim pickup validation
-- [ ] Update Q settings page
-- [ ] Update or remove trust cleanup routine
-- [ ] Search codebase for remaining TrustRelationship references
-- [ ] E2E tests for updated flows
\ No newline at end of file
diff --git a/.beans/sendou.ink-gjie--create-parameter-comparison-table-component.md b/.beans/sendou.ink-gjie--create-parameter-comparison-table-component.md
deleted file mode 100644
index ec7c68735..000000000
--- a/.beans/sendou.ink-gjie--create-parameter-comparison-table-component.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-# sendou.ink-gjie
-title: Create parameter comparison table component
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T12:22:15Z
-updated_at: 2026-01-13T12:21:54Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create a React component that displays weapon parameters in a comparison table format. Use `Table` component
-
-## Design
-
-- **Rows** = parameters (raw keys, translated via i18n if available)
-- **Columns** = weapons in same category (e.g., all shooters)
-- **Current weapon pinned** - always visible, visually highlighted
-- **Patch history inline** - cells show current value + indicator if changed, expandable to see full history (patch + date)
-
-## Props
-
-- `weaponId` - current weapon
-- `categoryWeapons` - list of weapons in same category
-- `params` - parameter data with patch history
-
-## Technical Notes
-
-- Use CSS modules for styling
-- Consider horizontal scroll for many weapons
-- Expandable rows for patch history (click to expand)
-- Changed values should have visual indicator (icon or color)
diff --git a/.beans/sendou.ink-gk34--improve-tournament-search-relevance.md b/.beans/sendou.ink-gk34--improve-tournament-search-relevance.md
deleted file mode 100644
index be1647614..000000000
--- a/.beans/sendou.ink-gk34--improve-tournament-search-relevance.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-gk34
-title: Improve tournament search relevance
-status: todo
-type: task
-created_at: 2026-01-11T08:58:56Z
-updated_at: 2026-01-11T08:58:56Z
-parent: sendou.ink-6eko
----
-
-For tournament search results, when there are equally good matches, show tournaments closest to current date first. Example: searching 'In The Zone' should show newest tournament first. Location: app/features/search/routes/search.ts:86
\ No newline at end of file
diff --git a/.beans/sendou.ink-govi--load-test-sidenav.md b/.beans/sendou.ink-govi--load-test-sidenav.md
deleted file mode 100644
index 21dbaa51b..000000000
--- a/.beans/sendou.ink-govi--load-test-sidenav.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-govi
-title: Load test sidenav
-status: todo
-type: task
-created_at: 2026-01-11T12:28:34Z
-updated_at: 2026-01-11T12:28:34Z
-parent: sendou.ink-6eko
----
-
-Perform load tests to ensure the sidenav performs well under various conditions and with different data volumes.
diff --git a/.beans/sendou.ink-h8l0--fix-mobilenav-padding-on-android.md b/.beans/sendou.ink-h8l0--fix-mobilenav-padding-on-android.md
deleted file mode 100644
index 0df271e07..000000000
--- a/.beans/sendou.ink-h8l0--fix-mobilenav-padding-on-android.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-h8l0
-title: Fix MobileNav padding on Android
-status: todo
-type: bug
-created_at: 2026-01-11T08:58:54Z
-updated_at: 2026-01-11T08:58:54Z
-parent: sendou.ink-6eko
----
-
-The mobile navigation lacks proper padding on Android devices. iOS displays correctly. Location: app/components/MobileNav.tsx:35
\ No newline at end of file
diff --git a/.beans/sendou.ink-h9ht--design-and-test-prestige-formula.md b/.beans/sendou.ink-h9ht--design-and-test-prestige-formula.md
deleted file mode 100644
index a3950b1e7..000000000
--- a/.beans/sendou.ink-h9ht--design-and-test-prestige-formula.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-# sendou.ink-h9ht
-title: Design and test prestige formula
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-12T09:21:17Z
-updated_at: 2026-01-12T09:21:23Z
-parent: sendou.ink-ylq5
-blocking:
- - sendou.ink-10ai
----
-
-Experiment with different prestige calculation formulas using real tournament data.
-
-## Algorithm Concept (from epic)
-
-Calculate prestige based on average seeding power of top 8 teams compared to a baseline.
-
-## Variables to Experiment With
-
-- Which teams to consider (top 8? top 4? all teams?)
-- Baseline value (median of all tournaments? fixed threshold?)
-- Team count weighting (16-team vs 128-team handling)
-- Continuous score vs discrete tiers
-
-## Test Cases
-
-Run formula against known tournaments and verify results match intuition:
-- Major community tournaments (should be high prestige)
-- Regular weeklies (should be medium)
-- Casual/new tournaments (should be lower)
-
-## Output
-
-- Documented formula with rationale
-- Test results showing formula produces expected rankings
-- Configuration constants for tuning
-
-## Dependencies
-
-- Seeding data analysis (sendou.ink-XXX) for understanding data distribution
\ No newline at end of file
diff --git a/.beans/sendou.ink-hw3x--update-sidebar-to-use-real-stream-data.md b/.beans/sendou.ink-hw3x--update-sidebar-to-use-real-stream-data.md
deleted file mode 100644
index 9b689578f..000000000
--- a/.beans/sendou.ink-hw3x--update-sidebar-to-use-real-stream-data.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-# sendou.ink-hw3x
-title: Update sidebar to use real stream data
-status: todo
-type: task
-created_at: 2026-01-12T09:20:56Z
-updated_at: 2026-01-12T09:20:56Z
-parent: sendou.ink-r6ry
----
-
-Replace mock stream data in sidebar with real aggregated streams.
-
-## Current State
-
-- `/app/features/sidebar/routes/sidebar.ts` has `getMockStreams()`
-- Returns hardcoded test data
-- Sidebar already displays streams in correct format
-
-## Requirements
-
-- Call stream aggregation service
-- Apply scoring algorithm to get top 3
-- Return in SideNavLink format: `{ id, name, imageUrl, subtitle, badge }`
-
-## Checklist
-
-- [ ] Import aggregation service in sidebar.ts
-- [ ] Replace `getMockStreams()` with call to `aggregateStreams()`
-- [ ] Apply `rankStreams()` to get scored/shuffled order
-- [ ] Take top 3 streams
-- [ ] Map to SideNavLink format
-- [ ] Add error handling (return empty array if service fails)
-- [ ] Test with real Twitch data
-
-## Implementation
-
-```typescript
-// sidebar.ts loader
-import { aggregateStreams, rankStreams } from "~/features/streams/streams.server";
-
-async function getStreams() {
- try {
- const allStreams = await aggregateStreams();
- const ranked = rankStreams(allStreams);
- return ranked.slice(0, 3).map(stream => ({
- id: stream.id,
- name: stream.name,
- imageUrl: stream.imageUrl,
- subtitle: stream.subtitle,
- badge: stream.badge,
- url: stream.url,
- }));
- } catch (error) {
- console.error("Failed to fetch streams:", error);
- return [];
- }
-}
-```
-
-## Error Handling
-
-- If aggregation service fails, return empty array (don't break sidebar)
-- Log error for debugging
-- Sidebar gracefully hides streams section when empty
-
-## Dependencies
-
-- sendou.ink-nw8b: Stream aggregation service
-- sendou.ink-js3r: Sidebar scoring algorithm
diff --git a/.beans/sendou.ink-i6lm--radio-buttons-and-similar-components-get-squished.md b/.beans/sendou.ink-i6lm--radio-buttons-and-similar-components-get-squished.md
deleted file mode 100644
index 6423ef5dd..000000000
--- a/.beans/sendou.ink-i6lm--radio-buttons-and-similar-components-get-squished.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# sendou.ink-i6lm
-title: Radio buttons and similar components get squished on mobile
-status: todo
-type: bug
-created_at: 2026-01-15T19:29:55Z
-updated_at: 2026-01-15T19:29:55Z
----
-
-Some components like radio buttons get squished when there is no horizontal space available on mobile devices. This affects usability and visual appearance on smaller screens.
-
-## Screenshots
-
-
-
-
-## Checklist
-
-- [ ] Identify affected components (radio buttons, checkboxes, etc.)
-- [ ] Investigate root cause of squishing behavior
-- [ ] Implement fix to ensure components maintain minimum size
-- [ ] Test on various mobile viewport widths
diff --git a/.beans/sendou.ink-iam7--replace-placeholder-logo.md b/.beans/sendou.ink-iam7--replace-placeholder-logo.md
deleted file mode 100644
index ad77d9563..000000000
--- a/.beans/sendou.ink-iam7--replace-placeholder-logo.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-iam7
-title: Replace placeholder logo
-status: todo
-type: task
-created_at: 2026-01-11T08:58:55Z
-updated_at: 2026-01-11T08:58:55Z
-parent: sendou.ink-6eko
----
-
-Replace the placeholder logo with final logo asset when ready. Location: app/components/layout/index.tsx:259
\ No newline at end of file
diff --git a/.beans/sendou.ink-iulp--friendrepository-implementation.md b/.beans/sendou.ink-iulp--friendrepository-implementation.md
deleted file mode 100644
index 03937c437..000000000
--- a/.beans/sendou.ink-iulp--friendrepository-implementation.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-# sendou.ink-iulp
-title: FriendRepository implementation
-status: in-progress
-type: task
-priority: normal
-created_at: 2026-01-13T09:32:05Z
-updated_at: 2026-01-16T07:59:43Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Create repository for friend-related database operations.
-
-## File
-
-`app/features/friends/FriendRepository.server.ts`
-
-## Functions
-
-### Friendship CRUD
-- `insert(userOneId, userTwoId)` - Create mutual friendship (ensure userOneId < userTwoId)
-- `delete(userId, friendId)` - Remove friendship
-- `findByUserId(userId)` - Get all friends for a user
-- `findMutualFriends(userIdA, userIdB)` - Get mutual friends between two users
-
-### Friend Requests
-- `insert(senderId, receiverId)` - Send friend request
-- `delete(senderId, receiverId)` - Cancel/decline request
-- `findPendingForUser(userId)` - Get incoming requests
-- `findOutgoingForUser(userId)` - Get outgoing requests
-- `hasPendingRequest(senderId, receiverId)` - Check if request exists
-
-### Connections (aggregated)
-- `findAllConnectionsWithActivity(userId)` - Get friends, teammates, associations with SendouQ/tournament activity
-
-## Checklist
-
-- [x] Create FriendRepository.server.ts
-- [x] Implement `findByUserIdWithActivity(userId)` for sidebar
-- [ ] Implement friendship CRUD
-- [ ] Implement friend request operations
-- [ ] Unit tests for repository functions
diff --git a/.beans/sendou.ink-ivaf--friends-section-in-sidebar-with-quick-invite.md b/.beans/sendou.ink-ivaf--friends-section-in-sidebar-with-quick-invite.md
deleted file mode 100644
index ff477e832..000000000
--- a/.beans/sendou.ink-ivaf--friends-section-in-sidebar-with-quick-invite.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-# sendou.ink-ivaf
-title: Friends section in sidebar with quick invite
-status: todo
-type: feature
-created_at: 2026-01-16T10:17:54Z
-updated_at: 2026-01-16T10:17:54Z
-parent: sendou.ink-6eko
----
-
-Integrate friends into the sidebar, enabling quick invites and friend status viewing.
-
-**Related:** sendou.ink-255r (Friends feature epic)
-
-## Features
-
-### Quick Invite
-- Users can send a "quick invite" to friends who have a partial SendouQ group that is currently looking for members
-- The invite should be fast/easy to send directly from the sidebar
-
-### Expandable Friend Details
-When a user expands a friend entry in the sidebar, display:
-- User avatar
-- User name
-- Weapons (their current weapon pool or equipped weapons)
-- Current group info (if they're in a SendouQ group)
-- Any custom status text if available
-
-For each of the friends groups' members
-
-### Pending Requests Indicator
-- Show pending requests somewhere visible in the UI
-
-## Checklist
-
-- [ ] Design UI for friends list in sidebar
-- [ ] Add expand/collapse functionality for friend entries
-- [ ] Display friend details (avatar, name, weapons, status text)
-- [ ] Show current SendouQ group info for friends who are looking
-- [ ] Implement quick invite button for friends with partial groups
-- [ ] Add pending friend requests indicator
-- [ ] Handle loading and empty states
diff --git a/.beans/sendou.ink-j4zp--remove-and-redirect-u-page.md b/.beans/sendou.ink-j4zp--remove-and-redirect-u-page.md
deleted file mode 100644
index 9edebfcd1..000000000
--- a/.beans/sendou.ink-j4zp--remove-and-redirect-u-page.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-# sendou.ink-j4zp
-title: Remove and redirect /u page
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T08:58:56Z
-updated_at: 2026-01-11T14:08:47Z
-parent: sendou.ink-6eko
----
-
-## Summary
-
-Deprecate and remove the /u page. The /u page is a user search page that should be replaced by the CommandPalette search modal.
-
-## Approach
-
-Add URL search params to CommandPalette to allow opening it via a direct link:
-- `?search=open` - opens the CommandPalette modal
-- `?q=` - pre-fills the search query
-- `?type=users|teams|organizations|tournaments` - sets the search type
-
-Then redirect /u to /?search=open&type=users (preserving any existing `q` param).
-
-## Files involved
-
-- `app/components/layout/CommandPalette.tsx` - add search param support
-- `app/features/user-search/routes/u.tsx` - replace with redirect
-- `app/features/user-search/loaders/u.server.ts` - can be removed
-- `routes.ts` - update route to use redirect
-- navIconUrl (png and avif files)
-
-## Checklist
-
-- [x] Add search param support to CommandPalette (`search`, `q`, `type` params)
-- [x] Update /u route to redirect to /?search=open&type=users
-- [x] Remove unused loader and route components
-- [x] Remove any reference to u navIcon including breadcrumbs
-- [x] Remove from nav (was not in nav)
-- [ ] Test the redirect works correctly
-- [x] Run checks to ensure everything passes
-
-## Additional changes
-
-- Updated `UserSearch` component to use `/search` API instead of `/u`
-- Removed `USER_SEARCH_PAGE` constant from urls.ts
-- Removed "u" nav item from `nav-items.ts` and `TopNavMenus.tsx`
diff --git a/.beans/sendou.ink-ja9h--show-all-notifications-link-doesnt-close-menu-on-m.md b/.beans/sendou.ink-ja9h--show-all-notifications-link-doesnt-close-menu-on-m.md
deleted file mode 100644
index dfb45aeae..000000000
--- a/.beans/sendou.ink-ja9h--show-all-notifications-link-doesnt-close-menu-on-m.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-# sendou.ink-ja9h
-title: Show all notifications link doesn't close menu on mobile
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T19:22:01Z
-updated_at: 2026-01-12T15:32:45Z
-parent: sendou.ink-6eko
----
-
-On mobile, clicking the 'Show all notifications' link navigates to the notifications page in the background but doesn't close the menu/popover.
-
-The menu should close when the page navigates.
\ No newline at end of file
diff --git a/.beans/sendou.ink-jesq--move-front-page-data-back-to-front-page-loader.md b/.beans/sendou.ink-jesq--move-front-page-data-back-to-front-page-loader.md
deleted file mode 100644
index 40092584f..000000000
--- a/.beans/sendou.ink-jesq--move-front-page-data-back-to-front-page-loader.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-# sendou.ink-jesq
-title: Move front page data back to front page loader
-status: todo
-type: task
-created_at: 2026-01-25T12:05:14Z
-updated_at: 2026-01-25T12:05:14Z
-parent: sendou.ink-6eko
----
-
-The commit 131fa699f moved front page specific data loading (ShowcaseTournaments.frontPageTournamentsByUserId, changelog, leaderboards) into root.tsx loader as part of the sidenav rework.
-
-This data should be moved back to the front page loader (_index route) since it's only needed there, not on every page load.
-
-## Context
-- Commit 131fa699f added this to root loader
-- Data includes: tournaments, changelog, leaderboards
-- Currently loaded via Promise.all in root loader
diff --git a/.beans/sendou.ink-jkq9--create-mock-twitch-streams-service-for-development.md b/.beans/sendou.ink-jkq9--create-mock-twitch-streams-service-for-development.md
deleted file mode 100644
index 5ea0b092e..000000000
--- a/.beans/sendou.ink-jkq9--create-mock-twitch-streams-service-for-development.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-# sendou.ink-jkq9
-title: Create mock Twitch streams service for development
-status: todo
-type: task
-created_at: 2026-01-12T12:21:36Z
-updated_at: 2026-01-12T12:21:36Z
-parent: sendou.ink-r6ry
----
-
-Create a mock streams service that simulates Twitch API responses for local development without requiring Twitch credentials.
-
-## Why
-
-- Develop stream features without Twitch API credentials
-- Faster iteration (no network calls)
-- Predictable test data
-- Works offline
-
-## Requirements
-
-- Same interface as real Twitch service (`getStreams()`)
-- Returns realistic mock data (usernames, thumbnails, viewer counts)
-- Configurable: number of streams, online/offline states
-- Easy toggle between mock and real service
-
-## Options to Consider
-
-1. **Simple mock function** - Just return hardcoded data in dev mode
-2. **JSON file** - Load mock data from a JSON file
-3. **json-server** - Separate mock server (may be overkill)
-4. **MSW (Mock Service Worker)** - Intercepts fetch calls (good for tests too)
-
-## Recommendation
-
-Start simple: environment variable toggle + mock function that returns static data.
-
-```typescript
-// /app/modules/twitch/streams.ts
-export async function getStreams() {
- if (process.env.NODE_ENV === "development" && !process.env.TWITCH_CLIENT_ID) {
- return getMockStreams();
- }
- return getRealStreams();
-}
-
-function getMockStreams(): MappedStream[] {
- return [
- { twitchUserName: "sendou", viewerCount: 150, thumbnailUrl: "..." },
- { twitchUserName: "teststreamer1", viewerCount: 89, thumbnailUrl: "..." },
- // ... more mock data
- ];
-}
-```
-
-## Mock Data Should Include
-
-- 5-10 mock streamers with realistic usernames
-- Variety of viewer counts (10 - 500 range)
-- Placeholder thumbnail URLs (or local images)
-- Some usernames matching seeded dev database users (if applicable)
-
-## Checklist
-
-- [ ] Add mock toggle logic to `/app/modules/twitch/streams.ts`
-- [ ] Create mock data with realistic stream info
-- [ ] Ensure mock works when TWITCH_CLIENT_ID is not set
-- [ ] Document in README or .env.example
-- [ ] Consider: sync mock usernames with seed data users
\ No newline at end of file
diff --git a/.beans/sendou.ink-jopf--decide-on-front-page-content-proper-feed-or-restor.md b/.beans/sendou.ink-jopf--decide-on-front-page-content-proper-feed-or-restor.md
deleted file mode 100644
index 9bc839f54..000000000
--- a/.beans/sendou.ink-jopf--decide-on-front-page-content-proper-feed-or-restor.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-# sendou.ink-jopf
-title: 'Decide on front page content: proper feed or restore old layout'
-status: todo
-type: task
-created_at: 2026-01-11T09:47:05Z
-updated_at: 2026-01-11T09:47:05Z
-parent: sendou.ink-6eko
----
-
-## Summary
-
-The front page needs attention - either build out a proper activity feed or restore the previous front page content for now.
-
-## Options
-
-### Option A: Build proper feed
-- Design and implement a real activity feed with relevant content
-- Would include things like: recent tournament results, friend activity, team updates, community highlights
-- More work but provides value
-
-### Option B: Restore old front page
-- Bring back the previous front page content/layout
-- Quick solution to have something meaningful on the homepage
-- Can revisit feed implementation later
-
-## Decision needed
-
-Decide which approach to take based on timeline and priorities.
-
-## Checklist
-
-- [ ] Decide on approach (feed vs restore old)
-- [ ] Implement chosen solution
-- [ ] Test on desktop and mobile
\ No newline at end of file
diff --git a/.beans/sendou.ink-js3r--implement-sidebar-scoring-algorithm.md b/.beans/sendou.ink-js3r--implement-sidebar-scoring-algorithm.md
deleted file mode 100644
index 94257506c..000000000
--- a/.beans/sendou.ink-js3r--implement-sidebar-scoring-algorithm.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-# sendou.ink-js3r
-title: Implement sidebar scoring algorithm
-status: todo
-type: feature
-priority: normal
-created_at: 2026-01-12T09:20:16Z
-updated_at: 2026-01-12T09:21:32Z
-parent: sendou.ink-r6ry
-blocking:
- - sendou.ink-hw3x
----
-
-Create the scoring algorithm that determines which streams appear in the sidebar (top 3).
-
-## Scoring Principles
-
-- Skill-based ranking only (NO viewer count)
-- Configurable weights for easy tuning
-
-## Scoring by Source
-
-### Tournament streams
-- Base: Tournament prestige score (from prestige epic)
-- Bonus: Round progression (later rounds score higher)
-- Fallback until prestige system: Simple heuristics (team count tiers)
-
-### SendouQ streams
-- Score based on tier/peak XP
-- Existing tier logic in /app/features/sendouq-streams/
-
-### Calendar event streams
-- Fixed score (e.g., 500 - tune based on testing)
-- Simple approach for now, can add event-based scoring later
-
-### Non-match streamers
-- Score by peak XP from linked X rank account
-
-## Daily Shuffle
-
-- Seeded random by date (consistent order for the day)
-- Higher skill weighted more heavily
-- Lower skill still has chance to appear
-
-Example algorithm:
-```typescript
-// Seed based on date for consistency
-const seed = dateFns.startOfDay(new Date()).getTime();
-const rng = seedrandom(seed.toString());
-
-// Weighted shuffle: multiply score by random factor
-const shuffled = streams.map(s => ({
- ...s,
- sortScore: s.score * (0.5 + rng() * 0.5) // 50-100% of score
-}));
-shuffled.sort((a, b) => b.sortScore - a.sortScore);
-```
-
-## Checklist
-
-- [ ] Create `scoreStream()` function for individual stream scoring
-- [ ] Create `rankStreams()` function that applies daily shuffle
-- [ ] Define score constants at top of file (easy to tune)
-- [ ] Add tournament fallback scoring (team count tiers until prestige exists)
-- [ ] Add round progression bonus mapping
-- [ ] Test with real data to verify reasonable distribution
-
-## Score Constants (starting point)
-
-```typescript
-const SCORES = {
- // Tournament base by team count
- TOURNAMENT_16_PLUS: 1000,
- TOURNAMENT_8_PLUS: 800,
- TOURNAMENT_SMALL: 600,
-
- // Round bonuses
- ROUND_FINALS: 200,
- ROUND_SEMIS: 150,
- ROUND_QUARTERS: 100,
-
- // Calendar event (fixed)
- CALENDAR_EVENT: 500,
-
- // SendouQ by tier (use existing tier values)
- // Non-match: use peak XP directly (already ~1500-3000 range)
-};
-```
-
-## Implementation Notes
-
-- Make weights configurable (constants at top of file)
-- Document the scoring formula clearly
-- Lives in `/app/features/streams/scoring.server.ts`
-- Consider A/B testing different weight configurations later
\ No newline at end of file
diff --git a/.beans/sendou.ink-kluy--deprecate-trustrelationship-table.md b/.beans/sendou.ink-kluy--deprecate-trustrelationship-table.md
deleted file mode 100644
index e181ff188..000000000
--- a/.beans/sendou.ink-kluy--deprecate-trustrelationship-table.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-# sendou.ink-kluy
-title: Deprecate TrustRelationship table
-status: todo
-type: task
-created_at: 2026-01-13T09:33:39Z
-updated_at: 2026-01-13T09:33:39Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Final cleanup: remove TrustRelationship table after migration is stable.
-
-## Prerequisites
-
-- Migration complete (sendou.ink-vd9w)
-- All trust-dependent features updated (sendou.ink-gdrp)
-- Stable in production for at least 1 week
-
-## Steps
-
-1. Remove TrustRelationship from `app/db/tables.ts`
-2. Create migration to drop table
-3. Remove `app/features/tournament/queries/giveTrust.server.ts`
-4. Remove `app/routines/deleteOldTrusts.ts`
-5. Remove any remaining trust-related code
-6. Update tests
-
-## Checklist
-
-- [ ] Confirm migration stable in production
-- [ ] Remove table definition from tables.ts
-- [ ] Create DROP TABLE migration
-- [ ] Remove giveTrust.server.ts
-- [ ] Remove deleteOldTrusts.ts routine
-- [ ] Search and remove remaining trust code
-- [ ] Update/remove trust-related tests
\ No newline at end of file
diff --git a/.beans/sendou.ink-kp16--map-pool-picker-checkmark-styling-broken-tiebreak.md b/.beans/sendou.ink-kp16--map-pool-picker-checkmark-styling-broken-tiebreak.md
deleted file mode 100644
index dae148182..000000000
--- a/.beans/sendou.ink-kp16--map-pool-picker-checkmark-styling-broken-tiebreak.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-# sendou.ink-kp16
-title: Map pool picker checkmark styling broken & tiebreak text hard to read
-status: todo
-type: bug
-created_at: 2026-01-13T15:13:02Z
-updated_at: 2026-01-13T15:13:02Z
-parent: sendou.ink-1l22
----
-
-## Description
-
-The map pool picker component has two styling issues:
-
-1. **Checkmark styling is broken** - The checkmarks on selected maps (e.g., Inkblot Art Academy, MakoMart) appear to have incorrect styling
-2. **Tiebreak text is hard to read** - The "TIEBREAK" text overlay has poor contrast/readability against the map image background
-
-## Expected behavior
-
-- Checkmarks should have consistent, visible styling that matches the design system
-- Tiebreak text should have sufficient contrast to be easily readable (similar to the "BANNED" text which appears more visible)
\ No newline at end of file
diff --git a/.beans/sendou.ink-kph0--deprecate-qstreams-with-redirect.md b/.beans/sendou.ink-kph0--deprecate-qstreams-with-redirect.md
deleted file mode 100644
index d69279ce9..000000000
--- a/.beans/sendou.ink-kph0--deprecate-qstreams-with-redirect.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# sendou.ink-kph0
-title: Deprecate /q/streams with redirect
-status: todo
-type: task
-created_at: 2026-01-12T09:20:46Z
-updated_at: 2026-01-12T09:20:46Z
-parent: sendou.ink-r6ry
----
-
-Remove the old /q/streams page and redirect to unified /streams page.
-
-## Requirements
-
-- Redirect /q/streams to /streams?source=sendouq
-- Remove link from /q/looking page
-- Keep redirect permanent (301)
-
-## Files to Update
-
-- /app/features/sendouq-streams/routes/q.streams.tsx - convert to redirect
-- /app/features/sendouq/routes/q.looking.tsx - remove streams link
-- routes.ts - may need route changes
-
-## Notes
-
-- Should be done in same release as /streams page launch
-- Preserve any bookmarked URLs via redirect
\ No newline at end of file
diff --git a/.beans/sendou.ink-kvrh--weapon-art-view-all-link-should-support-multiple-t.md b/.beans/sendou.ink-kvrh--weapon-art-view-all-link-should-support-multiple-t.md
deleted file mode 100644
index 936a9292c..000000000
--- a/.beans/sendou.ink-kvrh--weapon-art-view-all-link-should-support-multiple-t.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-# sendou.ink-kvrh
-title: Weapon art 'View all' link should support multiple tag variations
-status: todo
-type: task
-created_at: 2026-01-14T16:01:57Z
-updated_at: 2026-01-14T16:01:57Z
----
-
-The WeaponArtPreview component's 'View all' link currently only links to one tag (the slug with hyphens, e.g. `/art?tag=luna-blaster`). However, the art query searches for multiple tag variations (hyphens, spaces, underscores).
-
-Consider:
-- Updating the art page to support multiple tag filters
-- Or showing all matching tag variations in the link
-- Or consolidating duplicate tags in the database
-
-Related: WeaponArtPreview component in app/features/weapons/components/WeaponArtPreview.tsx
\ No newline at end of file
diff --git a/.beans/sendou.ink-kw6u--show-scrims-in-my-calendar.md b/.beans/sendou.ink-kw6u--show-scrims-in-my-calendar.md
deleted file mode 100644
index ea5e3d789..000000000
--- a/.beans/sendou.ink-kw6u--show-scrims-in-my-calendar.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-# sendou.ink-kw6u
-title: Show scrims in Events
-status: completed
-type: task
-priority: normal
-tags:
- - my-events-epic
-created_at: 2026-01-11T09:44:26Z
-updated_at: 2026-01-13T16:21:09Z
-parent: sendou.ink-6eko
----
-
-## Summary
-
-Display scrims (both scheduled and looking-for-match) in the sidebar's "Events" section.
-
-## Details
-
-The Events section currently shows tournament calendar entries. It should also include:
-
-1. **Scheduled scrims** - Scrims where the user's team has a confirmed match scheduled
-2. **Looking-for-match scrims** - Active scrim postings where user's team is still searching for opponents
-
-This gives competitive players visibility into their upcoming scrim commitments directly from the sidebar, reducing the need to navigate to a separate scrims page.
-
-## Checklist
-
-- [x] Identify where scrim data is fetched/stored
-- [x] Add `findUserScrims` repository function
-- [x] Update sidebar loader to fetch and merge scrims
-- [x] Update Layout component to render scrims with badges
-- [x] Add badge variant to SideNav component
-- [x] Add CSS for "looking" badge variant
-- [x] Add translation keys
-- [x] Test with various scrim states
\ No newline at end of file
diff --git a/.beans/sendou.ink-lk5i--profile-page-friend-button.md b/.beans/sendou.ink-lk5i--profile-page-friend-button.md
deleted file mode 100644
index 6f968428d..000000000
--- a/.beans/sendou.ink-lk5i--profile-page-friend-button.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-# sendou.ink-lk5i
-title: Profile page friend button
-status: todo
-type: task
-created_at: 2026-01-13T09:32:51Z
-updated_at: 2026-01-13T09:32:51Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Add friend request button to user profile pages. IMPORTANT need to be added both to the old user profile and new user profile (widget based).
-
-## Location
-
-`app/features/user-page/routes/u.$identifier.tsx` (or similar profile route)
-
-## States
-
-Button shows different states based on relationship:
-1. **Not friends, no request**: "Add Friend" button → sends request
-2. **Outgoing request pending**: "Request Sent" (disabled or cancel option)
-3. **Incoming request pending**: "Accept Request" / "Decline" buttons
-4. **Already friends**: "Friends ✓" with unfriend option in dropdown
-
-## Implementation
-
-- Check friendship status in loader
-- Check pending requests in both directions
-- Action handler for send/accept/decline/unfriend
-
-## Checklist
-
-- [ ] Add friendship status to profile loader
-- [ ] Friend button component with all states
-- [ ] Action handlers for friend operations
-- [ ] Loading states during actions
-- [ ] Success/error feedback
diff --git a/.beans/sendou.ink-m9lp--friend-checkbox-on-invite-link-join.md b/.beans/sendou.ink-m9lp--friend-checkbox-on-invite-link-join.md
deleted file mode 100644
index e76ffc0ba..000000000
--- a/.beans/sendou.ink-m9lp--friend-checkbox-on-invite-link-join.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-# sendou.ink-m9lp
-title: Friend checkbox on invite link join
-status: todo
-type: task
-created_at: 2026-01-13T09:33:50Z
-updated_at: 2026-01-13T09:33:50Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Update the invite link join flow to offer friending instead of trusting.
-
-## Current Flow
-
-When joining SendouQ group or tournament team via invite link:
-- Checkbox: "Trust [owner name]"
-- If checked, creates TrustRelationship
-
-## New Flow
-
-- Checkbox: "Send friend request to [owner name]"
-- If checked, creates FriendRequest (not immediate friendship)
-- Or if they already sent you a request, accepts it (creates friendship)
-
-## Files
-
-- `app/features/sendouq/actions/q.server.ts` - JOIN_TEAM_WITH_TRUST action
-- `app/features/tournament/actions/to.$id.join.server.ts` - Trust checkbox handling
-- Related UI components for the join forms
-
-## Behavior
-
-1. If not friends and no pending request: create FriendRequest from joiner → owner
-2. If pending request from owner → joiner: accept request, create Friendship
-3. If already friends: no-op
-4. Notification sent to owner
-
-## Checklist
-
-- [ ] Update SendouQ join action
-- [ ] Update tournament join action
-- [ ] Update checkbox labels (i18n)
-- [ ] Handle mutual request → friendship case
-- [ ] Tests for join flow
diff --git a/.beans/sendou.ink-n3wk--rename-mobile-menu-tab-from-calendar-to-avoid-conf.md b/.beans/sendou.ink-n3wk--rename-mobile-menu-tab-from-calendar-to-avoid-conf.md
deleted file mode 100644
index e093bd820..000000000
--- a/.beans/sendou.ink-n3wk--rename-mobile-menu-tab-from-calendar-to-avoid-conf.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-# sendou.ink-n3wk
-title: Rename mobile menu tab from Calendar to avoid confusion
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T09:38:36Z
-updated_at: 2026-01-11T12:48:03Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-On mobile, the bottom tab bar has a calendar icon labeled "Calendar" that opens the menu/navigation modal. This is confusing because there is an actual Calendar page in the app, and users may expect tapping "Calendar" to navigate there.
-
-## Screenshot
-
-The bottom tab shows a calendar icon with "Calendar" label, but it functions as the menu button.
-
-## Expected behavior
-
-The menu tab should have a label that clearly indicates it opens navigation/menu, not the Calendar page.
-
-## Possible solutions
-
-- Rename to "My Calendar" (check if fits)
-
-## Acceptance criteria
-
-- Mobile menu tab label clearly communicates its function
-- No confusion with the actual Calendar page
diff --git a/.beans/sendou.ink-nucy--consistent-avatar-border-radius-in-sidebar.md b/.beans/sendou.ink-nucy--consistent-avatar-border-radius-in-sidebar.md
deleted file mode 100644
index 842c674af..000000000
--- a/.beans/sendou.ink-nucy--consistent-avatar-border-radius-in-sidebar.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-# sendou.ink-nucy
-title: Consistent avatar border radius in sidebar
-status: draft
-type: feature
-created_at: 2026-01-16T09:23:10Z
-updated_at: 2026-01-16T09:23:10Z
----
-
-Currently sidebar avatars have inconsistent border radius styles:
-- Some are fully rounded (circle)
-- Some are slightly rounded
-- Some have no background/different treatment
-
-## Idea
-
-Add a theme option for avatar border radius that applies globally to all avatars:
-- **round** - fully circular (border-radius: 50%)
-- **rounded** - slightly rounded corners
-- **square** - no border radius
-
-This would provide visual consistency and give users control over their preferred avatar style.
-
-## Alternative
-
-Choose one and apply everywhere.
-
-## Areas to check
-- Tournament/event avatars in sidebar
-- Friend list avatars
-- User avatars throughout the app
-- Team avatars
-
-## Checklist
-- [ ] Audit current avatar border radius usage across codebase
-- [ ] Design CSS variable approach for avatar border radius
-- [ ] Add theme option to settings
-- [ ] Apply consistent border radius to all Avatar components
-- [ ] Test across different contexts (sidebar, profiles, etc.)
diff --git a/.beans/sendou.ink-nw8b--implement-stream-aggregation-service.md b/.beans/sendou.ink-nw8b--implement-stream-aggregation-service.md
deleted file mode 100644
index 19d391666..000000000
--- a/.beans/sendou.ink-nw8b--implement-stream-aggregation-service.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-# sendou.ink-nw8b
-title: Implement stream aggregation service
-status: todo
-type: feature
-priority: normal
-created_at: 2026-01-12T09:20:06Z
-updated_at: 2026-01-12T09:21:32Z
-parent: sendou.ink-r6ry
-blocking:
- - sendou.ink-hw3x
----
-
-Create a unified service that combines streams from all sources into a single sorted list.
-
-## Stream Sources
-
-### 1. SendouQ matches
-- Players in active matches who are streaming
-- Existing: `/app/features/sendouq-streams/core/streams.server.ts`
-- Reuse `streamedMatches()` function
-
-### 2. Tournament matches
-- Players/casters streaming tournament matches
-- Existing: `/app/features/tournament/core/streams.server.ts`
-- Reuse `streamsByTournamentId()` function
-- Include round name (e.g., 'Top 8', 'Grand Finals')
-- Group streams of the same match together
-
-### 3. Calendar event streams (new)
-- External events with curator-added stream links
-- Query CalendarEventStream table for upcoming events
-- These are just URLs - may not be live (display "Upcoming" not "LIVE")
-- Soft dependency on sendou.ink-a9gl (can skip if not done yet)
-
-### 4. Non-match streamers (new)
-- Players streaming Splatoon 3 but NOT in SQ/tournament matches
-- **Must have X rank account linked** (SplatoonPlayer with userId set)
-- Sorted by peak XP from X rank data
-- Filter out anyone already appearing in sources 1-2
-
-## Output Type
-
-```typescript
-interface AggregatedStream {
- id: string; // Unique identifier
- name: string; // Display name
- imageUrl: string; // Thumbnail or avatar
- subtitle: string; // Round name, scheduled time, etc.
- badge?: "LIVE" | "UPCOMING"; // Status badge
- source: "sendouq" | "tournament" | "calendar" | "general";
- score: number; // For sorting (from scoring algorithm)
- url: string; // Link to stream
- twitchUsername?: string; // For Twitch embeds
-}
-```
-
-## Checklist
-
-- [ ] Create `/app/features/streams/` folder structure
-- [ ] Create `aggregateStreams()` main function in `streams.server.ts`
-- [ ] Implement SendouQ source adapter
-- [ ] Implement Tournament source adapter
-- [ ] Implement Calendar event source adapter (can be empty initially)
-- [ ] Implement non-match streamers source (users with X rank + Twitch, currently streaming Splatoon 3)
-- [ ] Add type definitions
-- [ ] Add caching strategy (reuse Twitch's 2min cache pattern)
-
-## Implementation Notes
-
-- Create in `/app/features/streams/` (new feature folder)
-- Reuse existing Twitch caching via `/app/modules/twitch/`
-- Call existing stream functions, don't duplicate Twitch API logic
-- Non-match streamers query pattern:
- 1. Get all Splatoon 3 streams from Twitch API
- 2. Get users with `twitchUsername` AND linked `SplatoonPlayer` (X rank data)
- 3. Match streams to users
- 4. Filter out those already in SQ/tournament streams
- 5. Sort by peak XP
diff --git a/.beans/sendou.ink-o3l0--improve-notifications-popover-top-bar-styling.md b/.beans/sendou.ink-o3l0--improve-notifications-popover-top-bar-styling.md
deleted file mode 100644
index dbd158a24..000000000
--- a/.beans/sendou.ink-o3l0--improve-notifications-popover-top-bar-styling.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-# sendou.ink-o3l0
-title: Improve notifications popover top bar styling
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-11T11:51:53Z
-updated_at: 2026-01-11T11:51:53Z
-parent: sendou.ink-1l22
----
-
-The notifications popover top bar has styling issues:
-
-1. **Lacks padding** - The header area needs proper padding for visual balance
-2. **Refresh icon too large** - The refresh/reload icon appears oversized compared to the title text
-
-## Checklist
-
-- [ ] Add appropriate padding to the top bar header
-- [ ] Reduce the size of the refresh icon to match the title text better
\ No newline at end of file
diff --git a/.beans/sendou.ink-oiw2--my-calendar-navigation-links.md b/.beans/sendou.ink-oiw2--my-calendar-navigation-links.md
deleted file mode 100644
index ac3948fe9..000000000
--- a/.beans/sendou.ink-oiw2--my-calendar-navigation-links.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-# sendou.ink-oiw2
-title: My Events navigation links
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-11T11:45:36Z
-updated_at: 2026-01-11T12:50:48Z
-parent: sendou.ink-om3i
----
-
-## Summary
-
-Add links to My Events page in sidebar (desktop) and mobile menu.
-
-## Details
-
-**Desktop sidebar:**
-- Add "My Events" link
-- Placement TBD (near existing Calendar link?)
-- Only show when logged in
-
-**Mobile menu:**
-- Add "My Events" link in appropriate location
-- Only show when logged in
-
-## Checklist
-
-- [ ] Add My Events link to desktop sidebar
-- [ ] Add My Events link to mobile menu
-- [ ] Ensure links only appear when authenticated
-- [ ] Add translations for link text
\ No newline at end of file
diff --git a/.beans/sendou.ink-om3i--my-calendar-page.md b/.beans/sendou.ink-om3i--my-calendar-page.md
deleted file mode 100644
index 8e125df90..000000000
--- a/.beans/sendou.ink-om3i--my-calendar-page.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-# sendou.ink-om3i
-title: My Events page
-status: todo
-type: epic
-priority: normal
-created_at: 2026-01-11T09:45:51Z
-updated_at: 2026-01-11T12:55:40Z
-blocking:
- - sendou.ink-u4ag
----
-
-## Summary
-
-A dedicated page (`/my-events`) for viewing the user's personal events with all their upcoming commitments in one centralized view.
-
-## Why
-
-Users struggle to see all their commitments (tournaments, scrims) in one place. While the sidebar shows a quick glance, players need a full page view to see their complete schedule.
-
-## Scope (Initial)
-
-**Must have:**
-- Tournaments user is registered for
-- Tournaments user is organizing
-- Scrims (scheduled matches)
-- Scrims (looking-for-match posts)
-
-**Future consideration:**
-- SendouQ sessions
-- Team practice times
-- External calendar integration (Google, etc.)
-
-## Design
-
-**View format:** Simple list view, grouped by day (chronological)
-
-**Event card info:**
-- Name (tournament name or scrim opponent)
-- Time
-- Status
-- Check-in window (for tournaments, e.g. "Check-in opens in 2 hours")
-- Handle two-day tournaments appropriately
-
-**Time range:** All upcoming events only, no past events
-
-**Interaction:** Clicking an event navigates directly to the tournament/scrim page
-
-**URL:** `/my-events` (login required)
-
-**Empty state:** Simple message ("No upcoming events") with links to /calendar and /scrims
-
-**iCal export:** Support .ics file export for subscribing in external calendars (similar to existing /calendar feature)
-
-## Technical Notes
-
-- Share components and data fetching logic with sidebar "Events" section
-- Related tasks: `sendou.ink-kw6u` (scrims in sidebar), `sendou.ink-1kb8` (times on mobile panel)
-
-## Navigation
-
-- Add link to sidebar (desktop)
-- Add link to mobile menu
-
-## Completion Criteria
-
-All child tasks resolved.
\ No newline at end of file
diff --git a/.beans/sendou.ink-p9v1--create-npm-script-to-sync-weapon-params-from-leann.md b/.beans/sendou.ink-p9v1--create-npm-script-to-sync-weapon-params-from-leann.md
deleted file mode 100644
index 2b780323e..000000000
--- a/.beans/sendou.ink-p9v1--create-npm-script-to-sync-weapon-params-from-leann.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-# sendou.ink-p9v1
-title: Create npm script to sync weapon params from Leanny/splat3
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T12:22:15Z
-updated_at: 2026-01-13T12:04:46Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create an npm script (`npm run sync-weapon-params`) that fetches weapon parameter data from https://github.com/Leanny/splat3 and transforms it into sendou.ink's format.
-
-## Output Format
-
-JSON files stored in the repo. For parameters that changed across patches, use patch-keyed format:
-
-```json
-{
- "damage": 36,
- "damage@5.0.0": 32,
- "damage@4.0.0": 30,
- "range": 50
-}
-```
-
-- Plain key = current value
-- `key@patch` = historical value from that patch
-
-## Requirements
-
-- Fetch data from Leanny's repo (all weapon categories)
-- Track patch history by comparing versions
-- Output one JSON file per weapon or per category (TBD based on Leanny's structure)
-- Store in appropriate location (e.g., `app/features/weapons/data/`)
-
-## Technical Notes
-
-- Examine Leanny's repo structure to understand data format
-- Script should be idempotent - running multiple times produces same result
-- Consider storing patch metadata (dates) separately
\ No newline at end of file
diff --git a/.beans/sendou.ink-pspr--unit-test-sidenav-data-loading.md b/.beans/sendou.ink-pspr--unit-test-sidenav-data-loading.md
deleted file mode 100644
index 2fb86ef60..000000000
--- a/.beans/sendou.ink-pspr--unit-test-sidenav-data-loading.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-pspr
-title: Unit test sidenav data loading
-status: todo
-type: task
-created_at: 2026-01-11T12:28:34Z
-updated_at: 2026-01-11T12:28:34Z
-parent: sendou.ink-6eko
----
-
-Write Vitest unit tests for sidenav data loading logic including loader functions and data transformations.
\ No newline at end of file
diff --git a/.beans/sendou.ink-qu4s--show-team-and-association-members-in-friends-secti.md b/.beans/sendou.ink-qu4s--show-team-and-association-members-in-friends-secti.md
deleted file mode 100644
index ae8eec2b3..000000000
--- a/.beans/sendou.ink-qu4s--show-team-and-association-members-in-friends-secti.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-# sendou.ink-qu4s
-title: Show team and association members in friends section
-status: todo
-type: feature
-created_at: 2026-01-16T10:20:57Z
-updated_at: 2026-01-16T10:20:57Z
-parent: sendou.ink-255r
----
-
-Extend the friends section in the sidebar to also display:
-- Team members (from the user's team)
-- Association members (from the user's association)
-
-## Sorting priority
-Friends should appear first in the list, followed by team members, then association members.
-
-## Checklist
-- [ ] Query team members for the current user
-- [ ] Query association members for the current user
-- [ ] Combine friends, team members, and association members into a single list
-- [ ] Implement sorting logic: friends first, then team, then association
-- [ ] Handle duplicate entries (e.g., a friend who is also a team member should only appear once, as a friend)
-- [ ] Update sidebar UI to display the combined list
\ No newline at end of file
diff --git a/.beans/sendou.ink-qwz1--fix-admin-page-input-widths.md b/.beans/sendou.ink-qwz1--fix-admin-page-input-widths.md
deleted file mode 100644
index 2986bd07b..000000000
--- a/.beans/sendou.ink-qwz1--fix-admin-page-input-widths.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-# sendou.ink-qwz1
-title: Fix admin page input widths
-status: draft
-type: task
-created_at: 2026-01-11T12:59:32Z
-updated_at: 2026-01-11T12:59:32Z
-parent: sendou.ink-1l22
----
-
-The admin page has inconsistent input widths - some inputs extend too wide while others are narrow (like the User dropdowns).
-
-**Note:** With the incoming form rework, we might do a bigger overhaul of the admin UI anyway. This task may become part of that larger effort.
-
-## Context
-- "Impersonate user" text input stretches full width
-- "Link player" User dropdown is very narrow compared to the Player ID input
-- "Add as artist" and "Give video adder" User dropdowns are also narrow
-- Overall form layout could be more consistent
\ No newline at end of file
diff --git a/.beans/sendou.ink-r6ry--streams-integration-in-sidebar.md b/.beans/sendou.ink-r6ry--streams-integration-in-sidebar.md
deleted file mode 100644
index a1ce96170..000000000
--- a/.beans/sendou.ink-r6ry--streams-integration-in-sidebar.md
+++ /dev/null
@@ -1,160 +0,0 @@
----
-# sendou.ink-r6ry
-title: Streams integration in sidebar
-status: todo
-type: epic
-priority: normal
-created_at: 2026-01-11T09:18:00Z
-updated_at: 2026-01-12T08:49:38Z
----
-
-Unified streams experience across sendou.ink - displaying live and upcoming Splatoon community streams in the sidebar, mobile menu, and a dedicated /streams page.
-
-## Goals
-
-1. Surface live community streams prominently in the sidebar/mobile menu
-2. Create a central `/streams` page for browsing all current and upcoming streams
-3. Unify SendouQ, tournament, and community event streams under one system
-4. Deprecate fragmented stream pages (`/q/streams`, `/to/:id/streams`)
-
-## Stream Sources
-
-### 1. SendouQ Matches
-- Players in active SendouQ matches who are streaming
-- Scoring based on tier/peak XP
-- Already implemented in `/app/features/sendouq-streams/`
-
-### 2. Tournament Matches
-- Players/casters streaming tournament matches
-- Scoring based on tournament prestige (separate epic) + round progression
-- Round names should be visible (e.g., "Top 8", "Grand Finals")
-- Streams of the same match should be visually grouped
-- Already partially implemented in `/app/features/tournament/core/streams.server.ts`
-
-### 3. Calendar Event Streams (New)
-- External events (e.g., LANs) not hosted on sendou.ink
-- Requires new `STREAM_CURATOR` role (granted by staff)
-- Curators can only add stream links to events they created
-- Stream links are platform-agnostic URLs (Twitch, YouTube, etc.)
-- New CalendarEventStream join table for multiple links per event
-
-### 4. Non-Match Streamers
-- Players streaming Splatoon but not in SQ/tournament
-- Must have X rank account linked
-- Sorted by peak XP
-
-## Sidebar & Mobile Menu
-
-### Display
-- Show top 3 streams (constant, easy to change later)
-- Use existing SideNavLink format:
- - Image (thumbnail/logo)
- - Name (tournament/streamer name)
- - Subtitle (round name, or scheduled time for upcoming)
- - Badge ("LIVE" indicator)
-- Link to `/streams` page
-
-### Scoring Algorithm
-- Skill-based ranking only (no viewer count)
-- Configurable weights for easy tuning:
- - Tournament: prestige score + round progression bonus (fallback: team count tiers)
- - SendouQ: tier/peak XP
- - Calendar events: Fixed score (simple for now)
- - Non-match streamers: peak XP
-- Daily shuffle with bias toward higher score
- - Seeded random by date so order is consistent for the day
- - Higher scores weighted more heavily but lower scores still have chance to appear
-
-### Update Strategy
-- Separate task exists for defining sidebar data update strategy (sendou.ink-wn5o)
-
-## /streams Page
-
-### Layout
-- Two sections: Current/Live streams and Upcoming streams
-- Desktop: potentially two-column layout (TBD in design phase)
-- Option to view merged list or grouped by source (SQ/Tournaments/Events)
-
-### Current/Live Section
-- All active streams from all sources
-- Tournament streams sorted by round, grouped by match
-- Multiple tournaments interleaved by prestige/round score
-
-### Upcoming Section
-- Calendar events with attached stream info
-- Tournaments with known start times
-- Future: scheduled league matches
-
-### Twitch Embeds
-- Clicking a stream expands inline embed (accordion style)
-- Multiple embeds can be open simultaneously
-- Optional chat toggle alongside video
-
-## Deprecations (Same Release)
-
-### /q/streams
-- Redirect to `/streams?source=sendouq`
-- Remove link from `/q/looking` page
-
-### /to/:id/streams
-- Redirect to `/streams?tournament=:id` (or similar filter)
-- Tournament bracket LIVE popovers retain current behavior (no change)
-
-## New Permissions
-
-### STREAM_CURATOR Role
-- New role in existing permissions system
-- Granted by staff (same flow as "is artist" role)
-- Allows adding stream links to calendar events user created
-- Scoped to own events only
-- Database: `isStreamCurator` boolean column on User table
-
-## Dependencies
-
-- **sendou.ink-ylq5 - Tournament Prestige System**: Algorithm for calculating tournament prestige based on registered players' seeding power. Streams epic can start with simple heuristics (e.g., team count tiers) until prestige system is built. (soft dependency - can proceed without)
-
-## Data Model Changes
-
-### New Table: CalendarEventStream
-- Join table for calendar event stream links
-- Columns: id, calendarEventId, url
-- Supports multiple stream links per event (Twitch, YouTube, etc.)
-
-### User Table
-- Add `isStreamCurator` boolean column (like `isArtist`)
-
-## Technical Notes
-
-### Existing Infrastructure
-- Twitch API integration exists (`/app/modules/twitch/`)
-- Stream caching with 2-min cache, 10-min stale-while-revalidate
-- SendouQ streams logic in `/app/features/sendouq-streams/`
-- Tournament streams logic in `/app/features/tournament/core/streams.server.ts`
-
-### Sidebar Integration
-- Current mock data in `/app/features/sidebar/routes/sidebar.ts`
-- Replace `getMockStreams()` with real stream aggregation
-
-## Open Questions (To Resolve During Implementation)
-
-1. ~~Calendar event stream scoring weight~~ → Fixed score (resolved)
-2. Exact layout for /streams page (start simple, iterate)
-3. Visual design for tournament match grouping
-4. Round ordering: progression order (R1→Finals) or reverse (Finals first)?
-5. Cross-tournament interleaving vs grouping by tournament
-
-## Child Tasks
-
-All child tasks have been created as separate tickets under this epic:
-
-- sendou.ink-9cpl: Create /streams page route and basic layout
-- sendou.ink-nw8b: Implement stream aggregation service
-- sendou.ink-js3r: Implement sidebar scoring algorithm
-- sendou.ink-4m0t: Add STREAM_CURATOR role to permissions
-- sendou.ink-a9gl: Add Twitch channel field to CalendarEvent
-- sendou.ink-x535: Add stream curator UI for calendar events
-- sendou.ink-r717: Implement Twitch embed component with chat toggle
-- sendou.ink-kph0: Deprecate /q/streams with redirect
-- sendou.ink-u6b2: Deprecate /to/:id/streams with redirect
-- sendou.ink-hw3x: Update sidebar to use real stream data
-- sendou.ink-ae15: Add /streams link to sidebar and mobile menu
diff --git a/.beans/sendou.ink-r717--implement-twitch-embed-component-with-chat-toggle.md b/.beans/sendou.ink-r717--implement-twitch-embed-component-with-chat-toggle.md
deleted file mode 100644
index 16b0ff3c6..000000000
--- a/.beans/sendou.ink-r717--implement-twitch-embed-component-with-chat-toggle.md
+++ /dev/null
@@ -1,90 +0,0 @@
----
-# sendou.ink-r717
-title: Implement Twitch embed component with chat toggle
-status: todo
-type: feature
-created_at: 2026-01-12T09:20:45Z
-updated_at: 2026-01-12T09:20:45Z
-parent: sendou.ink-r6ry
----
-
-Create reusable Twitch embed component for the /streams page.
-
-## Requirements
-
-- Clicking a stream expands inline embed (accordion style)
-- Multiple embeds can be open simultaneously
-- Optional chat toggle alongside video
-- Responsive sizing (16:9 aspect ratio)
-
-## Checklist
-
-- [ ] Create `/app/components/TwitchEmbed.tsx` component
-- [ ] Implement video-only embed mode
-- [ ] Implement video + chat side-by-side mode
-- [ ] Add chat toggle button
-- [ ] Save chat preference to localStorage (`twitch-chat-enabled`)
-- [ ] Handle parent domain from `VITE_SITE_DOMAIN` env var
-- [ ] Add loading state while iframe loads
-- [ ] Test on mobile (responsive width)
-
-## Component API
-
-```tsx
-interface TwitchEmbedProps {
- channel: string; // Twitch username
- showChat?: boolean; // Default from localStorage
- onChatToggle?: (show: boolean) => void;
-}
-
-// Usage
-
-```
-
-## Twitch Embed URL Format
-
-```
-Video only:
-https://player.twitch.tv/?channel={channel}&parent={domain}&muted=false
-
-Chat only:
-https://www.twitch.tv/embed/{channel}/chat?parent={domain}
-```
-
-## Parent Domain
-
-Twitch requires the `parent` parameter for embeds to work. Use:
-- `import.meta.env.VITE_SITE_DOMAIN` (strips protocol)
-- Parse hostname: `new URL(VITE_SITE_DOMAIN).hostname`
-- For localhost: `localhost`
-- For production: `sendou.ink`
-
-## Layout
-
-```
-Desktop with chat:
-┌──────────────────────┬──────────┐
-│ │ │
-│ Video (16:9) │ Chat │
-│ │ (300px) │
-│ │ │
-└──────────────────────┴──────────┘
-
-Mobile (video only, full width):
-┌──────────────────────────────────┐
-│ │
-│ Video (16:9) │
-│ │
-└──────────────────────────────────┘
-```
-
-## Performance Notes
-
-- Use lazy loading: only load iframe when expanded
-- Consider max 3 simultaneous embeds (optional limit)
-- iframes are heavy - show placeholder/thumbnail when collapsed
-
-## References
-
-- Twitch embed docs: https://dev.twitch.tv/docs/embed/video-and-clips/
-- Chat embed docs: https://dev.twitch.tv/docs/embed/chat/
diff --git a/.beans/sendou.ink-rbyg--mutual-friends-display.md b/.beans/sendou.ink-rbyg--mutual-friends-display.md
deleted file mode 100644
index 9890e9da1..000000000
--- a/.beans/sendou.ink-rbyg--mutual-friends-display.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-# sendou.ink-rbyg
-title: Mutual friends display
-status: todo
-type: task
-created_at: 2026-01-13T09:32:58Z
-updated_at: 2026-01-13T09:32:58Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Show mutual friends on user profile pages.
-
-## Display
-
-On profile page, show:
-- "X mutual friends" count
-- Preview of 3-5 mutual friend avatars
-- Click to expand/see full list
-
-## Implementation
-
-- `FriendRepository.findMutualFriends(viewerId, profileUserId)`
-- Returns users who are friends with both
-- Count and limited preview in loader
-- Full list modal or expandable section
-
-## Checklist
-
-- [ ] Add mutual friends query to repository
-- [ ] Add to profile page loader
-- [ ] Mutual friends preview component
-- [ ] Full list modal/expansion
-- [ ] Handle zero mutual friends
\ No newline at end of file
diff --git a/.beans/sendou.ink-reks--define-sidebar-loading-behavior.md b/.beans/sendou.ink-reks--define-sidebar-loading-behavior.md
deleted file mode 100644
index ddf4a4e09..000000000
--- a/.beans/sendou.ink-reks--define-sidebar-loading-behavior.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-# sendou.ink-reks
-title: Define sidebar loading behavior
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T09:27:48Z
-updated_at: 2026-01-25T12:08:55Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-Currently the sidebar shows empty/nothing while data loads, making the page appear broken briefly.
-
-## Task
-
-Define how the sidebar should behave when loading data:
-- Should we show skeleton loaders?
-- Should we show the previous cached data while fetching fresh data?
-- Should we show a loading spinner?
-- What about error states if the fetch fails?
-
-## Current Implementation
-
-- Sidebar uses a fetcher to load data on mount (`app/components/layout/index.tsx`)
-- No loading or error states are shown
-- If fetcher fails, error is silently ignored
\ No newline at end of file
diff --git a/.beans/sendou.ink-s23a--implement-hover-menu-switching.md b/.beans/sendou.ink-s23a--implement-hover-menu-switching.md
deleted file mode 100644
index 0b115ecb2..000000000
--- a/.beans/sendou.ink-s23a--implement-hover-menu-switching.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-# sendou.ink-s23a
-title: Implement hover menu switching
-status: draft
-type: task
-priority: normal
-created_at: 2026-01-11T08:58:55Z
-updated_at: 2026-01-11T19:06:55Z
-parent: sendou.ink-6eko
----
-
-After clicking to open a menu, moving cursor to another menu item should show that menu's items. Menu should close on outside click or Escape key. Location: app/components/layout/TopNavMenus.tsx:14
-
-## Blocked
-
-React Aria Components doesn't make this easy currently. See: https://github.com/adobe/react-spectrum/issues/8905
\ No newline at end of file
diff --git a/.beans/sendou.ink-s83f--restore-sendou-bluepink-and-whitepink-themes.md b/.beans/sendou.ink-s83f--restore-sendou-bluepink-and-whitepink-themes.md
deleted file mode 100644
index 0686b5260..000000000
--- a/.beans/sendou.ink-s83f--restore-sendou-bluepink-and-whitepink-themes.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# sendou.ink-s83f
-title: Restore Sendou blue+pink and white+pink themes
-status: todo
-type: task
-created_at: 2026-01-11T09:49:34Z
-updated_at: 2026-01-11T09:49:34Z
-parent: sendou.ink-1l22
----
-
-## Summary
-
-Re-add the classic Sendou themes for the CSS rework:
-
-1. **Blue + Pink** - The signature Sendou.ink dark theme
-2. **White + Pink** - Light theme variant
-
-## Checklist
-
-- [ ] Define theme CSS variables for blue+pink theme
-- [ ] Define theme CSS variables for white+pink theme
-- [ ] Verify accessibility/contrast requirements are met
diff --git a/.beans/sendou.ink-sb5p--create-recent-vods-preview-component.md b/.beans/sendou.ink-sb5p--create-recent-vods-preview-component.md
deleted file mode 100644
index 08ea3d518..000000000
--- a/.beans/sendou.ink-sb5p--create-recent-vods-preview-component.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-# sendou.ink-sb5p
-title: Create recent vods preview component
-status: todo
-type: task
-created_at: 2026-01-11T12:22:34Z
-updated_at: 2026-01-11T12:22:34Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create a React component that displays 5 recent VODs for a weapon.
-
-## Features
-
-- Show 5 most recent VODs featuring the weapon
-- Each VOD shows: thumbnail, title, date, player(s)
-- "View all" link to `/vods?weapon={weaponId}`
-
-## Data Source
-
-- `VodRepository.findVods()` with weapon filter
-- Includes alt skins/kits via `weaponIdToArrayWithAlts()`
-
-## Props
-
-- `vods` - array of 5 vod objects
-- `weaponId` - for "view all" link
-
-## Technical Notes
-
-- Reuse existing VOD display components if available (`VodListing`)
diff --git a/.beans/sendou.ink-sonu--e2e-test-desktop-sidenav.md b/.beans/sendou.ink-sonu--e2e-test-desktop-sidenav.md
deleted file mode 100644
index 0174023f9..000000000
--- a/.beans/sendou.ink-sonu--e2e-test-desktop-sidenav.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-sonu
-title: E2E test desktop sidenav
-status: todo
-type: task
-created_at: 2026-01-11T12:28:33Z
-updated_at: 2026-01-11T12:28:33Z
-parent: sendou.ink-6eko
----
-
-Write Playwright E2E tests for the desktop sidenav functionality including navigation, collapsing, and user interactions.
\ No newline at end of file
diff --git a/.beans/sendou.ink-svz2--inline-function-in-notificationpopover.md b/.beans/sendou.ink-svz2--inline-function-in-notificationpopover.md
deleted file mode 100644
index b1233795c..000000000
--- a/.beans/sendou.ink-svz2--inline-function-in-notificationpopover.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-# sendou.ink-svz2
-title: Inline function in NotificationPopover
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T08:58:55Z
-updated_at: 2026-01-11T12:41:51Z
-parent: sendou.ink-6eko
----
-
-Refactor NotificationPopover by inlining the separate function that makes no sense as standalone. Location: app/components/layout/NotificationPopover.tsx:40
\ No newline at end of file
diff --git a/.beans/sendou.ink-takt--mobile-menu-doesnt-block-background-scrolling.md b/.beans/sendou.ink-takt--mobile-menu-doesnt-block-background-scrolling.md
deleted file mode 100644
index bd53cf0eb..000000000
--- a/.beans/sendou.ink-takt--mobile-menu-doesnt-block-background-scrolling.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-# sendou.ink-takt
-title: Mobile menu doesn't block background scrolling
-status: todo
-type: bug
-created_at: 2026-01-11T18:39:55Z
-updated_at: 2026-01-11T18:39:55Z
-parent: sendou.ink-1l22
----
-
-The mobile menu doesn't actually block scrolling the container when open. This might be a bug with our react-aria components scroll lock workaround.
-
-## Context
-- Mobile menu should prevent background content from scrolling when open
-- Current react-aria scroll lock implementation may not be working correctly
-
-## Investigation needed
-- Check the current scroll lock workaround implementation
-- Verify if this is a react-aria issue or our custom code
-- Test on different mobile browsers
\ No newline at end of file
diff --git a/.beans/sendou.ink-tnjk--rewrite-weapon-page-ui.md b/.beans/sendou.ink-tnjk--rewrite-weapon-page-ui.md
deleted file mode 100644
index ab934ed6d..000000000
--- a/.beans/sendou.ink-tnjk--rewrite-weapon-page-ui.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-# sendou.ink-tnjk
-title: Rewrite weapon page UI
-status: todo
-type: task
-created_at: 2026-01-11T12:23:05Z
-updated_at: 2026-01-11T12:23:05Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Replace the existing placeholder weapon page with the new design using all created components.
-
-## Components to Integrate
-
-- Weapon header (image, name)
-- Stats summary (top XP holder, popularity)
-- Quick links
-- Parameter comparison table
-- Recent vods preview (5)
-- Popular builds preview (5)
-- Art preview (5)
-
-## Requirements
-
-- Replace existing `/app/features/weapons/routes/weapons.$slug.tsx`
-- Well-componentized - each section in its own component for easy reordering
-- Use CSS modules for styling
-- Responsive design (desktop + mobile)
-
-## Technical Notes
-
-- Import data from rewritten loader
-- Each section component receives props from loader data
-- Handle empty states gracefully (e.g., "No art tagged for this weapon yet")
-- Order of sections can be adjusted later - keep components decoupled
\ No newline at end of file
diff --git a/.beans/sendou.ink-tq5i--fix-bracket-lines-and-match-timer-color-contrast.md b/.beans/sendou.ink-tq5i--fix-bracket-lines-and-match-timer-color-contrast.md
deleted file mode 100644
index c5b8084b0..000000000
--- a/.beans/sendou.ink-tq5i--fix-bracket-lines-and-match-timer-color-contrast.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-# sendou.ink-tq5i
-title: Fix bracket lines and match timer color contrast
-status: todo
-type: bug
-created_at: 2026-01-11T09:36:11Z
-updated_at: 2026-01-11T09:36:11Z
-parent: sendou.ink-1l22
----
-
-## Problem
-
-On the tournament bracket page, the bracket connector lines and match timer badge blend together because they use the same or very similar colors. This makes it difficult to visually distinguish the timer from the bracket structure.
-
-## Screenshot
-
-The timer showing "0m" and the bracket lines are both a similar gray/muted color, reducing visual clarity.
-
-## Expected behavior
-
-The bracket lines and match timer should have distinct colors so they're easily distinguishable at a glance.
-
-## Acceptance criteria
-
-- Bracket connector lines and match timer have sufficient color contrast between them
-- Both elements remain accessible and readable
-- Fits within the new CSS variable system in `vars.css`
\ No newline at end of file
diff --git a/.beans/sendou.ink-u4ag--my-events-future-work.md b/.beans/sendou.ink-u4ag--my-events-future-work.md
deleted file mode 100644
index 609c4fbc2..000000000
--- a/.beans/sendou.ink-u4ag--my-events-future-work.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-# sendou.ink-u4ag
-title: My events future work
-status: draft
-type: epic
-created_at: 2026-01-11T12:55:35Z
-updated_at: 2026-01-11T12:55:35Z
----
-
-Future enhancements for the My Events page after initial implementation is complete.
\ No newline at end of file
diff --git a/.beans/sendou.ink-u6b2--deprecate-toidstreams-with-redirect.md b/.beans/sendou.ink-u6b2--deprecate-toidstreams-with-redirect.md
deleted file mode 100644
index 41ebad0fb..000000000
--- a/.beans/sendou.ink-u6b2--deprecate-toidstreams-with-redirect.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-# sendou.ink-u6b2
-title: Deprecate /to/:id/streams with redirect
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-12T09:20:46Z
-updated_at: 2026-01-12T12:07:11Z
-parent: sendou.ink-r6ry
----
-
-Remove the old tournament streams page and redirect to unified /streams page.
-
-## Requirements
-
-- Redirect /to/:id/streams to /streams?tournament=:id (or similar filter)
-- Tournament bracket LIVE popovers retain current behavior (no change)
-- Keep redirect permanent (301)
-
-## Files to Update
-
-- /app/features/tournament/routes/to.$id.streams.tsx - convert to redirect
-- routes.ts - may need route changes
-
-## Notes
-
-- Should be done in same release as /streams page launch
-- Preserve any bookmarked URLs via redirect
-- Bracket popover behavior is separate and unchanged
\ No newline at end of file
diff --git a/.beans/sendou.ink-utog--update-user-pickable-themes-to-use-new-css-vars.md b/.beans/sendou.ink-utog--update-user-pickable-themes-to-use-new-css-vars.md
deleted file mode 100644
index a4800b60e..000000000
--- a/.beans/sendou.ink-utog--update-user-pickable-themes-to-use-new-css-vars.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-# sendou.ink-utog
-title: Update user-pickable themes to use new CSS vars
-status: todo
-type: task
-created_at: 2026-01-11T09:49:34Z
-updated_at: 2026-01-11T09:49:34Z
-parent: sendou.ink-1l22
----
-
-## Summary
-
-User profile pages and team pages allow custom theme colors. These need to be updated to work with the new CSS variable system from the CSS rework.
-
-## Affected areas
-
-- **User pages** - Profile customization with user-selected colors
-- **Team pages** - Team branding colors
-
-## Checklist
-
-- [ ] Audit current user theme implementation
-- [ ] Map old theme values to new CSS variable system
-- [ ] Update user page theme application logic
-- [ ] Update team page theme application logic
-- [ ] Test custom themes don't break with new CSS structure
-- [ ] Ensure theme picker UI works correctly
\ No newline at end of file
diff --git a/.beans/sendou.ink-uvge--create-weapon-quick-links-component.md b/.beans/sendou.ink-uvge--create-weapon-quick-links-component.md
deleted file mode 100644
index b07571590..000000000
--- a/.beans/sendou.ink-uvge--create-weapon-quick-links-component.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-# sendou.ink-uvge
-title: Create weapon quick links component
-status: todo
-type: task
-created_at: 2026-01-11T12:22:54Z
-updated_at: 2026-01-11T12:22:54Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create a React component that displays quick links to related pages.
-
-## Links to Include
-
-- **Builds** - `/builds/{weaponSlug}`
-- **Popular Builds** - `/builds/{weaponSlug}/popular`
-- **Ability Stats** - `/builds/{weaponSlug}/stats`
-- **VODs** - `/vods?weapon={weaponId}`
-- **Build Analyzer** - `/analyzer` (with weapon pre-selected if possible)
-- **Object Damage Calculator** - `/object-damage-calculator`
-- **Free Agents** - Link to SendouQ looking page filtered by weapon
-- **Leaderboard** - `/leaderboards?type=XP-WEAPON-{weaponId}` (shown with top XP holder)
-
-## Props
-
-- `weaponSlug`
-- `weaponId`
-
-## Technical Notes
-
-- Use existing `LinkButton` component
-- Appropriate icons for each link (existing icons in codebase)
-- Some links may be grouped with related features (e.g., leaderboard with stats summary)
\ No newline at end of file
diff --git a/.beans/sendou.ink-v42i--check-brackets-ui-design.md b/.beans/sendou.ink-v42i--check-brackets-ui-design.md
deleted file mode 100644
index 653bd087d..000000000
--- a/.beans/sendou.ink-v42i--check-brackets-ui-design.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-# sendou.ink-v42i
-title: Check brackets UI design
-status: todo
-type: task
-created_at: 2026-01-11T12:34:21Z
-updated_at: 2026-01-11T12:34:21Z
-parent: sendou.ink-6eko
----
-
-## Description
-
-Review the brackets UI and decide on design questions:
-
-## Checklist
-
-- [ ] Should tabs (Main/Underground) be "attached" to brackets outline?
-- [ ] Should "Add sub" link to a different page?
-- [ ] Compactify button restyle needed?
-- [ ] Do we need "Go to match" button when match info is already in the sidebar?
diff --git a/.beans/sendou.ink-vbbi--rewrite-weapon-page-loader.md b/.beans/sendou.ink-vbbi--rewrite-weapon-page-loader.md
deleted file mode 100644
index aacae4c73..000000000
--- a/.beans/sendou.ink-vbbi--rewrite-weapon-page-loader.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-# sendou.ink-vbbi
-title: Rewrite weapon page loader
-status: todo
-type: task
-created_at: 2026-01-11T12:22:54Z
-updated_at: 2026-01-11T12:22:54Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Rewrite the loader for `/weapons/:slug` to fetch all data needed for the new weapon page.
-
-## Data to Fetch
-
-All in a single loader:
-
-1. **Weapon info** - ID, name, slug, category (existing)
-2. **Weapon params** - From JSON files, including patch history
-3. **Category weapons** - All weapons in same category for comparison table
-4. **Top XP holder** - From `weaponXPLeaderboard(weaponId)`
-5. **Popularity stats** - Overall rank + category rank from XRankPlacement
-6. **Recent vods** - 5 most recent from `VodRepository.findVods()`
-7. **Popular builds** - 5 most popular from BuildRepository
-8. **Art by tag** - 5 art pieces tagged with weapon slug
-
-## Location
-
-`/app/features/weapons/loaders/weapons.$slug.server.ts`
-
-## Technical Notes
-
-- Use Promise.all for parallel DB queries where possible
-- Consider caching for expensive queries
-- Handle missing data gracefully (e.g., no art tagged yet)
\ No newline at end of file
diff --git a/.beans/sendou.ink-vd9w--migration-from-trust-to-friendship.md b/.beans/sendou.ink-vd9w--migration-from-trust-to-friendship.md
deleted file mode 100644
index 5a65a5d8e..000000000
--- a/.beans/sendou.ink-vd9w--migration-from-trust-to-friendship.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-# sendou.ink-vd9w
-title: Migration from trust to friendship
-status: todo
-type: task
-created_at: 2026-01-13T09:33:20Z
-updated_at: 2026-01-13T09:33:20Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Migrate existing TrustRelationship data to new Friendship system.
-
-## Migration Logic
-
-```sql
--- Find mutual trusts (A trusts B AND B trusts A)
--- Convert to friendships
-
-INSERT INTO Friendship (userOneId, userTwoId, createdAt)
-SELECT
- CASE WHEN t1.trustGiverUserId < t1.trustReceiverUserId
- THEN t1.trustGiverUserId
- ELSE t1.trustReceiverUserId END,
- CASE WHEN t1.trustGiverUserId < t1.trustReceiverUserId
- THEN t1.trustReceiverUserId
- ELSE t1.trustGiverUserId END,
- MIN(t1.lastUsedAt)
-FROM TrustRelationship t1
-JOIN TrustRelationship t2
- ON t1.trustGiverUserId = t2.trustReceiverUserId
- AND t1.trustReceiverUserId = t2.trustGiverUserId
-WHERE t1.trustGiverUserId < t1.trustReceiverUserId
-GROUP BY 1, 2;
-
--- Delete all trust relationships (mutual converted, one-way discarded)
-DELETE FROM TrustRelationship;
-```
-
-## Approach
-
-1. Create migration script (not DB migration - one-time data migration)
-2. Run on staging first
-3. Verify friendship counts match expected
-4. Run on production
-5. Keep TrustRelationship table temporarily for rollback
-6. Remove table in later migration after confirming stability
-
-## Checklist
-
-- [ ] Create migration script
-- [ ] Test on development database
-- [ ] Count mutual trusts before migration
-- [ ] Verify friendship count after migration
-- [ ] Test on staging
-- [ ] Run on production
-- [ ] Monitor for issues
\ No newline at end of file
diff --git a/.beans/sendou.ink-vj1n--fix-organizations-icon-in-commandpalette.md b/.beans/sendou.ink-vj1n--fix-organizations-icon-in-commandpalette.md
deleted file mode 100644
index eba7a0ce9..000000000
--- a/.beans/sendou.ink-vj1n--fix-organizations-icon-in-commandpalette.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-# sendou.ink-vj1n
-title: Fix organizations icon in CommandPalette
-status: completed
-type: bug
-priority: normal
-created_at: 2026-01-11T08:58:55Z
-updated_at: 2026-01-11T13:17:39Z
-parent: sendou.ink-6eko
----
-
-The organizations category uses wrong icon. Should use the same icon as AnythingAdder uses for organizations. Location: app/components/layout/CommandPalette.tsx:42
\ No newline at end of file
diff --git a/.beans/sendou.ink-vmid--define-navigation-menu-categories.md b/.beans/sendou.ink-vmid--define-navigation-menu-categories.md
deleted file mode 100644
index 94596b548..000000000
--- a/.beans/sendou.ink-vmid--define-navigation-menu-categories.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-vmid
-title: Define navigation menu categories
-status: todo
-type: task
-created_at: 2026-01-11T08:58:54Z
-updated_at: 2026-01-11T08:58:54Z
-parent: sendou.ink-6eko
----
-
-Replace placeholder categories in TopNavMenus with actual navigation structure. Location: app/components/layout/TopNavMenus.tsx:13
\ No newline at end of file
diff --git a/.beans/sendou.ink-vv5h--create-popular-builds-preview-component.md b/.beans/sendou.ink-vv5h--create-popular-builds-preview-component.md
deleted file mode 100644
index 9ed667424..000000000
--- a/.beans/sendou.ink-vv5h--create-popular-builds-preview-component.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-# sendou.ink-vv5h
-title: Create popular builds preview component
-status: todo
-type: task
-created_at: 2026-01-11T12:22:34Z
-updated_at: 2026-01-11T12:22:34Z
-parent: sendou.ink-0ze4
----
-
-## Summary
-
-Create a React component that displays 5 popular builds for a weapon.
-
-## Features
-
-- Show 5 most popular builds for the weapon
-- Each build shows: abilities, author, stats
-- "View all" link to `/builds/{weaponSlug}/popular`
-
-## Data Source
-
-- `BuildRepository` queries for popular builds
-- Existing popular builds logic in build-stats feature
-
-## Props
-
-- `builds` - array of 5 build objects
-- `weaponSlug` - for "view all" link
-
-## Technical Notes
-
-- Reuse existing `BuildCard` component if suitable
-- May need compact variant for preview display
\ No newline at end of file
diff --git a/.beans/sendou.ink-vzoj--friends-page-implementation.md b/.beans/sendou.ink-vzoj--friends-page-implementation.md
deleted file mode 100644
index 296aecf4c..000000000
--- a/.beans/sendou.ink-vzoj--friends-page-implementation.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-# sendou.ink-vzoj
-title: /friends page implementation
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-13T09:32:40Z
-updated_at: 2026-01-13T11:25:15Z
-parent: sendou.ink-255r
-blocking:
- - sendou.ink-0sk2
----
-
-## Overview
-
-Create the /friends page with full friend management capabilities.
-
-## Route
-
-`app/features/friends/routes/friends.tsx`
-
-Add to routes.ts.
-
-## Sections (grouped, unlike sidebar)
-
-### 1. Pending Requests
-- **Incoming requests**: Show sender info, accept/decline buttons
-- **Outgoing requests**: Show receiver info, cancel button
-- Badge count in section header
-
-### 2. Friends
-- List of explicit friends with activity status
-- Search/filter input
-- Each friend card shows: avatar, name, activity, unfriend option
-- Unfriend requires confirmation modal
-
-### 3. Teammates
-- Grouped by team
-- Show team name as subheader
-- Activity status for each teammate
-- Link to team page
-
-### 4. Connections
-- Association and Plus server members
-- Show association/org name as context
-- Activity status
-
-## Features
-
-- Search across all sections
-- Filter by activity (in SendouQ, in tournament)
-- Responsive layout (grid on desktop, list on mobile)
-- Empty states for each section
-
-## Checklist
-
-- [ ] Create route and add to routes.ts
-- [ ] Loader: fetch requests, friends, teammates, associations
-- [ ] Pending requests section UI
-- [ ] Friends section with management
-- [ ] Teammates section grouped by team
-- [ ] Connections section
-- [ ] Search/filter functionality
-- [ ] Unfriend confirmation modal
-- [ ] Responsive layout
-- [ ] Empty states
-- [ ] i18n translations
\ No newline at end of file
diff --git a/.beans/sendou.ink-w3cs--e2e-test-mobile-sidenav.md b/.beans/sendou.ink-w3cs--e2e-test-mobile-sidenav.md
deleted file mode 100644
index 9c037c40e..000000000
--- a/.beans/sendou.ink-w3cs--e2e-test-mobile-sidenav.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-w3cs
-title: E2E test mobile sidenav
-status: todo
-type: task
-created_at: 2026-01-11T12:28:34Z
-updated_at: 2026-01-11T12:28:34Z
-parent: sendou.ink-6eko
----
-
-Write Playwright E2E tests for the mobile sidenav/tabs functionality including responsive behavior and touch interactions.
\ No newline at end of file
diff --git a/.beans/sendou.ink-wn2f--define-ui-changes-when-sidebar-is-collapsed.md b/.beans/sendou.ink-wn2f--define-ui-changes-when-sidebar-is-collapsed.md
deleted file mode 100644
index bd92ef269..000000000
--- a/.beans/sendou.ink-wn2f--define-ui-changes-when-sidebar-is-collapsed.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# sendou.ink-wn2f
-title: Define UI changes when sidebar is collapsed
-status: draft
-type: task
-created_at: 2026-01-11T12:31:27Z
-updated_at: 2026-01-11T12:31:27Z
----
-
-Evaluate what UI adjustments should be made when the sidebar is in collapsed state.
-
-## Considerations
-
-- Show breadcrumbs for navigation context when sidebar is collapsed
-- Any other contextual information that might be lost when sidebar collapses
-- Mobile vs desktop behavior differences
-
-## Checklist
-
-- [ ] Decide if breadcrumbs should be shown
-- [ ] Identify other potential UI changes needed
-- [ ] Implement chosen changes
\ No newline at end of file
diff --git a/.beans/sendou.ink-wn5o--define-sidebar-data-update-strategy.md b/.beans/sendou.ink-wn5o--define-sidebar-data-update-strategy.md
deleted file mode 100644
index 407c55e49..000000000
--- a/.beans/sendou.ink-wn5o--define-sidebar-data-update-strategy.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-# sendou.ink-wn5o
-title: Define sidebar data update strategy
-status: todo
-type: task
-created_at: 2026-01-11T09:27:58Z
-updated_at: 2026-01-11T09:27:58Z
-parent: sendou.ink-6eko
----
-
-## Problem
-
-Currently the sidebar fetches fresh data every time the Layout mounts. Need to define when and how sidebar data should be updated.
-
-## Questions to Answer
-
-- When should sidebar data be refreshed? (On every navigation? On a timer? Only on specific actions?)
-- Should we use polling for real-time updates (e.g., friend online status, new tournaments)?
-- What data needs to stay fresh vs. can be cached longer?
-- How do we invalidate the cache when user takes actions (e.g., joins a tournament)?
-
-## Current Implementation
-
-- Sidebar fetches on mount via `useFetcher` (`app/components/layout/index.tsx:76-86`)
-- No cache invalidation strategy exists
-- Could cause excessive requests on rapid navigation
\ No newline at end of file
diff --git a/.beans/sendou.ink-wp5x--user-search-has-nested-input-borders.md b/.beans/sendou.ink-wp5x--user-search-has-nested-input-borders.md
deleted file mode 100644
index e33fb4684..000000000
--- a/.beans/sendou.ink-wp5x--user-search-has-nested-input-borders.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-# sendou.ink-wp5x
-title: User search has nested input borders
-status: completed
-type: bug
-created_at: 2026-01-11T13:54:26Z
-updated_at: 2026-01-11T13:54:26Z
-parent: sendou.ink-1l22
----
-
-The user search component displays an 'input inside input' visual issue - there's an outer border around the whole search container and an inner border around the actual text input, creating an unintended nested appearance.
-
-## Details
-
-- Visible on the admin page 'User to log in as' search
-- Likely affects other places using the same UserSearch component
-- Should have a single cohesive input appearance, not nested borders
diff --git a/.beans/sendou.ink-x535--add-stream-curator-ui-for-calendar-events.md b/.beans/sendou.ink-x535--add-stream-curator-ui-for-calendar-events.md
deleted file mode 100644
index 49aff3b76..000000000
--- a/.beans/sendou.ink-x535--add-stream-curator-ui-for-calendar-events.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-# sendou.ink-x535
-title: Add stream curator UI for calendar events
-status: todo
-type: feature
-created_at: 2026-01-12T09:20:31Z
-updated_at: 2026-01-12T09:20:31Z
-parent: sendou.ink-r6ry
----
-
-Create UI for stream curators to add stream links to their calendar events.
-
-## Requirements
-
-- Only visible to users with STREAM_CURATOR role
-- Only editable for events the user created
-- Allow adding/removing stream URL(s)
-- Basic URL format validation
-- Support any streaming platform (Twitch, YouTube, etc.)
-
-## UI Location
-
-- Calendar event edit page: `/app/features/calendar/routes/calendar.new.tsx`
-- (Same page handles both create and edit via `eventId` param)
-- New section: "Stream Links" or "Streams"
-
-## UI Design
-
-```
-## Streams (only visible to STREAM_CURATOR + event owner)
-
-[ https://twitch.tv/example ] [Remove]
-[ https://youtube.com/watch?v= ] [Remove]
-[+ Add stream link]
-
-Max 5 links per event
-```
-
-## Checklist
-
-- [ ] Add `useHasRole("STREAM_CURATOR")` check in calendar.new.tsx
-- [ ] Create "Streams" section in the form (only for edit mode, not create)
-- [ ] Add URL input with add/remove functionality
-- [ ] Add action handler for saving stream links
-- [ ] Show existing stream links when editing
-- [ ] Add i18n translations for labels
-
-## Implementation Notes
-
-- Use existing form patterns from the calendar edit page
-- Stream links are saved separately from main event data
-- Only show section in edit mode (after event is created)
-- Consider showing platform icon based on URL (Twitch, YouTube, etc.)
-
-## Dependencies
-
-- sendou.ink-4m0t: STREAM_CURATOR role
-- sendou.ink-a9gl: CalendarEventStream table
diff --git a/.beans/sendou.ink-xsyy--sidebar-friends-section-with-real-data.md b/.beans/sendou.ink-xsyy--sidebar-friends-section-with-real-data.md
deleted file mode 100644
index 52ed9bb1f..000000000
--- a/.beans/sendou.ink-xsyy--sidebar-friends-section-with-real-data.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-# sendou.ink-xsyy
-title: Sidebar friends section with real data
-status: in-progress
-type: task
-priority: normal
-created_at: 2026-01-13T09:32:29Z
-updated_at: 2026-01-16T08:04:13Z
-parent: sendou.ink-255r
----
-
-## Overview
-
-Replace mocked friends in sidebar with real data from friends, teammates, and associations.
-
-## Current State
-
-`app/features/sidebar/routes/sidebar.ts` returns mock friends when user is authenticated.
-
-## Requirements
-
-### Data Source
-Query from FriendRepository.findAllConnectionsWithActivity(userId) which returns:
-- Explicit friends
-- Team members
-- Association/Plus members
-
-### Display Priority
-1. Users with SendouQ activity (quota: ~3 slots)
-2. Users with tournament activity (quota: ~2 slots)
-3. Most recently interacted friends
-4. Then teammates, then associations
-
-### Item Display
-Each item shows:
-- Avatar
-- Username
-- Activity subtitle ("SendouQ", tournament name, team name)
-- Badge ("2/4" for group count, "LIVE" for tournament match)
-
-### Mixed List
-No grouping by relationship type in sidebar (mixed list with priority ordering).
-
-## Checklist
-
-- [x] Update sidebar loader to fetch real connections
-- [x] Implement basic priority sorting (SendouQ first, then tournament subs)
-- [x] Update SideNavFriendItem component with real data (URLs, avatars)
-- [ ] Full priority sorting logic with quota system
-- [ ] "See all" link to /friends page
-- [ ] Handle empty state (no friends yet)
\ No newline at end of file
diff --git a/.beans/sendou.ink-y2wo--remove-and-redirect-t-page.md b/.beans/sendou.ink-y2wo--remove-and-redirect-t-page.md
deleted file mode 100644
index 9503c61b7..000000000
--- a/.beans/sendou.ink-y2wo--remove-and-redirect-t-page.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-y2wo
-title: Remove and redirect /t page
-status: completed
-type: task
-created_at: 2026-01-11T08:58:56Z
-updated_at: 2026-01-11T08:58:56Z
-parent: sendou.ink-6eko
----
-
-Deprecate and remove the /t page. Add redirect to new location. Location: app/features/team/routes/t.tsx:51
diff --git a/.beans/sendou.ink-y9e1--update-sidebar-cache-shape.md b/.beans/sendou.ink-y9e1--update-sidebar-cache-shape.md
deleted file mode 100644
index 1b7b80a14..000000000
--- a/.beans/sendou.ink-y9e1--update-sidebar-cache-shape.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-# sendou.ink-y9e1
-title: Update sidebar cache shape
-status: todo
-type: task
-created_at: 2026-01-11T08:58:55Z
-updated_at: 2026-01-11T08:58:55Z
-parent: sendou.ink-6eko
----
-
-The cached value matches previous usage pattern. Update to match the new usage requirements. Location: app/features/sidebar/routes/sidebar.ts:44
\ No newline at end of file
diff --git a/.beans/sendou.ink-yg4i--implement-sidebar-collapseexpand.md b/.beans/sendou.ink-yg4i--implement-sidebar-collapseexpand.md
deleted file mode 100644
index 69930e78e..000000000
--- a/.beans/sendou.ink-yg4i--implement-sidebar-collapseexpand.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-# sendou.ink-yg4i
-title: Implement sidebar collapse/expand
-status: completed
-type: task
-priority: normal
-created_at: 2026-01-11T09:28:55Z
-updated_at: 2026-01-11T12:31:36Z
-parent: sendou.ink-6eko
-blocking:
- - sendou.ink-wn2f
----
-
-## Feature
-
-Allow users to collapse the sidebar to show icons only, giving more horizontal space to content.
-
-## Behavior
-
-- Collapsed state shows just icons for each section (profile, calendar, friends, streams)
-- User can toggle between collapsed and expanded states
-- Should persist preference (localStorage or user settings)
-
-## Considerations
-
-- Toggle button placement (in sidebar header? floating?)
-- Animation/transition when collapsing
-- Tooltip on hover for collapsed icons
-- Keyboard shortcut to toggle?
-- Mobile: does this apply or is mobile handled differently?
\ No newline at end of file
diff --git a/.beans/sendou.ink-ylq5--tournament-prestige-system.md b/.beans/sendou.ink-ylq5--tournament-prestige-system.md
deleted file mode 100644
index 5607b95a0..000000000
--- a/.beans/sendou.ink-ylq5--tournament-prestige-system.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-# sendou.ink-ylq5
-title: Tournament Prestige System
-status: draft
-type: epic
-priority: normal
-created_at: 2026-01-12T08:49:28Z
-updated_at: 2026-01-12T08:49:38Z
-blocking:
- - sendou.ink-r6ry
----
-
-Algorithm for calculating tournament prestige based on registered players' seeding power. Used for stream ranking and potentially other features like player profiles and historical rankings.
-
-## Why
-
-The community lacks a standardized way to define tournament importance. A stacked weekly can be as competitive as a named major, but naming alone doesn't reflect actual strength. Prestige should be derived from actual participant skill level.
-
-## Algorithm Concept
-
-Calculate prestige based on average seeding power of top 8 teams compared to a baseline. This needs experimentation to produce balanced and expected prestige values. Test with real production data to ensure we get the right algorithm for historic tournaments.
-
-### Inputs
-- Registered teams' seeding power (from existing seeding system)
-- Focus on top 8 teams to represent tournament strength
-
-### Outputs
-- Prestige score/tier for the tournament
-- Available from registration (not just after results)
-
-## Additional Features
-
-- Track prestige of tournament series across multiple editions
-- Historical prestige data for recurring tournaments
-
-## Use Cases
-
-1. **Stream ranking**: Higher prestige tournaments get priority in sidebar
-2. **Player profiles**: Show participation in high-prestige events
-3. **Leaderboards**: Weight tournament results by prestige
-4. **Historical records**: Track which events were truly significant
-
-## Open Questions
-
-- What baseline to compare against?
-- How to handle team count variance (16-team vs 128-team)?
-- Should there be discrete tiers or continuous scores?
-- How to weight recent vs historical editions for series prestige?
-
-## Child Tasks
-
-Research and implementation tasks (sequential order):
-
-1. sendou.ink-24f6: Analyze tournament seeding data distribution
-2. sendou.ink-h9ht: Design and test prestige formula
-3. sendou.ink-10ai: Implement prestige calculation
diff --git a/.beans/sendou.ink-yyzj--my-calendar-ical-export.md b/.beans/sendou.ink-yyzj--my-calendar-ical-export.md
deleted file mode 100644
index 2905d01e3..000000000
--- a/.beans/sendou.ink-yyzj--my-calendar-ical-export.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-# sendou.ink-yyzj
-title: My Events iCal export
-status: todo
-type: task
-priority: normal
-created_at: 2026-01-11T11:45:35Z
-updated_at: 2026-01-11T12:51:39Z
-parent: sendou.ink-om3i
----
-
-## Summary
-
-Add .ics file export for the user's personal events, allowing subscription in external calendar apps.
-
-## Details
-
-**Feature:**
-- Generate .ics file containing user's tournaments and scrims
-- Similar to existing /calendar iCal feature but personalized
-- Users can subscribe in Google Calendar, Apple Calendar, etc.
-
-**Events to include:**
-- Tournaments user is registered for
-- Tournaments user is organizing
-- Scheduled scrims
-- Looking-for-match scrims (optional - may not make sense)
-
-## Checklist
-
-- [ ] Research existing /calendar iCal implementation
-- [ ] Create endpoint for personal events .ics
-- [ ] Generate iCal events from user's tournaments
-- [ ] Generate iCal events from user's scrims
-- [ ] Add subscription URL/button to My Events page
-- [ ] Test subscription in external calendar app
\ No newline at end of file
diff --git a/.beans/sendou.ink-z3b2--seed-page-input-text-not-showing-up.md b/.beans/sendou.ink-z3b2--seed-page-input-text-not-showing-up.md
deleted file mode 100644
index 468caa6a4..000000000
--- a/.beans/sendou.ink-z3b2--seed-page-input-text-not-showing-up.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-# sendou.ink-z3b2
-title: Seed page input text not showing up
-status: todo
-type: bug
-created_at: 2026-01-18T20:04:43Z
-updated_at: 2026-01-18T20:04:43Z
-parent: sendou.ink-1l22
----
-
-On the tournament seed page, the seed number input fields appear empty even when they should contain values. The input boxes are visible but the text inside them is not rendering (likely a color/contrast issue with the CSS rework).
-
-## Screenshot
-The seed column shows empty input boxes where numbers should be visible.
-
-## Expected Behavior
-Seed numbers (1, 2, 3, etc.) should be visible inside the input fields.
-
-## Likely Cause
-Text color in the input field may be the same as or too close to the background color after the CSS variable changes.
\ No newline at end of file