👁️
fork

Configure Feed

Select the types of activity you want to include in your feed.

dark mode style overhaul

+738 -546
+188
.claude/DARK_MODE.md
··· 1 + # Dark Mode Style Guide 2 + 3 + ## The Problem (Pre-January 2025) 4 + 5 + Our dark mode was "very blue" and garish because: 6 + 7 + 1. **Slate is blue-tinted** - Tailwind's slate scale has a cool/blue undertone 8 + 2. **Cyan accent overload** - used for links, buttons, icons, focus states, everything 9 + 3. **Rainbow badge syndrome** - purple, indigo, rose, emerald, amber all fighting 10 + 4. **Inconsistent gray scales** - mixing `gray-` and `slate-` classes 11 + 12 + ## The Fix: Neutral Grays + Restrained Accent 13 + 14 + Inspired by Discord and Linear's approach: 15 + - True neutral backgrounds (zinc instead of slate) 16 + - Single accent color (cyan) for primary actions only 17 + - High contrast text (AAA compliant, 7.0+ ratio) 18 + - Muted/semantic colors for badges and status 19 + - Visible borders (zinc-600 for definition) 20 + 21 + ## Design Principles 22 + 23 + **60-30-10 rule**: 60% background, 30% secondary/text, 10% accent. Don't overuse the accent color. 24 + 25 + **Text contrast for AAA (7.0+)**: 26 + - zinc-100 on zinc-900 = 16.12:1 ✓ 27 + - zinc-300 on zinc-900 = 11.99:1 ✓ (use for secondary text) 28 + - zinc-400 on zinc-900 = 6.91:1 ✗ (below AAA, ok for muted/hints) 29 + - zinc-500 on zinc-900 = 3.67:1 ✗ (placeholder text only) 30 + 31 + **Saturated colors glow on dark**: Use 400-shade colors sparingly. Desaturate or use lighter tones for large areas. 32 + 33 + **Borders matter more in dark mode**: Less visual differentiation between dark grays means borders need to be more visible (zinc-600 instead of zinc-700). 34 + 35 + ## Color Palette 36 + 37 + ### Backgrounds (zinc scale - true neutral) 38 + 39 + | Use Case | Light | Dark | 40 + |----------|-------|------| 41 + | Page background | `bg-white` | `dark:bg-zinc-900` | 42 + | Elevated surface (cards, panels) | `bg-gray-50` | `dark:bg-zinc-800` | 43 + | Hover/active states | `bg-gray-100` | `dark:bg-zinc-700` | 44 + | Input backgrounds | `bg-white` | `dark:bg-zinc-800` | 45 + | Subtle dividers | `bg-gray-200` | `dark:bg-zinc-700` | 46 + 47 + ### Text 48 + 49 + | Use Case | Light | Dark | Dark Contrast | 50 + |----------|-------|------|---------------| 51 + | Primary text | `text-gray-900` | `dark:text-zinc-100` | 16.12:1 ✓ AAA | 52 + | Secondary text | `text-gray-600` | `dark:text-zinc-300` | 11.99:1 ✓ AAA | 53 + | Muted/tertiary | `text-gray-500` | `dark:text-zinc-400` | 6.91:1 ✗ AA only | 54 + | Placeholder | `text-gray-400` | `dark:text-zinc-500` | 3.67:1 ✗ decorative | 55 + 56 + ### Borders 57 + 58 + | Use Case | Light | Dark | 59 + |----------|-------|------| 60 + | Default border | `border-gray-200` | `dark:border-zinc-600` | 61 + | Subtle border | `border-gray-100` | `dark:border-zinc-700` | 62 + | Strong border | `border-gray-300` | `dark:border-zinc-500` | 63 + | Focus ring | `ring-cyan-500` | `dark:ring-cyan-400` | 64 + 65 + ### Accent Colors (Cyan) 66 + 67 + **Light cyan needs dark text; dark cyan can use white text.** 68 + 69 + Contrast ratios (calculated via WCAG formula): 70 + 71 + | Shade | + White | + Gray-900 | Best Text | 72 + |-------|---------|------------|-----------| 73 + | cyan-400 (#22d3ee) | 1.81:1 ✗ | 9.82:1 ✓ AAA | dark | 74 + | cyan-500 (#06b6d4) | 2.43:1 ✗ | 7.31:1 ✓ AAA | dark | 75 + | cyan-600 (#0891b2) | 3.68:1 ✗ | 4.82:1 ✓ AA | dark | 76 + | cyan-700 (#0e7490) | 5.36:1 ✓ AA | 3.31:1 ✗ | white | 77 + | cyan-800 (#155e75) | 7.27:1 ✓ AAA | 2.44:1 ✗ | white | 78 + 79 + | Use Case | Classes | Notes | 80 + |----------|---------|-------| 81 + | Primary button | `bg-cyan-400 hover:bg-cyan-300 text-gray-900` | Bright, AAA | 82 + | Selected/active state | `bg-cyan-400 text-gray-900` | Bright, AAA | 83 + | Inline card/mention ref | `bg-cyan-700 text-white` | Darker, AA | 84 + | Link text | `text-cyan-600 dark:text-cyan-400` | Text only | 85 + | Focus ring | `ring-cyan-500 dark:ring-cyan-400` | Decorative | 86 + | Toggle switch (on) | `bg-cyan-600` | No text label | 87 + 88 + ### Status/Semantic Colors 89 + 90 + Keep these muted in dark mode: 91 + 92 + | Status | Light | Dark | 93 + |--------|-------|------| 94 + | Success | `text-green-600` / `bg-green-100` | `dark:text-green-400` / `dark:bg-green-900/30` | 95 + | Warning | `text-amber-600` / `bg-amber-100` | `dark:text-amber-400` / `dark:bg-amber-900/30` | 96 + | Error | `text-red-600` / `bg-red-100` | `dark:text-red-400` / `dark:bg-red-900/30` | 97 + | Info | `text-blue-600` / `bg-blue-100` | `dark:text-blue-400` / `dark:bg-blue-900/30` | 98 + 99 + ### MTG-Specific 100 + 101 + Rarity colors stay as-is (established MTG conventions): 102 + 103 + ```css 104 + --color-rarity-common: #1a1718; 105 + --color-rarity-uncommon: #707883; 106 + --color-rarity-rare: #a58e4a; 107 + --color-rarity-mythic: #bf4427; 108 + --color-rarity-timeshifted: #652978; 109 + ``` 110 + 111 + For generic badges (set codes, format tags), prefer neutral styling: 112 + - `bg-zinc-100 dark:bg-zinc-800` 113 + - `border-zinc-200 dark:border-zinc-700` 114 + - `text-zinc-600 dark:text-zinc-400` 115 + 116 + ## Component Patterns 117 + 118 + ### Cards/Panels 119 + 120 + ```tsx 121 + <div className="bg-white dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg p-4"> 122 + <h3 className="text-gray-900 dark:text-zinc-100 font-medium">Title</h3> 123 + <p className="text-gray-600 dark:text-zinc-300 text-sm">Description</p> 124 + </div> 125 + ``` 126 + 127 + ### Buttons 128 + 129 + ```tsx 130 + // Primary (cyan bg needs dark text for contrast) 131 + <button className="bg-cyan-400 hover:bg-cyan-300 text-gray-900"> 132 + Action 133 + </button> 134 + 135 + // Secondary 136 + <button className="bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 text-gray-900 dark:text-zinc-100"> 137 + Secondary 138 + </button> 139 + 140 + // Ghost 141 + <button className="hover:bg-zinc-100 dark:hover:bg-zinc-800 text-gray-600 dark:text-zinc-400"> 142 + Ghost 143 + </button> 144 + ``` 145 + 146 + ### Links 147 + 148 + ```tsx 149 + <a className="text-cyan-600 dark:text-cyan-400 hover:underline"> 150 + Link text 151 + </a> 152 + ``` 153 + 154 + ### Form Inputs 155 + 156 + ```tsx 157 + <input className="bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 text-gray-900 dark:text-zinc-100 placeholder:text-gray-400 dark:placeholder:text-zinc-500 focus:ring-2 focus:ring-cyan-500 dark:focus:ring-cyan-400" /> 158 + ``` 159 + 160 + ## Checklist for New Components 161 + 162 + - [ ] Uses `zinc-*` for dark backgrounds, not `slate-*` 163 + - [ ] Primary accent is `cyan-*` 164 + - [ ] Cyan backgrounds use dark text (`text-gray-900`), not white 165 + - [ ] Primary text uses `zinc-100`, secondary uses `zinc-300` (AAA compliant) 166 + - [ ] Colored badges only for semantic meaning (rarity, status) 167 + - [ ] Borders use `zinc-600` for visibility 168 + - [ ] Focus states use `cyan-*` ring 169 + 170 + ## Alternative Accent Colors Considered 171 + 172 + If cyan doesn't work out, these were researched as alternatives: 173 + 174 + | Color | Hex | Best For | Concerns | 175 + |-------|-----|----------|----------| 176 + | amber-400 | `#fbbf24` | Buttons, gaming/treasure feel | Can read as warning | 177 + | amber-500 | `#f59e0b` | More muted gold | Needs dark text | 178 + | rose-400 | `#fb7185` | Links and buttons both | Could conflict with error red | 179 + | teal-400 | `#2dd4bf` | Warmer cyan alternative | Still cool-toned | 180 + 181 + ## References 182 + 183 + - [Discord Color Palette](https://www.color-hex.com/color-palette/114089) 184 + - [Linear UI Redesign](https://linear.app/now/how-we-redesigned-the-linear-ui) 185 + - [Tailwind Zinc Scale](https://tailwindcss.com/docs/customizing-colors) 186 + - [Dark Mode Best Practices](https://appinventiv.com/blog/guide-on-designing-dark-mode-for-mobile-app/) 187 + - [Yellow/Amber Accessibility](https://stephaniewalter.design/blog/yellow-purple-and-the-myth-of-accessibility-limits-color-palettes/) 188 + - [USWDS Color Tokens](https://designsystem.digital.gov/design-tokens/color/theme-tokens/)
+2 -1
.claude/settings.local.json
··· 65 65 "Bash(curl:*)", 66 66 "Bash(npm run build:lexicons:*)", 67 67 "Bash(npm run lexicons:lint:*)", 68 - "Bash(npm run lexicons:all:*)" 68 + "Bash(npm run lexicons:all:*)", 69 + "Bash(goat lex:*)" 69 70 ], 70 71 "deny": [], 71 72 "ask": []
+9 -7
CLAUDE.md
··· 86 86 87 87 **Dark Mode Support:** 88 88 - All components and pages must support both light and dark mode 89 - - Use Tailwind's `dark:` variant for dark mode styles (e.g., `bg-white dark:bg-slate-900`) 90 89 - Theme is managed by `ThemeProvider` in `src/lib/useTheme.tsx` 91 90 - Dark mode configuration: `@custom-variant dark (&:where(.dark, .dark *))` in `src/styles.css` 92 - - Common patterns: 93 - - Backgrounds: `bg-white dark:bg-slate-900` (page), `bg-gray-100 dark:bg-slate-800` (panels) 94 - - Primary text: `text-gray-900 dark:text-white` 95 - - Secondary text: `text-gray-600 dark:text-gray-400` 96 - - Borders: `border-gray-300 dark:border-slate-700` 97 - - Interactive elements: `hover:bg-gray-100 dark:hover:bg-gray-800` 91 + - **See `.claude/DARK_MODE.md` for the full style guide** 92 + - Key patterns: 93 + - Backgrounds: `bg-white dark:bg-zinc-900` (page), `bg-gray-50 dark:bg-zinc-800` (panels) 94 + - Primary text: `text-gray-900 dark:text-zinc-100` 95 + - Secondary text: `text-gray-600 dark:text-zinc-300` (AAA contrast) 96 + - Borders: `border-gray-200 dark:border-zinc-600` (visible) 97 + - Accent color: `cyan-*` (e.g., `text-cyan-600 dark:text-cyan-400`) 98 + - Focus rings: `focus:ring-cyan-500 dark:focus:ring-cyan-400` 99 + - **DO NOT use**: `slate-*` for dark mode (it's blue-tinted) 98 100 99 101 **Reduced Motion Support:** 100 102 - Respect `prefers-reduced-motion` for decorative and dramatic animations
+2 -1
package.json
··· 23 23 "lexicons:status": "goat lex status", 24 24 "lexicons:diff": "goat lex diff", 25 25 "lexicons:check-dns": "goat lex check-dns --did did:web:deckbelcher.com", 26 - "lexicons:publish": "goat lex publish --username deckbelcher.com", 26 + "lexicons:prepublish": "npm run lexicons:breaking && npm run lexicons:diff && npm run lexicons:status", 27 + "lexicons:publish": "npm run lexicons:prepublish && goat lex publish --username deckbelcher.com", 27 28 "lexicons:codegen": "lex-cli generate -c ./lex.config.js", 28 29 "lexicons:scopes": "node --experimental-strip-types scripts/generate-oauth-scopes.ts", 29 30 "lexicons:all": "npm run lexicons:compile && npm run lexicons:lint && npm run lexicons:breaking && npm run lexicons:codegen && npm run lexicons:scopes",
+8 -8
src/components/ActivityFeed.tsx
··· 25 25 26 26 if (error || !records) { 27 27 return ( 28 - <div className="text-center py-8 text-gray-500 dark:text-gray-400"> 28 + <div className="text-center py-8 text-gray-500 dark:text-zinc-300"> 29 29 Unable to load recent activity 30 30 </div> 31 31 ); ··· 33 33 34 34 if (records.length === 0) { 35 35 return ( 36 - <div className="text-center py-8 text-gray-500 dark:text-gray-400"> 36 + <div className="text-center py-8 text-gray-500 dark:text-zinc-300"> 37 37 No recent activity yet 38 38 </div> 39 39 ); ··· 78 78 <div 79 79 // biome-ignore lint/suspicious/noArrayIndexKey: static skeleton 80 80 key={i} 81 - className="flex gap-4 p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg animate-pulse" 81 + className="flex gap-4 p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg animate-pulse" 82 82 > 83 - <div className="flex-shrink-0 w-16 h-[90px] bg-gray-200 dark:bg-slate-700 rounded" /> 83 + <div className="flex-shrink-0 w-16 h-[90px] bg-gray-200 dark:bg-zinc-700 rounded" /> 84 84 <div className="flex-1 min-w-0"> 85 85 {/* Handle */} 86 - <div className="h-5 w-24 bg-gray-200 dark:bg-slate-700 rounded mb-1" /> 86 + <div className="h-5 w-24 bg-gray-200 dark:bg-zinc-700 rounded mb-1" /> 87 87 {/* Name */} 88 - <div className="h-7 w-40 bg-gray-200 dark:bg-slate-700 rounded" /> 88 + <div className="h-7 w-40 bg-gray-200 dark:bg-zinc-700 rounded" /> 89 89 {/* Format */} 90 - <div className="h-5 w-20 bg-gray-200 dark:bg-slate-700 rounded mt-1" /> 90 + <div className="h-5 w-20 bg-gray-200 dark:bg-zinc-700 rounded mt-1" /> 91 91 {/* Date */} 92 - <div className="h-5 w-28 bg-gray-200 dark:bg-slate-700 rounded mt-2" /> 92 + <div className="h-5 w-28 bg-gray-200 dark:bg-zinc-700 rounded mt-2" /> 93 93 </div> 94 94 </div> 95 95 ))}
+6 -6
src/components/CardImage.tsx
··· 85 85 <img 86 86 src={getImageUri(card.id, size, face)} 87 87 alt={card.name} 88 - className={`${baseClassName} bg-gray-200 dark:bg-slate-700`} 88 + className={`${baseClassName} bg-gray-200 dark:bg-zinc-700`} 89 89 style={{ backgroundImage: PLACEHOLDER_STRIPES }} 90 90 loading="lazy" 91 91 /> ··· 108 108 <img 109 109 src={getImageUri(card.id, size, "front")} 110 110 alt={card.name} 111 - className={`${baseClassName} bg-gray-200 dark:bg-slate-700`} 111 + className={`${baseClassName} bg-gray-200 dark:bg-zinc-700`} 112 112 loading="lazy" 113 113 style={{ 114 114 backfaceVisibility: "hidden", ··· 118 118 <img 119 119 src={getImageUri(card.id, size, "back")} 120 120 alt={`${card.name} (back)`} 121 - className={`${baseClassName} bg-gray-200 dark:bg-slate-700 absolute inset-0`} 121 + className={`${baseClassName} bg-gray-200 dark:bg-zinc-700 absolute inset-0`} 122 122 loading="lazy" 123 123 style={{ 124 124 backfaceVisibility: "hidden", ··· 131 131 <img 132 132 src={getImageUri(card.id, size, face)} 133 133 alt={card.name} 134 - className={`${baseClassName} bg-gray-200 dark:bg-slate-700 motion-safe:transition-transform motion-safe:duration-500 motion-safe:ease-in-out`} 134 + className={`${baseClassName} bg-gray-200 dark:bg-zinc-700 motion-safe:transition-transform motion-safe:duration-500 motion-safe:ease-in-out`} 135 135 loading="lazy" 136 136 style={{ 137 137 backgroundImage: PLACEHOLDER_STRIPES, ··· 162 162 export function CardSkeleton() { 163 163 return ( 164 164 <div 165 - className="aspect-[5/7] rounded-[4.75%/3.5%] bg-gray-200 dark:bg-slate-700 animate-pulse" 165 + className="aspect-[5/7] rounded-[4.75%/3.5%] bg-gray-200 dark:bg-zinc-700 animate-pulse" 166 166 style={{ backgroundImage: PLACEHOLDER_STRIPES }} 167 167 /> 168 168 ); ··· 191 191 {card.name} 192 192 </p> 193 193 {card.set_name && ( 194 - <p className="text-gray-200 dark:text-gray-300 text-xs mt-1"> 194 + <p className="text-gray-200 dark:text-zinc-300 text-xs mt-1"> 195 195 {card.set_name} 196 196 </p> 197 197 )}
+1 -1
src/components/ClientDate.tsx
··· 43 43 return ( 44 44 <span className={className}> 45 45 <span 46 - className="inline-block align-middle bg-gray-200 dark:bg-slate-700 rounded animate-pulse" 46 + className="inline-block align-middle bg-gray-200 dark:bg-zinc-700 rounded animate-pulse" 47 47 style={{ width: "5.5em", height: "0.75em" }} 48 48 /> 49 49 </span>
+6 -6
src/components/DeckPreview.tsx
··· 129 129 <Link 130 130 to="/profile/$did/deck/$rkey" 131 131 params={{ did, rkey: asRkey(rkey) }} 132 - className="group flex items-start gap-4 p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 132 + className="group flex items-start gap-4 p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 133 133 > 134 134 <CardSpread cardIds={previewCardIds} /> 135 135 136 136 <div className="flex-1 min-w-0"> 137 137 {showHandle && 138 138 (handle ? ( 139 - <p className="text-sm text-gray-600 dark:text-gray-400 truncate"> 139 + <p className="text-sm text-gray-600 dark:text-zinc-300 truncate"> 140 140 @{handle} 141 141 </p> 142 142 ) : ( 143 - <div className="h-5 w-24 bg-gray-200 dark:bg-slate-700 rounded animate-pulse" /> 143 + <div className="h-5 w-24 bg-gray-200 dark:bg-zinc-700 rounded animate-pulse" /> 144 144 ))} 145 145 146 146 <h2 className="text-lg font-bold text-gray-900 dark:text-white truncate font-display"> 147 147 {deck.name} 148 148 </h2> 149 149 {deck.format && ( 150 - <p className="text-sm text-gray-600 dark:text-gray-400 truncate"> 150 + <p className="text-sm text-gray-600 dark:text-zinc-300 truncate"> 151 151 {formatDisplayName(deck.format)} 152 152 </p> 153 153 )} 154 154 {sectionString && ( 155 - <p className="text-sm text-gray-600 dark:text-gray-400 truncate"> 155 + <p className="text-sm text-gray-600 dark:text-zinc-300 truncate"> 156 156 {sectionString} 157 157 </p> 158 158 )} 159 - <p className="text-sm text-gray-500 dark:text-gray-500"> 159 + <p className="text-sm text-gray-500 dark:text-zinc-400"> 160 160 Updated <ClientDate dateString={dateString} /> 161 161 </p> 162 162 </div>
+13 -13
src/components/Header.tsx
··· 19 19 20 20 return ( 21 21 <> 22 - <header className="p-2 sm:p-4 flex items-center bg-gray-800 dark:bg-gray-900 text-white shadow-lg"> 22 + <header className="p-2 sm:p-4 flex items-center bg-zinc-800 dark:bg-zinc-950 text-white shadow-lg"> 23 23 <div className="flex items-center"> 24 24 <button 25 25 type="button" 26 26 onClick={() => setIsOpen(true)} 27 - className="p-2 hover:bg-gray-700 dark:hover:bg-gray-800 rounded-lg transition-colors" 27 + className="p-2 hover:bg-zinc-700 dark:hover:bg-zinc-800 rounded-lg transition-colors" 28 28 aria-label="Open menu" 29 29 > 30 30 <Menu size={24} /> ··· 43 43 <Link 44 44 to="/cards" 45 45 search={{ q: "", sort: undefined, sort2: undefined }} 46 - className="flex items-center gap-2 px-3 sm:px-4 py-2 bg-cyan-600 hover:bg-cyan-700 rounded-lg transition-colors text-white text-sm font-medium" 46 + className="flex items-center gap-2 px-3 sm:px-4 py-2 bg-cyan-400 hover:bg-cyan-300 rounded-lg transition-colors text-gray-900 text-sm font-medium" 47 47 > 48 48 <Search size={18} /> 49 49 <span className="hidden sm:inline">Search Cards</span> ··· 52 52 53 53 <div className="flex items-center gap-2"> 54 54 {isLoading ? ( 55 - <div className="flex items-center gap-2 px-3 py-2 bg-gray-700 dark:bg-gray-800 rounded-lg animate-pulse"> 55 + <div className="flex items-center gap-2 px-3 py-2 bg-zinc-700 dark:bg-zinc-800 rounded-lg animate-pulse"> 56 56 <LogIn size={16} className="invisible" /> 57 57 <span className="text-sm font-medium invisible">Sign In</span> 58 58 </div> ··· 62 62 <Link 63 63 to="/signin" 64 64 onClick={handleSignInClick} 65 - className="flex items-center gap-2 px-2 sm:px-3 py-2 bg-cyan-600 hover:bg-cyan-700 rounded-lg transition-colors" 65 + className="flex items-center gap-2 px-2 sm:px-3 py-2 bg-cyan-400 hover:bg-cyan-300 text-gray-900 rounded-lg transition-colors" 66 66 > 67 67 <LogIn size={16} /> 68 68 <span className="text-sm font-medium hidden sm:inline"> ··· 73 73 <button 74 74 type="button" 75 75 onClick={toggleTheme} 76 - className="p-2 hover:bg-gray-700 dark:hover:bg-gray-800 rounded-lg transition-colors" 76 + className="p-2 hover:bg-zinc-700 dark:hover:bg-zinc-800 rounded-lg transition-colors" 77 77 aria-label="Toggle theme" 78 78 > 79 79 {theme === "dark" ? ( ··· 97 97 )} 98 98 99 99 <aside 100 - className={`fixed top-0 left-0 h-full w-80 bg-white dark:bg-gray-900 text-gray-900 dark:text-white shadow-2xl z-50 transform transition-transform duration-300 ease-in-out flex flex-col ${ 100 + className={`fixed top-0 left-0 h-full w-80 bg-white dark:bg-zinc-900 text-gray-900 dark:text-zinc-100 shadow-2xl z-50 transform transition-transform duration-300 ease-in-out flex flex-col ${ 101 101 isOpen ? "translate-x-0" : "-translate-x-full" 102 102 }`} 103 103 > 104 - <div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700"> 104 + <div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-zinc-600"> 105 105 <h2 className="text-xl font-bold">Navigation</h2> 106 106 <button 107 107 type="button" 108 108 onClick={() => setIsOpen(false)} 109 - className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors" 109 + className="p-2 hover:bg-gray-100 dark:hover:bg-zinc-800 rounded-lg transition-colors" 110 110 aria-label="Close menu" 111 111 > 112 112 <X size={24} /> ··· 119 119 onClick={() => setIsOpen(false)} 120 120 className="flex items-center gap-3 p-3 rounded-lg transition-colors mb-2" 121 121 inactiveProps={{ 122 - className: "hover:bg-gray-100 dark:hover:bg-gray-800", 122 + className: "hover:bg-gray-100 dark:hover:bg-zinc-800", 123 123 }} 124 124 activeProps={{ 125 - className: "bg-cyan-600 hover:bg-cyan-700 text-white", 125 + className: "bg-cyan-700 hover:bg-cyan-600 text-white", 126 126 }} 127 127 > 128 128 <Home size={20} /> ··· 135 135 onClick={() => setIsOpen(false)} 136 136 className="flex items-center gap-3 p-3 rounded-lg transition-colors mb-2" 137 137 inactiveProps={{ 138 - className: "hover:bg-gray-100 dark:hover:bg-gray-800", 138 + className: "hover:bg-gray-100 dark:hover:bg-zinc-800", 139 139 }} 140 140 activeProps={{ 141 - className: "bg-cyan-600 hover:bg-cyan-700 text-white", 141 + className: "bg-cyan-700 hover:bg-cyan-600 text-white", 142 142 }} 143 143 > 144 144 <Library size={20} />
+2 -2
src/components/HighlightedSearchInput.tsx
··· 77 77 78 78 return ( 79 79 <div 80 - className={`relative flex items-center rounded-lg border transition-colors bg-gray-100 dark:bg-slate-800 ${ 80 + className={`relative flex items-center rounded-lg border transition-colors bg-gray-100 dark:bg-zinc-800 ${ 81 81 hasError 82 82 ? "border-red-500" 83 - : "border-gray-300 dark:border-slate-700 focus-within:border-cyan-500" 83 + : "border-gray-300 dark:border-zinc-600 focus-within:border-cyan-500" 84 84 } ${className}`} 85 85 > 86 86 {/* Search icon - fixed, doesn't scroll */}
+5 -5
src/components/ListPreview.tsx
··· 61 61 <Link 62 62 to="/profile/$did/list/$rkey" 63 63 params={{ did, rkey: asRkey(rkey) }} 64 - className="group flex items-start gap-4 p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 64 + className="group flex items-start gap-4 p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 65 65 > 66 66 <CardSpread cardIds={cardIds} /> 67 67 68 68 <div className="flex-1 min-w-0"> 69 69 {showHandle && 70 70 (handle ? ( 71 - <p className="text-sm text-gray-600 dark:text-gray-400 truncate"> 71 + <p className="text-sm text-gray-600 dark:text-zinc-300 truncate"> 72 72 @{handle} 73 73 </p> 74 74 ) : ( 75 - <div className="h-5 w-24 bg-gray-200 dark:bg-slate-700 rounded animate-pulse" /> 75 + <div className="h-5 w-24 bg-gray-200 dark:bg-zinc-700 rounded animate-pulse" /> 76 76 ))} 77 77 78 78 <h2 className="text-lg font-bold text-gray-900 dark:text-white truncate font-display"> 79 79 {list.name} 80 80 </h2> 81 - <p className="text-sm text-gray-600 dark:text-gray-400 truncate"> 81 + <p className="text-sm text-gray-600 dark:text-zinc-300 truncate"> 82 82 {itemSummary} 83 83 </p> 84 - <p className="text-sm text-gray-500 dark:text-gray-500"> 84 + <p className="text-sm text-gray-500 dark:text-zinc-400"> 85 85 Updated <ClientDate dateString={dateString} /> 86 86 </p> 87 87 </div>
+3 -3
src/components/RouteErrorComponent.tsx
··· 32 32 }; 33 33 34 34 return ( 35 - <div className="min-h-screen bg-white dark:bg-slate-900 flex items-center justify-center p-6"> 35 + <div className="min-h-screen bg-white dark:bg-zinc-900 flex items-center justify-center p-6"> 36 36 <div className="max-w-4xl w-full"> 37 37 <div className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-6"> 38 38 <div className="flex items-start gap-4"> ··· 62 62 <button 63 63 type="button" 64 64 onClick={copyErrorDetails} 65 - className="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 dark:bg-slate-700 hover:bg-gray-300 dark:hover:bg-slate-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 65 + className="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 66 66 > 67 67 {copied ? ( 68 68 <Check className="w-4 h-4" /> ··· 73 73 </button> 74 74 <Link 75 75 to="/" 76 - className="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 dark:bg-slate-700 hover:bg-gray-300 dark:hover:bg-slate-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 76 + className="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 77 77 > 78 78 <Home className="w-4 h-4" /> 79 79 Go home
+12 -12
src/components/SearchPrimer.tsx
··· 3 3 4 4 function Code({ children }: { children: React.ReactNode }) { 5 5 return ( 6 - <code className="font-mono text-sm bg-gray-200 dark:bg-slate-700 px-1.5 py-0.5 rounded text-gray-800 dark:text-gray-200"> 6 + <code className="font-mono text-sm bg-gray-200 dark:bg-zinc-700 px-1.5 py-0.5 rounded text-gray-800 dark:text-zinc-200"> 7 7 {children} 8 8 </code> 9 9 ); ··· 14 14 <Link 15 15 to="/cards" 16 16 search={{ q, sort: undefined, sort2: undefined }} 17 - className="font-mono text-sm bg-gray-200 dark:bg-slate-700 px-1.5 py-0.5 rounded text-cyan-700 dark:text-cyan-300 hover:bg-cyan-100 dark:hover:bg-cyan-900/50 transition-colors" 17 + className="font-mono text-sm bg-gray-200 dark:bg-zinc-700 px-1.5 py-0.5 rounded text-cyan-700 dark:text-cyan-300 hover:bg-cyan-100 dark:hover:bg-cyan-900/50 transition-colors" 18 18 > 19 19 {q} 20 20 </Link> ··· 32 32 }) { 33 33 return ( 34 34 <div 35 - className={`bg-gray-50 dark:bg-slate-800/50 border border-gray-200 dark:border-slate-700 rounded-lg p-4 ${className}`} 35 + className={`bg-gray-50 dark:bg-zinc-800/50 border border-gray-200 dark:border-zinc-600 rounded-lg p-4 ${className}`} 36 36 > 37 37 <h3 className="font-semibold text-gray-900 dark:text-white mb-2"> 38 38 {title} ··· 53 53 }) { 54 54 return ( 55 55 <div 56 - className={`bg-gray-50/50 dark:bg-slate-800/30 border border-gray-200/50 dark:border-slate-700/50 rounded-lg p-3 ${className}`} 56 + className={`bg-gray-50/50 dark:bg-zinc-800/30 border border-gray-200/50 dark:border-zinc-600/50 rounded-lg p-3 ${className}`} 57 57 > 58 - <h4 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2"> 58 + <h4 className="text-sm font-medium text-gray-500 dark:text-zinc-300 mb-2"> 59 59 {title} 60 60 </h4> 61 61 {children} ··· 73 73 return ( 74 74 <div className="space-y-4"> 75 75 {/* Intro blurb */} 76 - <div className="text-sm text-gray-600 dark:text-gray-400 space-y-1"> 76 + <div className="text-sm text-gray-600 dark:text-zinc-300 space-y-1"> 77 77 <p> 78 78 Type anything to search by name—we'll find close matches even with 79 79 typos. ··· 87 87 <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"> 88 88 {/* Fields with examples */} 89 89 <MainCard title="Filter by..."> 90 - <ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300"> 90 + <ul className="space-y-1 text-sm text-gray-600 dark:text-zinc-300"> 91 91 <li> 92 92 <Q q="t:vampire" /> type 93 93 </li> ··· 120 120 121 121 {/* Operators */} 122 122 <MainCard title="Comparisons"> 123 - <ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300"> 123 + <ul className="space-y-1 text-sm text-gray-600 dark:text-zinc-300"> 124 124 <li> 125 125 <Q q="manavalue<3" /> less than 126 126 </li> ··· 141 141 142 142 {/* Colors - clearer framing */} 143 143 <MainCard title="Colors" className="sm:row-span-2 lg:row-span-1"> 144 - <div className="space-y-3 text-sm text-gray-600 dark:text-gray-300"> 144 + <div className="space-y-3 text-sm text-gray-600 dark:text-zinc-300"> 145 145 {/* Color codes */} 146 146 <div className="flex flex-wrap gap-x-3 gap-y-1"> 147 147 <span> ··· 166 166 167 167 {/* Card's colors */} 168 168 <div> 169 - <p className="text-gray-500 dark:text-gray-400 text-xs uppercase tracking-wide mb-1"> 169 + <p className="text-gray-500 dark:text-zinc-300 text-xs uppercase tracking-wide mb-1"> 170 170 Card's colors 171 171 </p> 172 172 <p> ··· 179 179 180 180 {/* Color identity for commander */} 181 181 <div> 182 - <p className="text-gray-500 dark:text-gray-400 text-xs uppercase tracking-wide mb-1"> 182 + <p className="text-gray-500 dark:text-zinc-300 text-xs uppercase tracking-wide mb-1"> 183 183 For commander decks 184 184 </p> 185 185 <p> ··· 199 199 200 200 {/* Combining */} 201 201 <MainCard title="Combining Filters"> 202 - <ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300"> 202 + <ul className="space-y-1 text-sm text-gray-600 dark:text-zinc-300"> 203 203 <li> 204 204 <Q q="t:goblin r:rare" /> both (AND) 205 205 </li>
+1 -1
src/components/SetSymbol.tsx
··· 20 20 }; 21 21 22 22 const RARITY_CLASSES: Record<string, string> = { 23 - common: "text-rarity-common dark:text-gray-400", 23 + common: "text-rarity-common dark:text-zinc-300", 24 24 uncommon: "text-rarity-uncommon", 25 25 rare: "text-rarity-rare", 26 26 mythic: "text-rarity-mythic",
+4 -4
src/components/UserMenu.tsx
··· 37 37 <button 38 38 type="button" 39 39 onClick={() => setIsOpen(!isOpen)} 40 - className="flex items-center gap-2 px-3 py-2 bg-gray-700 dark:bg-gray-800 rounded-lg hover:bg-gray-600 dark:hover:bg-gray-700 transition-colors" 40 + className="flex items-center gap-2 px-3 py-2 bg-gray-700 dark:bg-zinc-800 rounded-lg hover:bg-gray-600 dark:hover:bg-zinc-700 transition-colors" 41 41 aria-label="User menu" 42 42 aria-expanded={isOpen} 43 43 > ··· 54 54 </button> 55 55 56 56 {isOpen && ( 57 - <div className="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg shadow-lg overflow-hidden z-50"> 57 + <div className="absolute right-0 mt-2 w-48 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg overflow-hidden z-50"> 58 58 <Link 59 59 to="/profile/$did" 60 60 params={{ did: session.info.sub }} 61 61 onClick={() => setIsOpen(false)} 62 - className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm" 62 + className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm" 63 63 > 64 64 <User size={16} /> 65 65 <span>View Profile</span> ··· 70 70 signOut(); 71 71 setIsOpen(false); 72 72 }} 73 - className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm" 73 + className="w-full flex items-center gap-2 px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm" 74 74 > 75 75 <LogOut size={16} /> 76 76 <span>Sign Out</span>
+4 -4
src/components/comments/CommentForm.tsx
··· 78 78 /> 79 79 <div className="flex items-center justify-end gap-2"> 80 80 {isPending && ( 81 - <span className="text-sm text-gray-500 dark:text-gray-400"> 81 + <span className="text-sm text-gray-500 dark:text-zinc-300"> 82 82 Saving... 83 83 </span> 84 84 )} 85 85 {!isPending && isEditMode && isDirty && ( 86 - <span className="text-sm text-gray-500 dark:text-gray-400"> 86 + <span className="text-sm text-gray-500 dark:text-zinc-300"> 87 87 Unsaved changes 88 88 </span> 89 89 )} ··· 92 92 type="button" 93 93 onClick={onCancel} 94 94 disabled={isPending} 95 - className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300 disabled:opacity-50" 95 + className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300 disabled:opacity-50" 96 96 > 97 97 Cancel 98 98 </button> ··· 103 103 disabled={!hasContent || isPending} 104 104 className={`px-3 py-1.5 text-sm font-medium rounded-md disabled:opacity-50 disabled:cursor-not-allowed ${ 105 105 isEditMode 106 - ? "bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300" 106 + ? "bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300" 107 107 : "bg-blue-600 hover:bg-blue-700 text-white" 108 108 }`} 109 109 >
+13 -13
src/components/comments/CommentItem.tsx
··· 123 123 124 124 if (isError || !record) { 125 125 return ( 126 - <div className="py-3 text-sm text-gray-400 dark:text-gray-500 italic"> 126 + <div className="py-3 text-sm text-gray-400 dark:text-zinc-400 italic"> 127 127 [Failed to load {type}] 128 128 </div> 129 129 ); ··· 137 137 <Link 138 138 to="/profile/$did" 139 139 params={{ did }} 140 - className="font-medium text-gray-900 dark:text-gray-100 hover:underline" 140 + className="font-medium text-gray-900 dark:text-zinc-100 hover:underline" 141 141 > 142 142 @{handle ?? did.slice(0, 16)} 143 143 </Link> 144 - <span className="text-gray-400 dark:text-gray-500">·</span> 144 + <span className="text-gray-400 dark:text-zinc-400">·</span> 145 145 <ClientDate 146 146 dateString={record.createdAt} 147 147 format="relative" 148 - className="text-gray-500 dark:text-gray-400" 148 + className="text-gray-500 dark:text-zinc-300" 149 149 /> 150 150 {record.updatedAt && record.updatedAt !== record.createdAt && ( 151 - <span className="text-gray-400 dark:text-gray-500 text-xs"> 151 + <span className="text-gray-400 dark:text-zinc-400 text-xs"> 152 152 (edited) 153 153 </span> 154 154 )} 155 155 </div> 156 156 157 - <div className="mt-1 text-gray-800 dark:text-gray-200"> 157 + <div className="mt-1 text-gray-800 dark:text-zinc-200"> 158 158 <RichtextRenderer doc={record.content} /> 159 159 </div> 160 160 ··· 163 163 <button 164 164 type="button" 165 165 onClick={() => setShowReplyForm(!showReplyForm)} 166 - className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200" 166 + className="flex items-center gap-1 text-sm text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-200" 167 167 > 168 168 <MessageSquare className="w-4 h-4" /> 169 169 {replyCount > 0 && <span>{replyCount}</span>} 170 170 </button> 171 171 ) : ( 172 172 replyCount > 0 && ( 173 - <span className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400"> 173 + <span className="flex items-center gap-1 text-sm text-gray-500 dark:text-zinc-300"> 174 174 <MessageSquare className="w-4 h-4" /> 175 175 <span>{replyCount}</span> 176 176 </span> ··· 187 187 deleteCommentMutation.isPending || 188 188 deleteReplyMutation.isPending 189 189 } 190 - className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400" 190 + className="flex items-center gap-1 text-sm text-gray-500 dark:text-zinc-300 hover:text-red-600 dark:hover:text-red-400" 191 191 > 192 192 <Trash2 className="w-4 h-4" /> 193 193 </button> ··· 217 217 <div className="flex items-start gap-3"> 218 218 <div className="flex-1"> 219 219 <div className="flex items-center gap-2"> 220 - <div className="h-4 w-24 bg-gray-200 dark:bg-slate-700 rounded motion-safe:animate-pulse" /> 221 - <div className="h-4 w-16 bg-gray-200 dark:bg-slate-700 rounded motion-safe:animate-pulse" /> 220 + <div className="h-4 w-24 bg-gray-200 dark:bg-zinc-700 rounded motion-safe:animate-pulse" /> 221 + <div className="h-4 w-16 bg-gray-200 dark:bg-zinc-700 rounded motion-safe:animate-pulse" /> 222 222 </div> 223 223 <div className="mt-2 space-y-2"> 224 - <div className="h-4 w-full bg-gray-200 dark:bg-slate-700 rounded motion-safe:animate-pulse" /> 225 - <div className="h-4 w-3/4 bg-gray-200 dark:bg-slate-700 rounded motion-safe:animate-pulse" /> 224 + <div className="h-4 w-full bg-gray-200 dark:bg-zinc-700 rounded motion-safe:animate-pulse" /> 225 + <div className="h-4 w-3/4 bg-gray-200 dark:bg-zinc-700 rounded motion-safe:animate-pulse" /> 226 226 </div> 227 227 </div> 228 228 </div>
+1 -1
src/components/comments/CommentThread.tsx
··· 45 45 return ( 46 46 <div 47 47 className={ 48 - depth > 0 ? "pl-4 border-l border-gray-200 dark:border-slate-700" : "" 48 + depth > 0 ? "pl-4 border-l border-gray-200 dark:border-zinc-600" : "" 49 49 } 50 50 > 51 51 <CommentItem
+12 -12
src/components/comments/CommentsPanel.tsx
··· 71 71 ); 72 72 73 73 return ( 74 - <div className={`flex flex-col ${maxHeight} bg-white dark:bg-slate-900`}> 75 - <div className="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-slate-700"> 74 + <div className={`flex flex-col ${maxHeight} bg-white dark:bg-zinc-900`}> 75 + <div className="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-zinc-600"> 76 76 <div className="flex items-center gap-2"> 77 - <MessageSquare className="w-5 h-5 text-gray-600 dark:text-gray-400" /> 78 - <h2 className="font-semibold text-gray-900 dark:text-gray-100"> 77 + <MessageSquare className="w-5 h-5 text-gray-600 dark:text-zinc-300" /> 78 + <h2 className="font-semibold text-gray-900 dark:text-zinc-100"> 79 79 {title} 80 80 </h2> 81 81 {count > 0 && ( 82 - <span className="text-sm text-gray-500 dark:text-gray-400"> 82 + <span className="text-sm text-gray-500 dark:text-zinc-300"> 83 83 ({count}) 84 84 </span> 85 85 )} ··· 88 88 <button 89 89 type="button" 90 90 onClick={onClose} 91 - className="p-1 rounded-md hover:bg-gray-100 dark:hover:bg-slate-800 text-gray-500 dark:text-gray-400" 91 + className="p-1 rounded-md hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-500 dark:text-zinc-300" 92 92 > 93 93 <X className="w-5 h-5" /> 94 94 </button> ··· 97 97 98 98 <div className="flex-1 overflow-y-auto px-4"> 99 99 {commentsQuery.isLoading && ( 100 - <div className="py-8 text-center text-gray-500 dark:text-gray-400"> 100 + <div className="py-8 text-center text-gray-500 dark:text-zinc-300"> 101 101 Loading comments... 102 102 </div> 103 103 )} 104 104 105 105 {!commentsQuery.isLoading && comments.length === 0 && ( 106 - <div className="py-8 text-center text-gray-500 dark:text-gray-400"> 106 + <div className="py-8 text-center text-gray-500 dark:text-zinc-300"> 107 107 No comments yet. Be the first to comment! 108 108 </div> 109 109 )} 110 110 111 111 {comments.length > 0 && ( 112 - <div className="divide-y divide-gray-100 dark:divide-slate-800"> 112 + <div className="divide-y divide-gray-100 dark:divide-zinc-800"> 113 113 {comments.map((comment) => ( 114 114 <CommentThread 115 115 key={`${comment.did}/${comment.rkey}`} ··· 138 138 </div> 139 139 140 140 {session && ( 141 - <div className="border-t border-gray-200 dark:border-slate-700 px-4 py-2"> 141 + <div className="border-t border-gray-200 dark:border-zinc-600 px-4 py-2"> 142 142 {showForm ? ( 143 143 <CommentForm 144 144 onSubmit={handleSubmit} ··· 151 151 <button 152 152 type="button" 153 153 onClick={() => setShowForm(true)} 154 - className="w-full text-left px-3 py-2 text-sm text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-slate-800 rounded-md hover:bg-gray-100 dark:hover:bg-slate-700" 154 + className="w-full text-left px-3 py-2 text-sm text-gray-500 dark:text-zinc-300 bg-gray-50 dark:bg-zinc-800 rounded-md hover:bg-gray-100 dark:hover:bg-zinc-700" 155 155 > 156 156 Write a comment... 157 157 </button> ··· 160 160 )} 161 161 162 162 {!session && ( 163 - <div className="border-t border-gray-200 dark:border-slate-700 px-4 py-3 text-center text-sm text-gray-500 dark:text-gray-400"> 163 + <div className="border-t border-gray-200 dark:border-zinc-600 px-4 py-3 text-center text-sm text-gray-500 dark:text-zinc-300"> 164 164 Sign in to comment 165 165 </div> 166 166 )}
+4 -4
src/components/deck/BulkEditPreview.tsx
··· 24 24 25 25 export function BulkEditPreview({ lines }: BulkEditPreviewProps) { 26 26 return ( 27 - <div className="flex-1 p-4 border-l border-gray-200 dark:border-slate-700"> 27 + <div className="flex-1 p-4 border-l border-gray-200 dark:border-zinc-600"> 28 28 {lines.map((line) => ( 29 29 <PreviewRow key={line.lineKey} line={line} /> 30 30 ))} ··· 43 43 case "pending": 44 44 return ( 45 45 <div className={ROW_CLASS}> 46 - <span className="text-gray-400 dark:text-gray-500 italic truncate"> 46 + <span className="text-gray-400 dark:text-zinc-400 italic truncate"> 47 47 {line.name}... 48 48 </span> 49 49 </div> ··· 76 76 ? "bg-amber-50 dark:bg-amber-900/40 hover:bg-amber-100 dark:hover:bg-amber-900/50" 77 77 : line.isNew 78 78 ? "bg-green-50 dark:bg-green-900/40 hover:bg-green-100 dark:hover:bg-green-900/50" 79 - : "hover:bg-gray-100 dark:hover:bg-slate-800"; 79 + : "hover:bg-gray-100 dark:hover:bg-zinc-800"; 80 80 81 81 return ( 82 82 <div 83 83 className={`${ROW_CLASS} flex items-center gap-2 cursor-default rounded px-1 -mx-1 ${bgClass}`} 84 84 {...hoverProps} 85 85 > 86 - <span className="text-gray-600 dark:text-gray-400 text-xs w-4 text-right flex-shrink-0"> 86 + <span className="text-gray-600 dark:text-zinc-300 text-xs w-4 text-right flex-shrink-0"> 87 87 {line.quantity} 88 88 </span> 89 89 <span className="text-gray-900 dark:text-white truncate flex-1 min-w-0">
+1 -1
src/components/deck/CardDragOverlay.tsx
··· 16 16 return ( 17 17 <DragOverlay> 18 18 {draggedCardId && cardData ? ( 19 - <div className="bg-gray-100 dark:bg-slate-800 rounded px-2 py-1 shadow-lg opacity-90 cursor-grabbing"> 19 + <div className="bg-gray-100 dark:bg-zinc-800 rounded px-2 py-1 shadow-lg opacity-90 cursor-grabbing"> 20 20 <div className="flex items-center gap-2"> 21 21 <span className="text-gray-900 dark:text-white text-sm font-medium"> 22 22 {cardData.name}
+15 -15
src/components/deck/CardModal.tsx
··· 117 117 role="dialog" 118 118 aria-modal="true" 119 119 aria-labelledby={titleId} 120 - className="bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-slate-700" 120 + className="bg-white dark:bg-zinc-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-zinc-600" 121 121 > 122 122 {/* Header */} 123 - <div className="flex items-start justify-between p-6 border-b border-gray-200 dark:border-slate-800"> 123 + <div className="flex items-start justify-between p-6 border-b border-gray-200 dark:border-zinc-700"> 124 124 <div className="flex-1 min-w-0"> 125 125 {primaryFace ? ( 126 126 <> ··· 138 138 )} 139 139 </div> 140 140 {primaryFace.type_line && ( 141 - <div className="text-sm text-gray-600 dark:text-gray-400"> 141 + <div className="text-sm text-gray-600 dark:text-zinc-300"> 142 142 {primaryFace.type_line} 143 143 </div> 144 144 )} ··· 156 156 type="button" 157 157 onClick={onClose} 158 158 aria-label="Close" 159 - className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors ml-4" 159 + className="text-gray-400 hover:text-gray-600 dark:hover:text-zinc-300 transition-colors ml-4" 160 160 > 161 161 <X className="w-6 h-6" /> 162 162 </button> ··· 179 179 180 180 {/* Quantity */} 181 181 <div> 182 - <div className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> 182 + <div className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2"> 183 183 Quantity 184 184 </div> 185 185 <div className="flex items-center gap-3"> ··· 187 187 type="button" 188 188 onClick={() => handleQuantityChange(quantity - 1)} 189 189 disabled={readOnly || quantity <= 1} 190 - className="p-2 rounded-lg bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" 190 + className="p-2 rounded-lg bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" 191 191 > 192 - <Minus className="w-4 h-4 text-gray-700 dark:text-gray-300" /> 192 + <Minus className="w-4 h-4 text-gray-700 dark:text-zinc-300" /> 193 193 </button> 194 194 <input 195 195 type="number" ··· 201 201 ) 202 202 } 203 203 disabled={readOnly} 204 - className="w-20 px-3 py-2 text-center bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed" 204 + className="w-20 px-3 py-2 text-center bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed" 205 205 /> 206 206 <button 207 207 type="button" 208 208 onClick={() => handleQuantityChange(quantity + 1)} 209 209 disabled={readOnly} 210 - className="p-2 rounded-lg bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" 210 + className="p-2 rounded-lg bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" 211 211 > 212 - <Plus className="w-4 h-4 text-gray-700 dark:text-gray-300" /> 212 + <Plus className="w-4 h-4 text-gray-700 dark:text-zinc-300" /> 213 213 </button> 214 214 </div> 215 215 </div> 216 216 217 217 {/* Section */} 218 218 <div> 219 - <div className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> 219 + <div className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2"> 220 220 Section 221 221 </div> 222 222 <select 223 223 value={card.section} 224 224 onChange={(e) => onMoveToSection(e.target.value as Section)} 225 225 disabled={readOnly} 226 - className="w-full px-4 py-2 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed" 226 + className="w-full px-4 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed" 227 227 > 228 228 <option value="commander">Commander</option> 229 229 <option value="mainboard">Mainboard</option> ··· 234 234 235 235 {/* Tags */} 236 236 <div> 237 - <div className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> 237 + <div className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2"> 238 238 Tags 239 239 </div> 240 240 <div className="mb-2"> ··· 266 266 </div> 267 267 268 268 {/* Footer */} 269 - <div className="flex items-center justify-between p-6 border-t border-gray-200 dark:border-slate-800"> 269 + <div className="flex items-center justify-between p-6 border-t border-gray-200 dark:border-zinc-700"> 270 270 <button 271 271 type="button" 272 272 onClick={handleDelete} ··· 279 279 <button 280 280 type="button" 281 281 onClick={onClose} 282 - className="px-6 py-2 bg-gray-200 dark:bg-slate-800 hover:bg-gray-300 dark:hover:bg-slate-700 text-gray-900 dark:text-white rounded-lg transition-colors" 282 + className="px-6 py-2 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 text-gray-900 dark:text-white rounded-lg transition-colors" 283 283 > 284 284 Close 285 285 </button>
+9 -9
src/components/deck/CardSearchAutocomplete.tsx
··· 212 212 <div className="flex items-center gap-2 flex-shrink-0"> 213 213 <label 214 214 htmlFor={toggleId} 215 - className="text-sm text-gray-700 dark:text-gray-300 whitespace-nowrap" 215 + className="text-sm text-gray-700 dark:text-zinc-300 whitespace-nowrap" 216 216 > 217 217 Legal only 218 218 </label> ··· 224 224 onClick={() => setLegalityFilterEnabled(!legalityFilterEnabled)} 225 225 className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${ 226 226 legalityFilterEnabled 227 - ? "bg-blue-500 dark:bg-blue-600" 228 - : "bg-gray-300 dark:bg-gray-600" 227 + ? "bg-cyan-600" 228 + : "bg-gray-300 dark:bg-zinc-600" 229 229 }`} 230 230 > 231 231 <span ··· 250 250 } 251 251 }} 252 252 placeholder="Search for a card..." 253 - className="w-full px-4 py-2 pr-10 bg-white dark:bg-slate-900 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400" 253 + className="w-full px-4 py-2 pr-10 bg-white dark:bg-zinc-900 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-cyan-500 dark:focus:ring-cyan-400" 254 254 /> 255 255 256 256 {isFetching && debouncedSearch.trim().length > 0 && ( 257 257 <div className="absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none"> 258 - <div className="w-5 h-5 border-2 border-gray-300 dark:border-slate-600 border-t-blue-500 dark:border-t-blue-400 rounded-full animate-spin" /> 258 + <div className="w-5 h-5 border-2 border-gray-300 dark:border-zinc-600 border-t-cyan-500 dark:border-t-cyan-400 rounded-full animate-spin" /> 259 259 </div> 260 260 )} 261 261 ··· 264 264 ref={dropdownRef} 265 265 onMouseLeave={handleMouseLeaveDropdown} 266 266 role="listbox" 267 - className="absolute z-50 w-full mt-1 bg-white dark:bg-slate-900 border border-gray-300 dark:border-slate-700 rounded-lg shadow-lg max-h-96 overflow-y-auto top-full" 267 + className="absolute z-50 w-full mt-1 bg-white dark:bg-zinc-900 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg max-h-96 overflow-y-auto top-full" 268 268 > 269 269 {hasResults ? ( 270 270 <div className="py-1"> ··· 288 288 onClick={() => handleCardSelect(card)} 289 289 className={`w-full px-3 py-1.5 text-left cursor-pointer transition-colors ${ 290 290 index === selectedIndex 291 - ? "bg-blue-100 dark:bg-blue-900/30" 292 - : "hover:bg-gray-100 dark:hover:bg-slate-800" 291 + ? "bg-cyan-100 dark:bg-cyan-900/50" 292 + : "hover:bg-gray-100 dark:hover:bg-zinc-800" 293 293 }`} 294 294 > 295 295 <div className="flex items-center justify-between gap-2"> ··· 307 307 })} 308 308 </div> 309 309 ) : ( 310 - <div className="px-4 py-8 text-center text-gray-500 dark:text-gray-400"> 310 + <div className="px-4 py-8 text-center text-gray-500 dark:text-zinc-300"> 311 311 No results found 312 312 </div> 313 313 )}
+2 -2
src/components/deck/CommonTagsOverlay.tsx
··· 100 100 )} 101 101 102 102 {/* Background */} 103 - <div className="absolute inset-0 bg-white/90 dark:bg-slate-800/90 rounded" /> 103 + <div className="absolute inset-0 bg-white/90 dark:bg-zinc-800/90 rounded" /> 104 104 105 105 {/* Content */} 106 106 <div className="relative flex items-center justify-between gap-2"> 107 107 <span className="truncate text-gray-900 dark:text-white"> 108 108 {tag.tagName} 109 109 </span> 110 - <span className="text-xs opacity-70 flex-shrink-0 text-gray-600 dark:text-gray-400"> 110 + <span className="text-xs opacity-70 flex-shrink-0 text-gray-600 dark:text-zinc-300"> 111 111 {tag.count} 112 112 </span> 113 113 </div>
+8 -8
src/components/deck/DeckActionsMenu.tsx
··· 104 104 <button 105 105 type="button" 106 106 onClick={() => setIsOpen(!isOpen)} 107 - className="p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors" 107 + className="p-2 text-gray-600 dark:text-zinc-300 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-zinc-800 rounded-lg transition-colors" 108 108 aria-label="Deck actions" 109 109 aria-expanded={isOpen} 110 110 > ··· 112 112 </button> 113 113 114 114 {isOpen && ( 115 - <div className="absolute left-0 mt-2 w-48 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg shadow-lg overflow-hidden z-50"> 115 + <div className="absolute left-0 mt-2 w-48 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg overflow-hidden z-50"> 116 116 <Link 117 117 to="/profile/$did/deck/$rkey/play" 118 118 params={{ did, rkey }} 119 - className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm flex items-center gap-2" 119 + className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm flex items-center gap-2" 120 120 onClick={() => setIsOpen(false)} 121 121 > 122 122 <Play size={14} /> ··· 125 125 <Link 126 126 to="/profile/$did/deck/$rkey/export" 127 127 params={{ did, rkey }} 128 - className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm flex items-center gap-2" 128 + className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm flex items-center gap-2" 129 129 onClick={() => setIsOpen(false)} 130 130 > 131 131 <Download size={14} /> ··· 133 133 </Link> 134 134 {!readOnly && ( 135 135 <> 136 - <div className="border-t border-gray-200 dark:border-gray-700" /> 136 + <div className="border-t border-gray-200 dark:border-zinc-600" /> 137 137 <button 138 138 type="button" 139 139 onClick={handleSetAllToCheapest} 140 - className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm" 140 + className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm" 141 141 > 142 142 Set all to cheapest 143 143 </button> 144 144 <button 145 145 type="button" 146 146 onClick={handleSetAllToBest} 147 - className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-900 dark:text-white text-sm" 147 + className="w-full text-left px-4 py-3 hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors text-gray-900 dark:text-white text-sm" 148 148 > 149 149 Set all to best 150 150 </button> 151 - <div className="border-t border-gray-200 dark:border-gray-700" /> 151 + <div className="border-t border-gray-200 dark:border-zinc-600" /> 152 152 <button 153 153 type="button" 154 154 onClick={() => {
+1 -1
src/components/deck/DeckHeader.tsx
··· 69 69 value={format || ""} 70 70 onChange={(e) => onFormatChange(e.target.value)} 71 71 disabled={readOnly} 72 - className="px-4 py-2 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" 72 + className="px-4 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" 73 73 > 74 74 <option value="">No Format</option> 75 75 {FORMAT_GROUPS.map((group) => (
+5 -5
src/components/deck/DeckSection.tsx
··· 81 81 }, [sortedGroupNames, groupedCards, cardMap, sortBy]); 82 82 83 83 return ( 84 - <div className="mb-8 pb-8 border-b border-gray-200 dark:border-slate-800 last:border-b-0 last:pb-0"> 84 + <div className="mb-8 pb-8 border-b border-gray-200 dark:border-zinc-700 last:border-b-0 last:pb-0"> 85 85 <DroppableSection section={section} isDragging={isDragging}> 86 86 <DroppableSectionHeader> 87 87 <h2 className="text-xl font-bold text-gray-900 dark:text-white"> 88 88 {sectionNames[section]} 89 89 </h2> 90 - <span className="text-sm text-gray-600 dark:text-gray-400"> 90 + <span className="text-sm text-gray-600 dark:text-zinc-300"> 91 91 {totalQuantity} {totalQuantity === 1 ? "card" : "cards"} 92 92 </span> 93 93 </DroppableSectionHeader> 94 94 {cards.length === 0 ? ( 95 - <div className="bg-gray-100 dark:bg-slate-800 rounded-lg p-6 border-2 border-dashed border-gray-300 dark:border-slate-700"> 96 - <p className="text-gray-500 dark:text-gray-400 text-center"> 95 + <div className="bg-gray-100 dark:bg-zinc-800 rounded-lg p-6 border-2 border-dashed border-gray-300 dark:border-zinc-600"> 96 + <p className="text-gray-500 dark:text-zinc-300 text-center"> 97 97 No cards in {sectionNames[section].toLowerCase()} 98 98 </p> 99 99 </div> ··· 168 168 enabled={groupedCards.get(groupName)?.forTag ?? false} 169 169 isDragging={isDragging} 170 170 > 171 - <div className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-1"> 171 + <div className="text-sm font-semibold text-gray-700 dark:text-zinc-300 mb-1"> 172 172 {groupName} ({groupQuantity}) 173 173 </div> 174 174 <div className="space-y-1">
+4 -4
src/components/deck/DeckStats.tsx
··· 24 24 25 25 if (isLoading) { 26 26 return ( 27 - <div className="mt-8 pt-8 border-t border-gray-200 dark:border-slate-700"> 27 + <div className="mt-8 pt-8 border-t border-gray-200 dark:border-zinc-600"> 28 28 <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4"> 29 29 Statistics 30 30 </h2> 31 - <div className="flex items-center justify-center h-48 bg-gray-100 dark:bg-slate-800 rounded-lg"> 32 - <div className="text-gray-500 dark:text-gray-400"> 31 + <div className="flex items-center justify-center h-48 bg-gray-100 dark:bg-zinc-800 rounded-lg"> 32 + <div className="text-gray-500 dark:text-zinc-300"> 33 33 Loading statistics... 34 34 </div> 35 35 </div> ··· 49 49 } 50 50 51 51 return ( 52 - <div className="mt-8 pt-8 border-t border-gray-200 dark:border-slate-700"> 52 + <div className="mt-8 pt-8 border-t border-gray-200 dark:border-zinc-600"> 53 53 <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4"> 54 54 Statistics 55 55 </h2>
+7 -7
src/components/deck/DeleteDeckDialog.tsx
··· 65 65 role="alertdialog" 66 66 aria-modal="true" 67 67 aria-labelledby={titleId} 68 - className="bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-slate-700" 68 + className="bg-white dark:bg-zinc-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-zinc-600" 69 69 > 70 70 {/* Header */} 71 - <div className="flex items-center gap-3 p-6 border-b border-gray-200 dark:border-slate-800"> 71 + <div className="flex items-center gap-3 p-6 border-b border-gray-200 dark:border-zinc-700"> 72 72 <div className="p-2 bg-red-100 dark:bg-red-900/30 rounded-full"> 73 73 <AlertTriangle className="w-5 h-5 text-red-600 dark:text-red-400" /> 74 74 </div> ··· 82 82 83 83 {/* Body */} 84 84 <form onSubmit={handleSubmit} className="p-6 space-y-4"> 85 - <p className="text-gray-600 dark:text-gray-400"> 85 + <p className="text-gray-600 dark:text-zinc-300"> 86 86 This action <strong>cannot</strong> be undone. This will 87 87 permanently delete the deck and all its cards. 88 88 </p> ··· 90 90 <div> 91 91 <label 92 92 htmlFor={inputId} 93 - className="block text-sm text-gray-700 dark:text-gray-300 mb-2" 93 + className="block text-sm text-gray-700 dark:text-zinc-300 mb-2" 94 94 > 95 95 Please type{" "} 96 - <span className="font-mono font-semibold text-gray-900 dark:text-white bg-gray-100 dark:bg-slate-800 px-1.5 py-0.5 rounded"> 96 + <span className="font-mono font-semibold text-gray-900 dark:text-white bg-gray-100 dark:bg-zinc-800 px-1.5 py-0.5 rounded"> 97 97 {deckName} 98 98 </span>{" "} 99 99 to confirm. ··· 105 105 onChange={(e) => setConfirmText(e.target.value)} 106 106 disabled={isDeleting} 107 107 autoComplete="off" 108 - className="w-full px-4 py-2 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" 108 + className="w-full px-4 py-2 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" 109 109 placeholder="Deck name" 110 110 /> 111 111 </div> ··· 116 116 type="button" 117 117 onClick={onClose} 118 118 disabled={isDeleting} 119 - className="px-4 py-2 bg-gray-200 dark:bg-slate-800 hover:bg-gray-300 dark:hover:bg-slate-700 text-gray-900 dark:text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed" 119 + className="px-4 py-2 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 text-gray-900 dark:text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed" 120 120 > 121 121 Cancel 122 122 </button>
+4 -4
src/components/deck/DraggableCard.tsx
··· 71 71 {...attributes} 72 72 {...(disabled ? {} : listeners)} 73 73 type="button" 74 - className="group relative rounded px-2 py-1 w-full text-left md:touch-none bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700" 74 + className="group relative rounded px-2 py-1 w-full text-left md:touch-none bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700" 75 75 style={{ 76 76 opacity: isDragging ? 0.5 : 1, 77 77 cursor: disabled ? "pointer" : isDragging ? "grabbing" : "grab", ··· 94 94 > 95 95 <div 96 96 ref={highlightRef} 97 - className="absolute inset-0 rounded bg-amber-100 dark:bg-slate-700 opacity-0 pointer-events-none" 97 + className="absolute inset-0 rounded bg-amber-100 dark:bg-zinc-700 opacity-0 pointer-events-none" 98 98 /> 99 99 <div className="flex items-baseline gap-2"> 100 - <span className="text-gray-600 dark:text-gray-400 font-mono text-xs w-4 text-right flex-shrink-0"> 100 + <span className="text-gray-600 dark:text-zinc-300 font-mono text-xs w-4 text-right flex-shrink-0"> 101 101 {card.quantity} 102 102 </span> 103 103 <span className="text-gray-900 dark:text-white text-sm truncate flex-1 min-w-0 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'wght'_400] motion-safe:group-hover:[font-variation-settings:'wght'_500]"> ··· 118 118 {primaryFace?.mana_cost ? ( 119 119 <ManaCost cost={primaryFace.mana_cost} size="small" /> 120 120 ) : isLoading ? ( 121 - <div className="h-5 w-12 bg-gray-300 dark:bg-slate-700 rounded animate-pulse" /> 121 + <div className="h-5 w-12 bg-gray-300 dark:bg-zinc-700 rounded animate-pulse" /> 122 122 ) : null} 123 123 </div> 124 124 </div>
+1 -1
src/components/deck/DroppableTagGroup.tsx
··· 53 53 <div className="absolute inset-0 bg-cyan-500/20 dark:bg-cyan-600/30 rounded-lg z-10" /> 54 54 {/* Label */} 55 55 <div className="absolute inset-0 flex items-center justify-center z-20"> 56 - <div className="bg-cyan-500 dark:bg-cyan-700 text-white px-3 py-2 rounded-lg text-sm font-semibold shadow-lg"> 56 + <div className="bg-cyan-400 text-gray-900 px-3 py-2 rounded-lg text-sm font-semibold shadow-lg"> 57 57 Drop to add "{tagName}" 58 58 </div> 59 59 </div>
+1 -1
src/components/deck/GoldfishDragDropProvider.tsx
··· 116 116 <img 117 117 src={imageSrc} 118 118 alt="Dragging card" 119 - className="h-40 aspect-[5/7] rounded-[4.75%/3.5%] bg-gray-200 dark:bg-slate-700 shadow-2xl" 119 + className="h-40 aspect-[5/7] rounded-[4.75%/3.5%] bg-gray-200 dark:bg-zinc-700 shadow-2xl" 120 120 style={{ backgroundImage: PLACEHOLDER_STRIPES }} 121 121 draggable={false} 122 122 />
+2 -2
src/components/deck/GoldfishView.tsx
··· 86 86 if (cards.length === 0) return null; 87 87 88 88 return ( 89 - <div className="mt-8 pt-8 border-t border-gray-200 dark:border-slate-700"> 89 + <div className="mt-8 pt-8 border-t border-gray-200 dark:border-zinc-600"> 90 90 <SeedEmbed /> 91 91 <div className="flex items-center justify-between mb-4"> 92 92 <h2 className="text-lg font-semibold text-gray-900 dark:text-white"> ··· 96 96 <button 97 97 type="button" 98 98 onClick={newHand} 99 - className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-slate-700" 99 + className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 text-gray-700 dark:text-zinc-300 hover:bg-gray-200 dark:hover:bg-zinc-700" 100 100 > 101 101 New Hand 102 102 </button>
+4 -4
src/components/deck/TagAutocomplete.tsx
··· 97 97 onBlur={handleBlur} 98 98 placeholder={placeholder} 99 99 disabled={disabled} 100 - className="flex-1 px-3 py-2 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed" 100 + className="flex-1 px-3 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-cyan-500 disabled:opacity-50 disabled:cursor-not-allowed" 101 101 /> 102 102 <button 103 103 type="button" 104 104 onClick={() => handleAdd(value)} 105 105 disabled={disabled} 106 - className="px-4 py-2 bg-cyan-600 hover:bg-cyan-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white rounded-lg transition-colors" 106 + className="px-4 py-2 bg-cyan-400 hover:bg-cyan-300 disabled:bg-gray-400 disabled:cursor-not-allowed text-gray-900 rounded-lg transition-colors" 107 107 > 108 108 Add 109 109 </button> ··· 113 113 <div 114 114 id={listboxId} 115 115 role="listbox" 116 - className="absolute z-10 mt-1 w-full bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto" 116 + className="absolute z-10 mt-1 w-full bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg max-h-48 overflow-y-auto" 117 117 > 118 118 {filtered.map((tag, i) => ( 119 119 <div ··· 129 129 className={`px-3 py-2 text-sm cursor-pointer ${ 130 130 i === selectedIndex 131 131 ? "bg-cyan-100 dark:bg-cyan-900 text-cyan-900 dark:text-cyan-100" 132 - : "text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-slate-700" 132 + : "text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-zinc-700" 133 133 }`} 134 134 > 135 135 {tag}
+5 -5
src/components/deck/ValidationBadge.tsx
··· 64 64 </button> 65 65 66 66 {isOpen && ( 67 - <div className="absolute top-full left-0 mt-1 w-[28rem] max-h-[32rem] overflow-y-auto bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 z-50"> 67 + <div className="absolute top-full left-0 mt-1 w-[28rem] max-h-[32rem] overflow-y-auto bg-white dark:bg-zinc-800 rounded-lg shadow-lg border border-gray-200 dark:border-zinc-600 z-50"> 68 68 <div className="p-3 space-y-3"> 69 69 {errors.length > 0 && ( 70 70 <ViolationGroup ··· 121 121 const ruleText = rule?.ruleText; 122 122 123 123 return ( 124 - <li className="text-sm text-gray-600 dark:text-gray-400"> 124 + <li className="text-sm text-gray-600 dark:text-zinc-300"> 125 125 <button 126 126 type="button" 127 127 onClick={() => ruleText && setIsExpanded(!isExpanded)} 128 - className={`flex items-start gap-1 text-left w-full ${ruleText ? "cursor-pointer hover:text-gray-900 dark:hover:text-gray-200" : "cursor-default"}`} 128 + className={`flex items-start gap-1 text-left w-full ${ruleText ? "cursor-pointer hover:text-gray-900 dark:hover:text-zinc-200" : "cursor-default"}`} 129 129 > 130 130 {ruleText ? ( 131 131 <ChevronRight ··· 135 135 <span className="w-4" /> 136 136 )} 137 137 <span> 138 - <span className="font-mono text-xs text-gray-400 dark:text-gray-500 mr-1.5"> 138 + <span className="font-mono text-xs text-gray-400 dark:text-zinc-400 mr-1.5"> 139 139 [{violation.rule}] 140 140 </span> 141 141 {violation.message} 142 142 </span> 143 143 </button> 144 144 {isExpanded && ruleText && ( 145 - <div className="ml-5 mt-1.5 pl-3 border-l-2 border-gray-200 dark:border-slate-600 text-xs text-gray-500 dark:text-gray-400 italic"> 145 + <div className="ml-5 mt-1.5 pl-3 border-l-2 border-gray-200 dark:border-zinc-600 text-xs text-gray-500 dark:text-zinc-300 italic"> 146 146 {ruleText} 147 147 </div> 148 148 )}
+4 -4
src/components/deck/ViewControls.tsx
··· 37 37 <div className="flex items-center gap-1.5"> 38 38 <label 39 39 htmlFor={groupById} 40 - className="text-xs font-medium text-gray-600 dark:text-gray-400" 40 + className="text-xs font-medium text-gray-600 dark:text-zinc-300" 41 41 > 42 42 Group: 43 43 </label> ··· 45 45 id={groupById} 46 46 value={groupBy} 47 47 onChange={(e) => onGroupByChange(e.target.value as GroupBy)} 48 - className="min-w-32 cursor-pointer rounded bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 py-1 px-2 text-sm text-gray-900 dark:text-white hover:bg-gray-200 dark:hover:bg-slate-700 focus:outline-none focus:ring-1 focus:ring-cyan-500 transition-colors" 48 + className="min-w-32 cursor-pointer rounded bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 py-1 px-2 text-sm text-gray-900 dark:text-white hover:bg-gray-200 dark:hover:bg-zinc-700 focus:outline-none focus:ring-1 focus:ring-cyan-500 transition-colors" 49 49 > 50 50 {GROUP_BY_OPTIONS.map((option) => ( 51 51 <option key={option.value} value={option.value}> ··· 58 58 <div className="flex items-center gap-1.5"> 59 59 <label 60 60 htmlFor={sortById} 61 - className="text-xs font-medium text-gray-600 dark:text-gray-400" 61 + className="text-xs font-medium text-gray-600 dark:text-zinc-300" 62 62 > 63 63 Sort: 64 64 </label> ··· 66 66 id={sortById} 67 67 value={sortBy} 68 68 onChange={(e) => onSortByChange(e.target.value as SortBy)} 69 - className="min-w-28 cursor-pointer rounded bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 py-1 px-2 text-sm text-gray-900 dark:text-white hover:bg-gray-200 dark:hover:bg-slate-700 focus:outline-none focus:ring-1 focus:ring-cyan-500 transition-colors" 69 + className="min-w-28 cursor-pointer rounded bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 py-1 px-2 text-sm text-gray-900 dark:text-white hover:bg-gray-200 dark:hover:bg-zinc-700 focus:outline-none focus:ring-1 focus:ring-cyan-500 transition-colors" 70 70 > 71 71 {SORT_BY_OPTIONS.map((option) => ( 72 72 <option key={option.value} value={option.value}>
+2 -2
src/components/deck/goldfish/GoldfishBattlefield.tsx
··· 27 27 className={`isolate relative w-full h-full rounded-lg border-2 border-dashed transition-colors ${ 28 28 isOver 29 29 ? "border-green-500 bg-green-500/10" 30 - : "border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-800/50" 30 + : "border-gray-300 dark:border-zinc-600 bg-gray-50 dark:bg-zinc-800/50" 31 31 }`} 32 32 > 33 33 {cards.length === 0 && ( 34 - <div className="absolute inset-0 flex items-center justify-center text-gray-400 dark:text-gray-500 text-sm pointer-events-none"> 34 + <div className="absolute inset-0 flex items-center justify-center text-gray-400 dark:text-zinc-400 text-sm pointer-events-none"> 35 35 Battlefield 36 36 </div> 37 37 )}
+2 -2
src/components/deck/goldfish/GoldfishBoard.tsx
··· 113 113 return ( 114 114 <GoldfishDragDropProvider onDragEnd={handleDragEnd}> 115 115 <SeedEmbed /> 116 - <div className="flex h-full gap-4 p-4 bg-white dark:bg-slate-950"> 116 + <div className="flex h-full gap-4 p-4 bg-white dark:bg-zinc-950"> 117 117 {/* Left: Card Preview */} 118 118 <div className="w-64 flex-shrink-0"> 119 119 {hoveredCardData && !hoveredCard?.isFaceDown ? ( ··· 126 126 } 127 127 /> 128 128 ) : ( 129 - <div className="w-full aspect-[5/7] rounded-lg bg-gray-100 dark:bg-slate-800 flex items-center justify-center text-gray-400 dark:text-gray-500 text-sm"> 129 + <div className="w-full aspect-[5/7] rounded-lg bg-gray-100 dark:bg-zinc-800 flex items-center justify-center text-gray-400 dark:text-zinc-400 text-sm"> 130 130 {hoveredCard?.isFaceDown ? "Face down" : "Hover a card"} 131 131 </div> 132 132 )}
+1 -1
src/components/deck/goldfish/GoldfishCard.tsx
··· 60 60 <img 61 61 src={imageSrc} 62 62 alt={card?.name ?? "Card"} 63 - className={`rounded-[4.75%/3.5%] bg-gray-200 dark:bg-slate-700 ${sizeClass} aspect-[5/7]`} 63 + className={`rounded-[4.75%/3.5%] bg-gray-200 dark:bg-zinc-700 ${sizeClass} aspect-[5/7]`} 64 64 style={{ backgroundImage: PLACEHOLDER_STRIPES }} 65 65 draggable={false} 66 66 loading="lazy"
+2 -2
src/components/deck/goldfish/GoldfishHand.tsx
··· 27 27 className={`flex gap-2 overflow-x-auto p-2 min-h-[11rem] rounded-lg border-2 border-dashed transition-colors ${ 28 28 isOver 29 29 ? "border-blue-500 bg-blue-500/10" 30 - : "border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-800/50" 30 + : "border-gray-300 dark:border-zinc-600 bg-gray-50 dark:bg-zinc-800/50" 31 31 }`} 32 32 > 33 33 {cards.length === 0 ? ( 34 - <div className="flex items-center justify-center w-full text-gray-400 dark:text-gray-500 text-sm"> 34 + <div className="flex items-center justify-center w-full text-gray-400 dark:text-zinc-400 text-sm"> 35 35 Hand is empty 36 36 </div> 37 37 ) : (
+2 -2
src/components/deck/goldfish/GoldfishPile.tsx
··· 35 35 className={`rounded-lg border-2 border-dashed transition-colors ${ 36 36 isOver 37 37 ? "border-purple-500 bg-purple-500/10" 38 - : "border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-800/50" 38 + : "border-gray-300 dark:border-zinc-600 bg-gray-50 dark:bg-zinc-800/50" 39 39 }`} 40 40 > 41 41 <button 42 42 type="button" 43 43 onClick={() => setExpanded(!expanded)} 44 - className="w-full flex items-center justify-between p-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-t-lg" 44 + className="w-full flex items-center justify-between p-2 text-sm font-medium text-gray-700 dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 rounded-t-lg" 45 45 > 46 46 <span> 47 47 {label} ({cards.length})
+14 -14
src/components/deck/goldfish/GoldfishSidebar.tsx
··· 42 42 }); 43 43 44 44 return ( 45 - <div className="w-48 flex flex-col gap-3 p-2 bg-gray-100 dark:bg-slate-900 rounded-lg overflow-y-auto overflow-x-hidden"> 45 + <div className="w-48 flex flex-col gap-3 p-2 bg-gray-100 dark:bg-zinc-900 rounded-lg overflow-y-auto overflow-x-hidden"> 46 46 {/* Library */} 47 47 <div 48 48 ref={setLibraryRef} 49 49 className={`rounded-lg border-2 border-dashed p-2 transition-colors ${ 50 50 isOverLibrary 51 51 ? "border-green-500 bg-green-500/10" 52 - : "border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-800/50" 52 + : "border-gray-300 dark:border-zinc-600 bg-gray-50 dark:bg-zinc-800/50" 53 53 }`} 54 54 > 55 55 <div className="flex items-center justify-between mb-2"> 56 - <span className="text-sm font-medium text-gray-700 dark:text-gray-300"> 56 + <span className="text-sm font-medium text-gray-700 dark:text-zinc-300"> 57 57 Library ({library.length}) 58 58 </span> 59 - <span className="text-xs text-gray-500 dark:text-gray-400"> 59 + <span className="text-xs text-gray-500 dark:text-zinc-300"> 60 60 D to draw 61 61 </span> 62 62 </div> ··· 69 69 fromLibrary 70 70 /> 71 71 ) : ( 72 - <div className="h-40 aspect-[5/7] rounded-[4.75%/3.5%] border-2 border-dashed border-gray-300 dark:border-slate-600" /> 72 + <div className="h-40 aspect-[5/7] rounded-[4.75%/3.5%] border-2 border-dashed border-gray-300 dark:border-zinc-600" /> 73 73 )} 74 74 </div> 75 75 ··· 96 96 {/* Player Stats */} 97 97 <div className="space-y-2"> 98 98 {/* Life */} 99 - <div className="flex items-center justify-between p-2 rounded bg-gray-50 dark:bg-slate-800"> 99 + <div className="flex items-center justify-between p-2 rounded bg-gray-50 dark:bg-zinc-800"> 100 100 <button 101 101 type="button" 102 102 onClick={() => onAdjustLife(-1)} 103 - className="p-1 rounded hover:bg-gray-200 dark:hover:bg-slate-700" 103 + className="p-1 rounded hover:bg-gray-200 dark:hover:bg-zinc-700" 104 104 aria-label="Decrease life" 105 105 > 106 106 <Minus className="w-4 h-4" /> 107 107 </button> 108 - <span className="text-lg font-bold text-gray-700 dark:text-gray-200"> 108 + <span className="text-lg font-bold text-gray-700 dark:text-zinc-200"> 109 109 {player.life} 110 110 </span> 111 111 <button 112 112 type="button" 113 113 onClick={() => onAdjustLife(1)} 114 - className="p-1 rounded hover:bg-gray-200 dark:hover:bg-slate-700" 114 + className="p-1 rounded hover:bg-gray-200 dark:hover:bg-zinc-700" 115 115 aria-label="Increase life" 116 116 > 117 117 <Plus className="w-4 h-4" /> ··· 119 119 </div> 120 120 121 121 {/* Poison */} 122 - <div className="flex items-center justify-between p-2 rounded bg-gray-50 dark:bg-slate-800"> 122 + <div className="flex items-center justify-between p-2 rounded bg-gray-50 dark:bg-zinc-800"> 123 123 <button 124 124 type="button" 125 125 onClick={() => onAdjustPoison(-1)} 126 - className="p-1 rounded hover:bg-gray-200 dark:hover:bg-slate-700" 126 + className="p-1 rounded hover:bg-gray-200 dark:hover:bg-zinc-700" 127 127 aria-label="Decrease poison" 128 128 > 129 129 <Minus className="w-4 h-4" /> ··· 135 135 <button 136 136 type="button" 137 137 onClick={() => onAdjustPoison(1)} 138 - className="p-1 rounded hover:bg-gray-200 dark:hover:bg-slate-700" 138 + className="p-1 rounded hover:bg-gray-200 dark:hover:bg-zinc-700" 139 139 aria-label="Increase poison" 140 140 > 141 141 <Plus className="w-4 h-4" /> ··· 156 156 <button 157 157 type="button" 158 158 onClick={onMulligan} 159 - className="w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded bg-gray-200 dark:bg-slate-700 text-gray-700 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-slate-600" 159 + className="w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded bg-gray-200 dark:bg-zinc-700 text-gray-700 dark:text-zinc-200 hover:bg-gray-300 dark:hover:bg-zinc-600" 160 160 > 161 161 <RefreshCw className="w-4 h-4" /> 162 162 Mulligan ··· 171 171 </div> 172 172 173 173 {/* Keyboard hints */} 174 - <div className="text-xs text-gray-400 dark:text-gray-500 space-y-1"> 174 + <div className="text-xs text-gray-400 dark:text-zinc-400 space-y-1"> 175 175 <p>T/Space: tap • F: flip</p> 176 176 <p>G: graveyard • E: exile</p> 177 177 <p>H: hand • B: play</p>
+21 -21
src/components/deck/stats/ManaBreakdown.tsx
··· 51 51 selection.type === type; 52 52 53 53 return ( 54 - <div className="bg-white dark:bg-slate-900 rounded-lg p-4 border border-gray-200 dark:border-slate-700 col-span-full xl:col-span-2"> 55 - <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4"> 54 + <div className="bg-white dark:bg-zinc-900 rounded-lg p-4 border border-gray-200 dark:border-zinc-600 col-span-full xl:col-span-2"> 55 + <h3 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-4"> 56 56 Mana Breakdown 57 57 </h3> 58 58 ··· 82 82 83 83 {/* Land Production section */} 84 84 {totalLands > 0 && ( 85 - <div className="mt-4 pt-3 border-t border-gray-200 dark:border-slate-700"> 86 - <div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-2"> 85 + <div className="mt-4 pt-3 border-t border-gray-200 dark:border-zinc-600"> 86 + <div className="text-xs font-medium text-gray-500 dark:text-zinc-300 mb-2"> 87 87 Land Production ({totalLands} lands) 88 88 </div> 89 89 <div ··· 113 113 )} 114 114 115 115 {/* Legend */} 116 - <div className="mt-4 pt-3 border-t border-gray-200 dark:border-slate-700 flex flex-wrap items-center justify-between gap-2"> 116 + <div className="mt-4 pt-3 border-t border-gray-200 dark:border-zinc-600 flex flex-wrap items-center justify-between gap-2"> 117 117 <div className="flex gap-3 text-xs"> 118 118 <span 119 119 className="flex items-center gap-1 cursor-help" 120 120 title="Untapped lands, fast mana rocks, shocklands (pay life = your choice)" 121 121 > 122 122 <span className="w-2 h-2 rounded-full bg-emerald-500" /> 123 - <span className="text-gray-600 dark:text-gray-400">Immediate</span> 123 + <span className="text-gray-600 dark:text-zinc-300">Immediate</span> 124 124 </span> 125 125 <span 126 126 className="flex items-center gap-1 cursor-help" 127 127 title="Check lands, fast lands, battle lands - may enter tapped based on game state" 128 128 > 129 129 <span className="w-2 h-2 rounded-full bg-sky-500" /> 130 - <span className="text-gray-600 dark:text-gray-400"> 130 + <span className="text-gray-600 dark:text-zinc-300"> 131 131 Conditional 132 132 </span> 133 133 </span> ··· 136 136 title="Tap lands, mana dorks (summoning sickness)" 137 137 > 138 138 <span className="w-2 h-2 rounded-full bg-rose-500" /> 139 - <span className="text-gray-600 dark:text-gray-400">Delayed</span> 139 + <span className="text-gray-600 dark:text-zinc-300">Delayed</span> 140 140 </span> 141 141 <span 142 142 className="flex items-center gap-1 cursor-help" 143 143 title="Bouncelands - enter tapped and return a land" 144 144 > 145 - <span className="w-2 h-2 rounded-full bg-violet-500" /> 146 - <span className="text-gray-600 dark:text-gray-400">Bounce</span> 145 + <span className="w-2 h-2 rounded-full bg-cyan-500" /> 146 + <span className="text-gray-600 dark:text-zinc-300">Bounce</span> 147 147 </span> 148 148 </div> 149 149 {totalSources > 0 && ( 150 150 <div 151 - className="text-xs text-gray-600 dark:text-gray-400 cursor-help" 151 + className="text-xs text-gray-600 dark:text-zinc-300 cursor-help" 152 152 title={`${totalImmediate} of ${totalSources} sources can produce mana the turn they enter`} 153 153 > 154 154 {immediatePercent}% of sources produce mana immediately ··· 206 206 isSelected("symbol") 207 207 ? "ring-2 ring-blue-500 bg-blue-50 dark:bg-blue-900/30" 208 208 : hasSymbols 209 - ? "hover:bg-gray-100 dark:hover:bg-slate-800" 209 + ? "hover:bg-gray-100 dark:hover:bg-zinc-800" 210 210 : "cursor-default" 211 211 }`} 212 212 > ··· 226 226 {Math.round(data.symbolPercent)}% 227 227 </div> 228 228 <div 229 - className="text-xs text-gray-500 dark:text-gray-400 cursor-help" 229 + className="text-xs text-gray-500 dark:text-zinc-300 cursor-help" 230 230 title={`${data.symbolCount} ${colorName.toLowerCase()} mana symbols in card costs`} 231 231 > 232 232 {data.symbolCount} pips ··· 237 237 {sourceCount > 0 && ( 238 238 <div className="w-full mt-2"> 239 239 <div 240 - className="flex h-3 rounded-md overflow-hidden bg-gray-200 dark:bg-slate-700 cursor-help" 240 + className="flex h-3 rounded-md overflow-hidden bg-gray-200 dark:bg-zinc-700 cursor-help" 241 241 title={`${sourceCount} sources produce ${colorName.toLowerCase()} mana (${Math.round((sourceCount / totalSources) * 100)}% of all sources)`} 242 242 > 243 243 {data.immediateSourceCount > 0 && ( ··· 282 282 {data.bounceSourceCount > 0 && ( 283 283 <button 284 284 type="button" 285 - className={`bg-violet-500 transition-opacity ${ 285 + className={`bg-cyan-500 transition-opacity ${ 286 286 isSelected("bounce") 287 287 ? "opacity-100" 288 288 : "opacity-80 hover:opacity-100" ··· 294 294 )} 295 295 </div> 296 296 <div 297 - className="text-xs text-gray-500 dark:text-gray-400 text-center mt-1 cursor-help" 297 + className="text-xs text-gray-500 dark:text-zinc-300 text-center mt-1 cursor-help" 298 298 title={`${sourceCount} cards produce ${colorName.toLowerCase()} mana`} 299 299 > 300 300 {sourceCount} sources ··· 349 349 {/* Coverage bar - mana colored */} 350 350 <button 351 351 type="button" 352 - className={`relative w-full h-4 rounded overflow-hidden bg-gray-200 dark:bg-slate-700 transition-opacity ${ 352 + className={`relative w-full h-4 rounded overflow-hidden bg-gray-200 dark:bg-zinc-700 transition-opacity ${ 353 353 isSelected ? "ring-2 ring-blue-500" : "hover:opacity-90" 354 354 }`} 355 355 onClick={onSelect} ··· 359 359 className={`h-full ${MANA_BAR_COLORS[data.color]}`} 360 360 style={{ width: `${data.landSourcePercent}%` }} 361 361 /> 362 - <span className="absolute inset-0 flex items-center justify-center text-xs font-medium text-gray-700 dark:text-gray-300"> 362 + <span className="absolute inset-0 flex items-center justify-center text-xs font-medium text-gray-700 dark:text-zinc-300"> 363 363 {Math.round(data.landSourcePercent)}% 364 364 </span> 365 365 </button> ··· 367 367 {/* Tempo bar - smaller, shows quality of those lands */} 368 368 {landCount > 0 && ( 369 369 <div 370 - className="w-full h-1.5 rounded-full overflow-hidden bg-gray-200 dark:bg-slate-700 flex cursor-help" 370 + className="w-full h-1.5 rounded-full overflow-hidden bg-gray-200 dark:bg-zinc-700 flex cursor-help" 371 371 title={`Land tempo: ${data.landImmediateCount} immediate, ${data.landConditionalCount} conditional, ${data.landDelayedCount} delayed, ${data.landBounceCount} bounce`} 372 372 > 373 373 {data.landImmediateCount > 0 && ( ··· 390 390 )} 391 391 {data.landBounceCount > 0 && ( 392 392 <div 393 - className="h-full bg-violet-500" 393 + className="h-full bg-cyan-500" 394 394 style={{ width: `${bouncePercent}%` }} 395 395 /> 396 396 )} ··· 398 398 )} 399 399 400 400 <div 401 - className="text-xs text-gray-500 dark:text-gray-400 text-center cursor-help" 401 + className="text-xs text-gray-500 dark:text-zinc-300 text-center cursor-help" 402 402 title={`${Math.round(data.landProductionPercent)}% of your lands' total mana production is ${colorName.toLowerCase()}`} 403 403 > 404 404 {Math.round(data.landProductionPercent)}% of symbols on lands
+6 -6
src/components/deck/stats/ManaCurveChart.tsx
··· 17 17 18 18 const COLORS = { 19 19 permanent: "var(--color-cyan-500)", 20 - spell: "var(--color-violet-500)", 20 + spell: "var(--color-amber-500)", 21 21 permanentHover: "var(--color-cyan-600)", 22 - spellHover: "var(--color-violet-600)", 22 + spellHover: "var(--color-amber-600)", 23 23 }; 24 24 25 25 export function ManaCurveChart({ ··· 38 38 selection.type === type; 39 39 40 40 return ( 41 - <div className="bg-white dark:bg-slate-900 rounded-lg p-4 border border-gray-200 dark:border-slate-700"> 42 - <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4"> 41 + <div className="bg-white dark:bg-zinc-900 rounded-lg p-4 border border-gray-200 dark:border-zinc-600"> 42 + <h3 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-4"> 43 43 Mana Curve 44 44 </h3> 45 45 <div className="h-48"> ··· 114 114 className="w-3 h-3 rounded" 115 115 style={{ backgroundColor: COLORS.permanent }} 116 116 /> 117 - <span className="text-xs text-gray-600 dark:text-gray-400"> 117 + <span className="text-xs text-gray-600 dark:text-zinc-300"> 118 118 Permanents 119 119 </span> 120 120 </div> ··· 123 123 className="w-3 h-3 rounded" 124 124 style={{ backgroundColor: COLORS.spell }} 125 125 /> 126 - <span className="text-xs text-gray-600 dark:text-gray-400"> 126 + <span className="text-xs text-gray-600 dark:text-zinc-300"> 127 127 Spells 128 128 </span> 129 129 </div>
+4 -4
src/components/deck/stats/SpeedPieChart.tsx
··· 29 29 const total = data.reduce((sum, d) => sum + d.count, 0); 30 30 31 31 return ( 32 - <div className="bg-white dark:bg-slate-900 rounded-lg p-4 border border-gray-200 dark:border-slate-700"> 33 - <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4"> 32 + <div className="bg-white dark:bg-zinc-900 rounded-lg p-4 border border-gray-200 dark:border-zinc-600"> 33 + <h3 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-4"> 34 34 Speed 35 35 </h3> 36 36 <div className="h-48 flex"> ··· 76 76 className="w-2 h-2 rounded-full flex-shrink-0" 77 77 style={{ backgroundColor: SPEED_COLORS[entry.category] }} 78 78 /> 79 - <span className="text-xs text-gray-600 dark:text-gray-400"> 79 + <span className="text-xs text-gray-600 dark:text-zinc-300"> 80 80 {SPEED_LABELS[entry.category]} 81 81 </span> 82 - <span className="text-xs text-gray-500 dark:text-gray-500 ml-auto"> 82 + <span className="text-xs text-gray-500 dark:text-zinc-400 ml-auto"> 83 83 {total > 0 ? Math.round((entry.count / total) * 100) : 0}% 84 84 </span> 85 85 </button>
+5 -5
src/components/deck/stats/StatsCardList.tsx
··· 38 38 }); 39 39 40 40 return ( 41 - <div className="bg-gray-50 dark:bg-slate-800 rounded-lg p-4 min-w-48"> 42 - <h4 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> 41 + <div className="bg-gray-50 dark:bg-zinc-800 rounded-lg p-4 min-w-48"> 42 + <h4 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2"> 43 43 {title} 44 44 </h4> 45 45 {uniqueCards.length === 0 ? ( 46 - <p className="text-sm text-gray-500 dark:text-gray-400 italic"> 46 + <p className="text-sm text-gray-500 dark:text-zinc-300 italic"> 47 47 No cards 48 48 </p> 49 49 ) : ( ··· 62 62 <li key={`${deckCard.scryfallId}-${faceIdx}`}> 63 63 <button 64 64 type="button" 65 - className="w-full text-left px-2 py-1 rounded hover:bg-gray-200 dark:hover:bg-slate-700 transition-colors flex items-center gap-2" 65 + className="w-full text-left px-2 py-1 rounded hover:bg-gray-200 dark:hover:bg-zinc-700 transition-colors flex items-center gap-2" 66 66 onMouseEnter={() => onCardHover(deckCard.scryfallId)} 67 67 onMouseLeave={() => onCardHover(null)} 68 68 onClick={() => onCardClick?.(deckCard)} 69 69 > 70 - <span className="text-gray-600 dark:text-gray-400 font-mono text-xs w-4 text-right flex-shrink-0"> 70 + <span className="text-gray-600 dark:text-zinc-300 font-mono text-xs w-4 text-right flex-shrink-0"> 71 71 {deckCard.quantity} 72 72 </span> 73 73 <span className="text-gray-900 dark:text-white text-sm truncate flex-1 min-w-0">
+8 -8
src/components/deck/stats/SubtypesPieChart.tsx
··· 10 10 11 11 const COLORS = [ 12 12 "var(--color-cyan-500)", 13 - "var(--color-violet-500)", 13 + "var(--color-cyan-500)", 14 14 "var(--color-amber-500)", 15 15 "var(--color-emerald-500)", 16 16 "var(--color-rose-500)", ··· 40 40 41 41 if (data.length === 0) { 42 42 return ( 43 - <div className="bg-white dark:bg-slate-900 rounded-lg p-4 border border-gray-200 dark:border-slate-700"> 44 - <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4"> 43 + <div className="bg-white dark:bg-zinc-900 rounded-lg p-4 border border-gray-200 dark:border-zinc-600"> 44 + <h3 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-4"> 45 45 Subtypes 46 46 </h3> 47 - <div className="h-48 flex items-center justify-center text-gray-500 dark:text-gray-400 text-sm"> 47 + <div className="h-48 flex items-center justify-center text-gray-500 dark:text-zinc-300 text-sm"> 48 48 No subtypes 49 49 </div> 50 50 </div> ··· 52 52 } 53 53 54 54 return ( 55 - <div className="bg-white dark:bg-slate-900 rounded-lg p-4 border border-gray-200 dark:border-slate-700"> 56 - <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4"> 55 + <div className="bg-white dark:bg-zinc-900 rounded-lg p-4 border border-gray-200 dark:border-zinc-600"> 56 + <h3 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-4"> 57 57 Subtypes 58 58 </h3> 59 59 <div className="h-48 flex"> ··· 99 99 className="w-2 h-2 rounded-full flex-shrink-0" 100 100 style={{ backgroundColor: getSubtypeColor(entry.type, index) }} 101 101 /> 102 - <span className="text-xs text-gray-600 dark:text-gray-400 truncate"> 102 + <span className="text-xs text-gray-600 dark:text-zinc-300 truncate"> 103 103 {entry.type} 104 104 </span> 105 - <span className="text-xs text-gray-500 dark:text-gray-500 ml-auto"> 105 + <span className="text-xs text-gray-500 dark:text-zinc-400 ml-auto"> 106 106 {Math.round((entry.count / total) * 100)}% 107 107 </span> 108 108 </button>
+5 -5
src/components/deck/stats/TypesPieChart.tsx
··· 12 12 Creature: "var(--color-emerald-500)", 13 13 Instant: "var(--color-cyan-500)", 14 14 Sorcery: "var(--color-amber-500)", 15 - Enchantment: "var(--color-violet-500)", 15 + Enchantment: "var(--color-sky-500)", 16 16 Artifact: "var(--color-slate-500)", 17 17 Planeswalker: "var(--color-orange-500)", 18 18 Land: "var(--color-lime-500)", ··· 36 36 const total = data.reduce((sum, d) => sum + d.count, 0); 37 37 38 38 return ( 39 - <div className="bg-white dark:bg-slate-900 rounded-lg p-4 border border-gray-200 dark:border-slate-700"> 40 - <h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-4"> 39 + <div className="bg-white dark:bg-zinc-900 rounded-lg p-4 border border-gray-200 dark:border-zinc-600"> 40 + <h3 className="text-sm font-medium text-gray-700 dark:text-zinc-300 mb-4"> 41 41 Card Types 42 42 </h3> 43 43 <div className="h-48 flex"> ··· 81 81 className="w-2 h-2 rounded-full flex-shrink-0" 82 82 style={{ backgroundColor: getTypeColor(entry.type) }} 83 83 /> 84 - <span className="text-xs text-gray-600 dark:text-gray-400 truncate"> 84 + <span className="text-xs text-gray-600 dark:text-zinc-300 truncate"> 85 85 {entry.type} 86 86 </span> 87 - <span className="text-xs text-gray-500 dark:text-gray-500 ml-auto"> 87 + <span className="text-xs text-gray-500 dark:text-zinc-400 ml-auto"> 88 88 {Math.round((entry.count / total) * 100)}% 89 89 </span> 90 90 </button>
+7 -7
src/components/list/DeleteListDialog.tsx
··· 63 63 role="alertdialog" 64 64 aria-modal="true" 65 65 aria-labelledby={titleId} 66 - className="bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-slate-700" 66 + className="bg-white dark:bg-zinc-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-zinc-600" 67 67 > 68 - <div className="flex items-center gap-3 p-6 border-b border-gray-200 dark:border-slate-800"> 68 + <div className="flex items-center gap-3 p-6 border-b border-gray-200 dark:border-zinc-700"> 69 69 <div className="p-2 bg-red-100 dark:bg-red-900/30 rounded-full"> 70 70 <AlertTriangle className="w-5 h-5 text-red-600 dark:text-red-400" /> 71 71 </div> ··· 78 78 </div> 79 79 80 80 <form onSubmit={handleSubmit} className="p-6 space-y-4"> 81 - <p className="text-gray-600 dark:text-gray-400"> 81 + <p className="text-gray-600 dark:text-zinc-300"> 82 82 This action <strong>cannot</strong> be undone. This will 83 83 permanently delete the list. 84 84 </p> ··· 86 86 <div> 87 87 <label 88 88 htmlFor={inputId} 89 - className="block text-sm text-gray-700 dark:text-gray-300 mb-2" 89 + className="block text-sm text-gray-700 dark:text-zinc-300 mb-2" 90 90 > 91 91 Please type{" "} 92 - <span className="font-mono font-semibold text-gray-900 dark:text-white bg-gray-100 dark:bg-slate-800 px-1.5 py-0.5 rounded"> 92 + <span className="font-mono font-semibold text-gray-900 dark:text-white bg-gray-100 dark:bg-zinc-800 px-1.5 py-0.5 rounded"> 93 93 {listName} 94 94 </span>{" "} 95 95 to confirm. ··· 101 101 onChange={(e) => setConfirmText(e.target.value)} 102 102 disabled={isDeleting} 103 103 autoComplete="off" 104 - className="w-full px-4 py-2 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" 104 + className="w-full px-4 py-2 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" 105 105 placeholder="List name" 106 106 /> 107 107 </div> ··· 111 111 type="button" 112 112 onClick={onClose} 113 113 disabled={isDeleting} 114 - className="px-4 py-2 bg-gray-200 dark:bg-slate-800 hover:bg-gray-300 dark:hover:bg-slate-700 text-gray-900 dark:text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed" 114 + className="px-4 py-2 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 text-gray-900 dark:text-white rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed" 115 115 > 116 116 Cancel 117 117 </button>
+2 -2
src/components/list/ListActionsMenu.tsx
··· 34 34 <button 35 35 type="button" 36 36 onClick={() => setIsOpen(!isOpen)} 37 - className="p-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg transition-colors" 37 + className="p-2 text-gray-600 dark:text-zinc-300 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-zinc-800 rounded-lg transition-colors" 38 38 aria-label="List actions" 39 39 aria-expanded={isOpen} 40 40 > ··· 42 42 </button> 43 43 44 44 {isOpen && ( 45 - <div className="absolute left-0 mt-2 w-48 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg shadow-lg overflow-hidden z-50"> 45 + <div className="absolute left-0 mt-2 w-48 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg overflow-hidden z-50"> 46 46 <button 47 47 type="button" 48 48 onClick={() => {
+8 -8
src/components/list/SaveToListDialog.tsx
··· 118 118 role="dialog" 119 119 aria-modal="true" 120 120 aria-labelledby={titleId} 121 - className="bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-slate-700" 121 + className="bg-white dark:bg-zinc-900 rounded-lg shadow-2xl max-w-md w-full pointer-events-auto border border-gray-300 dark:border-zinc-600" 122 122 > 123 123 {/* Header */} 124 - <div className="flex items-center gap-3 p-6 border-b border-gray-200 dark:border-slate-800"> 124 + <div className="flex items-center gap-3 p-6 border-b border-gray-200 dark:border-zinc-700"> 125 125 <div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-full"> 126 126 <Bookmark className="w-5 h-5 text-blue-600 dark:text-blue-400" /> 127 127 </div> ··· 140 140 <Loader2 className="w-6 h-6 animate-spin text-gray-400" /> 141 141 </div> 142 142 ) : lists.length === 0 ? ( 143 - <p className="text-gray-600 dark:text-gray-400 text-center py-4"> 143 + <p className="text-gray-600 dark:text-zinc-300 text-center py-4"> 144 144 You don't have any lists yet. Create one below! 145 145 </p> 146 146 ) : ( ··· 162 162 {/* Create new list */} 163 163 <form 164 164 onSubmit={handleCreateList} 165 - className="flex items-center gap-2 pt-2 border-t border-gray-200 dark:border-slate-800" 165 + className="flex items-center gap-2 pt-2 border-t border-gray-200 dark:border-zinc-700" 166 166 > 167 167 <input 168 168 id={inputId} ··· 171 171 onChange={(e) => setNewListName(e.target.value)} 172 172 disabled={createMutation.isPending} 173 173 placeholder="New list name..." 174 - className="flex-1 px-4 py-2 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" 174 + className="flex-1 px-4 py-2 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed" 175 175 /> 176 176 <button 177 177 type="submit" ··· 192 192 <button 193 193 type="button" 194 194 onClick={onClose} 195 - className="px-4 py-2 bg-gray-200 dark:bg-slate-800 hover:bg-gray-300 dark:hover:bg-slate-700 text-gray-900 dark:text-white rounded-lg transition-colors" 195 + className="px-4 py-2 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 text-gray-900 dark:text-white rounded-lg transition-colors" 196 196 > 197 197 Done 198 198 </button> ··· 243 243 className={`w-full flex items-center justify-between px-4 py-3 rounded-lg transition-colors ${ 244 244 isSaved 245 245 ? "bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/30" 246 - : "bg-gray-50 dark:bg-slate-800 hover:bg-gray-100 dark:hover:bg-slate-700" 246 + : "bg-gray-50 dark:bg-zinc-800 hover:bg-gray-100 dark:hover:bg-zinc-700" 247 247 }`} 248 248 > 249 249 <span ··· 252 252 {list.name} 253 253 </span> 254 254 <span 255 - className={`text-sm ${isSaved ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-gray-400"}`} 255 + className={`text-sm ${isSaved ? "text-blue-600 dark:text-blue-400" : "text-gray-500 dark:text-zinc-300"}`} 256 256 > 257 257 {toggleMutation.isPending ? ( 258 258 <Loader2 className="w-4 h-4 animate-spin" />
+10 -10
src/components/profile/ProfileHeader.tsx
··· 97 97 href={handleUrl} 98 98 target="_blank" 99 99 rel="noopener noreferrer" 100 - className="text-gray-400 hover:text-cyan-500 dark:text-gray-500 dark:hover:text-cyan-400 transition-colors" 100 + className="text-gray-400 hover:text-cyan-500 dark:text-zinc-400 dark:hover:text-cyan-400 transition-colors" 101 101 title={`Visit ${handleUrl}`} 102 102 > 103 103 <ExternalLink className="w-6 h-6" /> ··· 109 109 <div> 110 110 <label 111 111 htmlFor={pronounsId} 112 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" 112 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-1" 113 113 > 114 114 Pronouns 115 115 </label> ··· 126 126 }} 127 127 placeholder="e.g. she/her, they/them" 128 128 maxLength={64} 129 - className="px-3 py-2 w-full max-w-xs bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" 129 + className="px-3 py-2 w-full max-w-xs bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" 130 130 /> 131 131 </div> 132 132 133 133 {/* Bio editor */} 134 134 <div> 135 - <span className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> 135 + <span className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-1"> 136 136 Bio 137 137 </span> 138 138 <ProseMirrorEditor ··· 144 144 145 145 {/* Save status and done button */} 146 146 <div className="flex items-center justify-between"> 147 - <div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400"> 147 + <div className="flex items-center gap-2 text-sm text-gray-500 dark:text-zinc-300"> 148 148 {isSaving && <span>Saving...</span>} 149 149 {!isSaving && isDirty && <span>Unsaved changes</span>} 150 150 {!isSaving && !isDirty && hasContent && <span>Saved</span>} ··· 152 152 <button 153 153 type="button" 154 154 onClick={handleDone} 155 - className="px-4 py-2 text-sm font-medium rounded-lg bg-cyan-600 hover:bg-cyan-700 text-white" 155 + className="px-4 py-2 text-sm font-medium rounded-lg bg-cyan-400 hover:bg-cyan-300 text-gray-900" 156 156 > 157 157 Done 158 158 </button> ··· 176 176 href={handleUrl} 177 177 target="_blank" 178 178 rel="noopener noreferrer" 179 - className="text-gray-400 hover:text-cyan-500 dark:text-gray-500 dark:hover:text-cyan-400 transition-colors" 179 + className="text-gray-400 hover:text-cyan-500 dark:text-zinc-400 dark:hover:text-cyan-400 transition-colors" 180 180 title={`Visit ${handleUrl}`} 181 181 > 182 182 <ExternalLink className="w-6 h-6" /> ··· 185 185 </div> 186 186 {/* Pronouns */} 187 187 {profile?.pronouns && ( 188 - <p className="text-sm text-gray-500 dark:text-gray-400"> 188 + <p className="text-sm text-gray-500 dark:text-zinc-300"> 189 189 {profile.pronouns} 190 190 </p> 191 191 )} ··· 194 194 {hasContent && profile?.bio && ( 195 195 <RichtextRenderer 196 196 doc={profile.bio} 197 - className="text-gray-700 dark:text-gray-300" 197 + className="text-gray-700 dark:text-zinc-300" 198 198 /> 199 199 )} 200 200 ··· 203 203 <button 204 204 type="button" 205 205 onClick={handleStartEdit} 206 - className="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300" 206 + className="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300" 207 207 > 208 208 <Pencil className="w-4 h-4" /> 209 209 {hasContent || profile?.pronouns ? "Edit profile" : "Add bio"}
+4 -4
src/components/profile/ProfileLayout.tsx
··· 62 62 const isOwner = session?.info.sub === did; 63 63 64 64 return ( 65 - <div className="min-h-screen bg-white dark:bg-slate-900"> 65 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 66 66 <div className="max-w-7xl mx-auto px-6 py-16"> 67 67 {/* Profile Header */} 68 68 <ProfileHeader ··· 76 76 /> 77 77 78 78 {/* Tab Navigation */} 79 - <nav className="flex border-b border-gray-200 dark:border-slate-700 mb-6"> 79 + <nav className="flex border-b border-gray-200 dark:border-zinc-600 mb-6"> 80 80 <Link 81 81 to="/profile/$did" 82 82 params={{ did }} 83 83 activeOptions={{ exact: true }} 84 - className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 border-transparent hover:border-gray-300 dark:hover:border-gray-600 [&.active]:border-cyan-500 [&.active]:text-cyan-600 dark:[&.active]:text-cyan-400" 84 + className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-300 border-transparent hover:border-gray-300 dark:hover:border-zinc-600 [&.active]:border-cyan-500 [&.active]:text-cyan-600 dark:[&.active]:text-cyan-400" 85 85 > 86 86 Decks 87 87 </Link> 88 88 <Link 89 89 to="/profile/$did/lists" 90 90 params={{ did }} 91 - className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 border-transparent hover:border-gray-300 dark:hover:border-gray-600 [&.active]:border-cyan-500 [&.active]:text-cyan-600 dark:[&.active]:text-cyan-400" 91 + className="px-4 py-2 font-medium text-sm border-b-2 transition-colors text-gray-500 dark:text-zinc-300 hover:text-gray-700 dark:hover:text-zinc-300 border-transparent hover:border-gray-300 dark:hover:border-zinc-600 [&.active]:border-cyan-500 [&.active]:text-cyan-600 dark:[&.active]:text-cyan-400" 92 92 > 93 93 Lists 94 94 </Link>
+9 -9
src/components/richtext/CombinedAutocomplete.tsx
··· 141 141 }: MentionPopupContentProps) { 142 142 return ( 143 143 <div 144 - className="absolute z-50 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-600 rounded-lg shadow-lg py-1 w-56" 144 + className="absolute z-50 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg py-1 w-56" 145 145 style={{ top: position.top, left: position.left }} 146 146 role="listbox" 147 147 > 148 148 {options.length === 0 ? ( 149 - <div className="px-3 py-2 text-sm text-gray-500 dark:text-gray-400"> 149 + <div className="px-3 py-2 text-sm text-gray-500 dark:text-zinc-300"> 150 150 No matches 151 151 </div> 152 152 ) : ( ··· 159 159 className={`w-full px-3 py-2 text-left text-sm ${ 160 160 i === selectedIndex 161 161 ? "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-900 dark:text-cyan-100" 162 - : "text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-slate-700" 162 + : "text-gray-900 dark:text-zinc-100 hover:bg-gray-100 dark:hover:bg-zinc-700" 163 163 }`} 164 164 onMouseEnter={() => onSelectIndex(i)} 165 165 onMouseDown={(e) => { ··· 192 192 }: CardPopupContentProps) { 193 193 return ( 194 194 <div 195 - className="absolute z-50 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-600 rounded-lg shadow-lg py-1 w-64 max-h-64 overflow-y-auto" 195 + className="absolute z-50 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg py-1 w-64 max-h-64 overflow-y-auto" 196 196 style={{ top: position.top, left: position.left }} 197 197 role="listbox" 198 198 > 199 199 {options.length === 0 ? ( 200 - <div className="px-3 py-2 text-sm text-gray-500 dark:text-gray-400"> 200 + <div className="px-3 py-2 text-sm text-gray-500 dark:text-zinc-300"> 201 201 No cards found 202 202 </div> 203 203 ) : ( ··· 210 210 className={`w-full px-3 py-2 text-left text-sm ${ 211 211 i === selectedIndex 212 212 ? "bg-sky-50 dark:bg-sky-900/30 text-sky-900 dark:text-sky-100" 213 - : "text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-slate-700" 213 + : "text-gray-900 dark:text-zinc-100 hover:bg-gray-100 dark:hover:bg-zinc-700" 214 214 }`} 215 215 onMouseEnter={() => onSelectIndex(i)} 216 216 onMouseDown={(e) => { ··· 243 243 }: TagPopupContentProps) { 244 244 return ( 245 245 <div 246 - className="absolute z-50 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-600 rounded-lg shadow-lg py-1 w-56 max-h-64 overflow-y-auto" 246 + className="absolute z-50 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg py-1 w-56 max-h-64 overflow-y-auto" 247 247 style={{ top: position.top, left: position.left }} 248 248 role="listbox" 249 249 > 250 250 {options.length === 0 ? ( 251 - <div className="px-3 py-2 text-sm text-gray-500 dark:text-gray-400"> 251 + <div className="px-3 py-2 text-sm text-gray-500 dark:text-zinc-300"> 252 252 No tags found 253 253 </div> 254 254 ) : ( ··· 261 261 className={`w-full px-3 py-2 text-left text-sm ${ 262 262 i === selectedIndex 263 263 ? "bg-amber-100 dark:bg-amber-900/30 text-amber-900 dark:text-amber-100" 264 - : "text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-slate-700" 264 + : "text-gray-900 dark:text-zinc-100 hover:bg-gray-100 dark:hover:bg-zinc-700" 265 265 }`} 266 266 onMouseEnter={() => onSelectIndex(i)} 267 267 onMouseDown={(e) => {
+7 -7
src/components/richtext/LinkModal.tsx
··· 71 71 onClick={onClose} 72 72 aria-label="Close modal" 73 73 /> 74 - <div className="relative bg-white dark:bg-slate-800 rounded-lg shadow-xl p-4 w-full max-w-md mx-4"> 74 + <div className="relative bg-white dark:bg-zinc-800 rounded-lg shadow-xl p-4 w-full max-w-md mx-4"> 75 75 <div className="flex items-center justify-between mb-4"> 76 76 <h3 77 77 id={`${id}-title`} ··· 82 82 <button 83 83 type="button" 84 84 onClick={onClose} 85 - className="p-1 rounded hover:bg-gray-100 dark:hover:bg-slate-700 text-gray-500 dark:text-gray-400" 85 + className="p-1 rounded hover:bg-gray-100 dark:hover:bg-zinc-700 text-gray-500 dark:text-zinc-300" 86 86 > 87 87 <X className="w-5 h-5" /> 88 88 </button> ··· 92 92 <div> 93 93 <label 94 94 htmlFor={urlId} 95 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" 95 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-1" 96 96 > 97 97 URL 98 98 </label> ··· 103 103 value={url} 104 104 onChange={(e) => setUrl(e.target.value)} 105 105 placeholder="example.com" 106 - className="w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-md bg-white dark:bg-slate-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500" 106 + className="w-full px-3 py-2 border border-gray-300 dark:border-zinc-600 rounded-md bg-white dark:bg-zinc-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-blue-500" 107 107 /> 108 108 </div> 109 109 ··· 111 111 <div> 112 112 <label 113 113 htmlFor={textId} 114 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" 114 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-1" 115 115 > 116 116 Link Text 117 117 </label> ··· 121 121 value={text} 122 122 onChange={(e) => setText(e.target.value)} 123 123 placeholder="Display text (optional)" 124 - className="w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-md bg-white dark:bg-slate-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500" 124 + className="w-full px-3 py-2 border border-gray-300 dark:border-zinc-600 rounded-md bg-white dark:bg-zinc-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-blue-500" 125 125 /> 126 126 </div> 127 127 )} ··· 130 130 <button 131 131 type="button" 132 132 onClick={onClose} 133 - className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-md" 133 + className="px-4 py-2 text-sm font-medium text-gray-700 dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 rounded-md" 134 134 > 135 135 Cancel 136 136 </button>
+2 -2
src/components/richtext/ProseMirrorEditor.tsx
··· 247 247 }, 248 248 attributes: { 249 249 class: 250 - "focus:outline-none min-h-[8rem] p-3 text-gray-900 dark:text-gray-100", 250 + "focus:outline-none min-h-[8rem] p-3 text-gray-900 dark:text-zinc-100", 251 251 "data-placeholder": initialPlaceholderRef.current, 252 252 }, 253 253 }); ··· 262 262 263 263 return ( 264 264 <div ref={wrapperRef} className={`relative ${className ?? ""}`}> 265 - <div className="prosemirror-editor border border-gray-300 dark:border-slate-700 rounded-lg bg-white dark:bg-slate-800 overflow-hidden"> 265 + <div className="prosemirror-editor border border-gray-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 overflow-hidden"> 266 266 {showToolbar && <Toolbar view={viewRef.current} />} 267 267 <div ref={containerRef} /> 268 268 </div>
+4 -4
src/components/richtext/RichtextRenderer.tsx
··· 81 81 82 82 case "com.deckbelcher.richtext#codeBlock": 83 83 return ( 84 - <pre className="bg-gray-100 dark:bg-slate-800 rounded-lg p-3 my-2 overflow-x-auto"> 85 - <code className="font-mono text-sm text-gray-800 dark:text-gray-200"> 84 + <pre className="bg-gray-100 dark:bg-zinc-800 rounded-lg p-3 my-2 overflow-x-auto"> 85 + <code className="font-mono text-sm text-gray-800 dark:text-zinc-200"> 86 86 {block.text} 87 87 </code> 88 88 </pre> ··· 112 112 ); 113 113 114 114 case "com.deckbelcher.richtext#horizontalRuleBlock": 115 - return <hr className="my-4 border-gray-300 dark:border-slate-600" />; 115 + return <hr className="my-4 border-gray-300 dark:border-zinc-600" />; 116 116 117 117 default: { 118 118 const para = block as ParagraphBlock; ··· 257 257 258 258 case "com.deckbelcher.richtext.facet#code": 259 259 return ( 260 - <code className="bg-gray-100 dark:bg-slate-800 px-1 rounded font-mono text-sm"> 260 + <code className="bg-gray-100 dark:bg-zinc-800 px-1 rounded font-mono text-sm"> 261 261 {content} 262 262 </code> 263 263 );
+7 -7
src/components/richtext/RichtextSection.tsx
··· 94 94 availableTags={availableTags} 95 95 /> 96 96 <div className="flex items-center justify-between"> 97 - <div className="flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400"> 97 + <div className="flex items-center gap-2 text-sm text-gray-500 dark:text-zinc-300"> 98 98 {isSaving && <span>Saving...</span>} 99 99 {!isSaving && isDirty && <span>Unsaved changes</span>} 100 100 {!isSaving && !isDirty && hasContent && <span>Saved</span>} ··· 102 102 <button 103 103 type="button" 104 104 onClick={() => setIsEditing(false)} 105 - className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300" 105 + className="px-3 py-1.5 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300" 106 106 > 107 107 Done 108 108 </button> ··· 120 120 <button 121 121 type="button" 122 122 onClick={() => setIsEditing(true)} 123 - className="text-sm text-gray-400 dark:text-gray-500 hover:text-blue-600 dark:hover:text-blue-400 italic" 123 + className="text-sm text-gray-400 dark:text-zinc-400 hover:text-blue-600 dark:hover:text-blue-400 italic" 124 124 > 125 125 {emptyText} 126 126 </button> ··· 142 142 > 143 143 <RichtextRenderer 144 144 doc={document} 145 - className="text-gray-700 dark:text-gray-300" 145 + className="text-gray-700 dark:text-zinc-300" 146 146 /> 147 147 </div> 148 148 149 149 {needsTruncation && !isExpanded && ( 150 - <div className="absolute bottom-0 left-0 right-0 h-12 bg-gradient-to-t from-white dark:from-slate-900 to-transparent pointer-events-none" /> 150 + <div className="absolute bottom-0 left-0 right-0 h-12 bg-gradient-to-t from-white dark:from-zinc-900 to-transparent pointer-events-none" /> 151 151 )} 152 152 </div> 153 153 ··· 156 156 <button 157 157 type="button" 158 158 onClick={() => setIsExpanded(!isExpanded)} 159 - className="inline-flex items-center gap-1 px-2 py-1 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300" 159 + className="inline-flex items-center gap-1 px-2 py-1 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300" 160 160 > 161 161 {isExpanded ? ( 162 162 <> ··· 175 175 <button 176 176 type="button" 177 177 onClick={() => setIsEditing(true)} 178 - className="inline-flex items-center gap-1 px-2 py-1 text-sm font-medium rounded-md bg-gray-100 dark:bg-slate-800 hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-700 dark:text-gray-300" 178 + className="inline-flex items-center gap-1 px-2 py-1 text-sm font-medium rounded-md bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-700 dark:text-zinc-300" 179 179 > 180 180 <Pencil className="w-4 h-4" /> 181 181 Edit
+4 -4
src/components/richtext/Toolbar.tsx
··· 71 71 // Render placeholder to reserve space and prevent layout shift 72 72 // Height matches: p-2 (8px*2) + button p-1.5 (6px*2) + icon h-4 (16px) = 44px 73 73 return ( 74 - <div className="flex flex-wrap items-center gap-1 p-2 border-b border-gray-300 dark:border-slate-700 bg-gray-50 dark:bg-slate-800/50 min-h-11" /> 74 + <div className="flex flex-wrap items-center gap-1 p-2 border-b border-gray-300 dark:border-zinc-600 bg-gray-50 dark:bg-zinc-800/50 min-h-11" /> 75 75 ); 76 76 } 77 77 ··· 251 251 252 252 return ( 253 253 <> 254 - <div className="flex flex-wrap items-center gap-1 p-2 border-b border-gray-300 dark:border-slate-700 bg-gray-50 dark:bg-slate-800/50"> 254 + <div className="flex flex-wrap items-center gap-1 p-2 border-b border-gray-300 dark:border-zinc-600 bg-gray-50 dark:bg-zinc-800/50"> 255 255 {/* History */} 256 256 <ToolbarButton onClick={runUndo} active={false} title="Undo (Cmd+Z)"> 257 257 <Undo className="w-4 h-4" /> ··· 377 377 } 378 378 379 379 function ToolbarDivider() { 380 - return <div className="w-px h-5 bg-gray-300 dark:bg-slate-600 mx-1" />; 380 + return <div className="w-px h-5 bg-gray-300 dark:bg-zinc-600 mx-1" />; 381 381 } 382 382 383 383 interface ToolbarButtonProps { ··· 401 401 className={`p-1.5 rounded transition-colors ${ 402 402 active 403 403 ? "bg-blue-100 dark:bg-blue-900/50 text-blue-600 dark:text-blue-400" 404 - : "hover:bg-gray-200 dark:hover:bg-slate-700 text-gray-600 dark:text-gray-400" 404 + : "hover:bg-gray-200 dark:hover:bg-zinc-700 text-gray-600 dark:text-zinc-300" 405 405 }`} 406 406 > 407 407 {children}
+5 -5
src/components/richtext/schema.ts
··· 36 36 "blockquote", 37 37 { 38 38 class: 39 - "border-l-4 border-gray-300 dark:border-slate-600 pl-4 my-2 text-gray-600 dark:text-gray-400 italic", 39 + "border-l-4 border-gray-300 dark:border-zinc-600 pl-4 my-2 text-gray-600 dark:text-zinc-300 italic", 40 40 }, 41 41 0, 42 42 ]; ··· 47 47 group: "block", 48 48 parseDOM: [{ tag: "hr" }], 49 49 toDOM() { 50 - return ["hr", { class: "my-4 border-gray-300 dark:border-slate-600" }]; 50 + return ["hr", { class: "my-4 border-gray-300 dark:border-zinc-600" }]; 51 51 }, 52 52 }, 53 53 ··· 99 99 "pre", 100 100 { 101 101 class: 102 - "bg-gray-100 dark:bg-slate-800 rounded-lg p-3 my-2 overflow-x-auto", 102 + "bg-gray-100 dark:bg-zinc-800 rounded-lg p-3 my-2 overflow-x-auto", 103 103 ...(node.attrs.params ? { "data-params": node.attrs.params } : {}), 104 104 }, 105 105 [ 106 106 "code", 107 - { class: "font-mono text-sm text-gray-800 dark:text-gray-200" }, 107 + { class: "font-mono text-sm text-gray-800 dark:text-zinc-200" }, 108 108 0, 109 109 ], 110 110 ]; ··· 367 367 "code", 368 368 { 369 369 class: 370 - "bg-gray-100 dark:bg-slate-700 text-gray-800 dark:text-gray-200 px-1 py-0.5 rounded font-mono text-sm", 370 + "bg-gray-100 dark:bg-zinc-700 text-gray-800 dark:text-zinc-200 px-1 py-0.5 rounded font-mono text-sm", 371 371 }, 372 372 ]; 373 373 },
+6 -6
src/components/social/BacklinkModal.tsx
··· 134 134 role="dialog" 135 135 aria-modal="true" 136 136 aria-labelledby={titleId} 137 - className="bg-white dark:bg-slate-900 rounded-lg shadow-2xl max-w-xl w-full pointer-events-auto border border-gray-300 dark:border-slate-700 flex flex-col h-[70vh]" 137 + className="bg-white dark:bg-zinc-900 rounded-lg shadow-2xl max-w-xl w-full pointer-events-auto border border-gray-300 dark:border-zinc-600 flex flex-col h-[70vh]" 138 138 > 139 139 {/* Header */} 140 - <div className="flex items-center justify-between p-6 border-b border-gray-200 dark:border-slate-800 flex-shrink-0"> 140 + <div className="flex items-center justify-between p-6 border-b border-gray-200 dark:border-zinc-700 flex-shrink-0"> 141 141 <div className="flex items-center gap-3"> 142 142 <div className={`p-2 ${config.iconBg} rounded-full`}> 143 143 <Icon className={`w-5 h-5 ${config.iconColor}`} /> ··· 149 149 > 150 150 {config.title} 151 151 </h2> 152 - <p className="text-sm text-gray-500 dark:text-gray-400"> 152 + <p className="text-sm text-gray-500 dark:text-zinc-300"> 153 153 {total.toLocaleString()}{" "} 154 154 {total === 1 155 155 ? type === "likes" ··· 168 168 <button 169 169 type="button" 170 170 onClick={onClose} 171 - className="p-2 hover:bg-gray-100 dark:hover:bg-slate-800 rounded-lg transition-colors" 171 + className="p-2 hover:bg-gray-100 dark:hover:bg-zinc-800 rounded-lg transition-colors" 172 172 aria-label="Close" 173 173 > 174 - <X className="w-5 h-5 text-gray-500 dark:text-gray-400" /> 174 + <X className="w-5 h-5 text-gray-500 dark:text-zinc-300" /> 175 175 </button> 176 176 </div> 177 177 ··· 185 185 ))} 186 186 </div> 187 187 ) : allRecords.length === 0 ? ( 188 - <p className="text-gray-600 dark:text-gray-400 text-center py-4"> 188 + <p className="text-gray-600 dark:text-zinc-300 text-center py-4"> 189 189 No {type} yet 190 190 </p> 191 191 ) : (
+5 -5
src/components/social/BacklinkRow.tsx
··· 43 43 <Link 44 44 to="/profile/$did" 45 45 params={{ did }} 46 - className="block px-3 py-2 hover:bg-gray-100 dark:hover:bg-slate-800 rounded-lg text-gray-900 dark:text-gray-100" 46 + className="block px-3 py-2 hover:bg-gray-100 dark:hover:bg-zinc-800 rounded-lg text-gray-900 dark:text-zinc-100" 47 47 > 48 48 {isLoading ? ( 49 - <span className="inline-block w-24 h-4 bg-gray-200 dark:bg-slate-700 rounded animate-pulse" /> 49 + <span className="inline-block w-24 h-4 bg-gray-200 dark:bg-zinc-700 rounded animate-pulse" /> 50 50 ) : ( 51 51 <span>@{handle ?? did.slice(0, 20)}</span> 52 52 )} ··· 94 94 95 95 export function RowSkeleton() { 96 96 return ( 97 - <div className="p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg"> 98 - <div className="h-5 w-32 bg-gray-200 dark:bg-slate-700 rounded animate-pulse mb-2" /> 99 - <div className="h-4 w-48 bg-gray-200 dark:bg-slate-700 rounded animate-pulse" /> 97 + <div className="p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg"> 98 + <div className="h-5 w-32 bg-gray-200 dark:bg-zinc-700 rounded animate-pulse mb-2" /> 99 + <div className="h-4 w-48 bg-gray-200 dark:bg-zinc-700 rounded animate-pulse" /> 100 100 </div> 101 101 ); 102 102 }
+9 -9
src/components/social/SocialStats.tsx
··· 77 77 const statBase = "flex items-center gap-1 p-2 rounded-lg"; 78 78 const buttonBase = `${statBase} transition-colors ${ 79 79 session 80 - ? "hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer" 80 + ? "hover:bg-gray-100 dark:hover:bg-zinc-800 cursor-pointer" 81 81 : "cursor-default opacity-75" 82 82 }`; 83 83 ··· 99 99 className={`w-5 h-5 ${ 100 100 isLikedByUser 101 101 ? "text-rose-400 dark:text-red-400" 102 - : "text-gray-600 dark:text-gray-400" 102 + : "text-gray-600 dark:text-zinc-300" 103 103 }`} 104 104 fill={isLikedByUser ? "currentColor" : "none"} 105 105 /> ··· 112 112 className={`text-sm tabular-nums px-1 py-2 rounded ${isLikeLoading ? "opacity-50" : ""} ${ 113 113 isLikedByUser 114 114 ? "text-rose-400 dark:text-red-400" 115 - : "text-gray-600 dark:text-gray-400" 115 + : "text-gray-600 dark:text-zinc-300" 116 116 } ${likeCount > 0 ? "hover:underline cursor-pointer" : "cursor-default"}`} 117 117 title={likeCount > 0 ? "See who liked this" : undefined} 118 118 > ··· 141 141 className={`w-5 h-5 ${ 142 142 isSavedByUser 143 143 ? "text-blue-500 dark:text-blue-400" 144 - : "text-gray-600 dark:text-gray-400" 144 + : "text-gray-600 dark:text-zinc-300" 145 145 }`} 146 146 fill={isSavedByUser ? "currentColor" : "none"} 147 147 /> ··· 154 154 className={`text-sm tabular-nums px-1 py-2 rounded ${isSaveLoading ? "opacity-50" : ""} ${ 155 155 isSavedByUser 156 156 ? "text-blue-500 dark:text-blue-400" 157 - : "text-gray-600 dark:text-gray-400" 157 + : "text-gray-600 dark:text-zinc-300" 158 158 } ${saveCount > 0 ? "hover:underline cursor-pointer" : "cursor-default"}`} 159 159 title={saveCount > 0 ? "See lists with this item" : undefined} 160 160 > ··· 170 170 className={`${statBase} ${ 171 171 isInUserDeck 172 172 ? "text-purple-500 dark:text-purple-400" 173 - : "text-gray-600 dark:text-gray-400" 173 + : "text-gray-600 dark:text-zinc-300" 174 174 }`} 175 175 title={isInUserDeck ? "In your deck" : "Decks containing this card"} 176 176 > ··· 186 186 className={`text-sm tabular-nums px-1 py-2 rounded ${isDeckCountLoading ? "opacity-50" : ""} ${ 187 187 isInUserDeck 188 188 ? "text-purple-500 dark:text-purple-400" 189 - : "text-gray-600 dark:text-gray-400" 189 + : "text-gray-600 dark:text-zinc-300" 190 190 } ${deckCount > 0 ? "hover:underline cursor-pointer" : "cursor-default"}`} 191 191 title={deckCount > 0 ? "See decks with this card" : undefined} 192 192 > ··· 201 201 <button 202 202 type="button" 203 203 onClick={onCommentClick} 204 - className={`${statBase} text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer transition-colors`} 204 + className={`${statBase} text-gray-600 dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-800 cursor-pointer transition-colors`} 205 205 aria-label="Comments" 206 206 title="Comments" 207 207 > ··· 209 209 </button> 210 210 {showCount && !hideCommentCount && ( 211 211 <span 212 - className={`text-sm tabular-nums px-1 py-2 text-gray-600 dark:text-gray-400 ${commentCountQuery.isLoading ? "opacity-50" : ""}`} 212 + className={`text-sm tabular-nums px-1 py-2 text-gray-600 dark:text-zinc-300 ${commentCountQuery.isLoading ? "opacity-50" : ""}`} 213 213 > 214 214 {commentCount} 215 215 </span>
+2 -2
src/routes/__root.tsx
··· 86 86 }), 87 87 88 88 notFoundComponent: () => ( 89 - <div className="min-h-screen flex items-center justify-center bg-white dark:bg-slate-900 p-4"> 89 + <div className="min-h-screen flex items-center justify-center bg-white dark:bg-zinc-900 p-4"> 90 90 <div className="text-center"> 91 91 <h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-4"> 92 92 404 93 93 </h1> 94 - <p className="text-gray-600 dark:text-gray-400 mb-6">Page not found</p> 94 + <p className="text-gray-600 dark:text-zinc-300 mb-6">Page not found</p> 95 95 </div> 96 96 </div> 97 97 ),
+34 -34
src/routes/card/$id.tsx
··· 210 210 211 211 if (!isValidId) { 212 212 return ( 213 - <div className="min-h-screen bg-white dark:bg-slate-900 flex items-center justify-center"> 213 + <div className="min-h-screen bg-white dark:bg-zinc-900 flex items-center justify-center"> 214 214 <p className="text-red-600 dark:text-red-400 text-lg"> 215 215 Invalid card ID format 216 216 </p> ··· 220 220 221 221 if (cardLoading) { 222 222 return ( 223 - <div className="min-h-screen bg-white dark:bg-slate-900"> 223 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 224 224 <div className="max-w-7xl mx-auto px-6 py-8"> 225 225 <div className="flex items-center justify-center py-20"> 226 - <p className="text-gray-600 dark:text-gray-400 text-lg"> 226 + <p className="text-gray-600 dark:text-zinc-300 text-lg"> 227 227 Loading card... 228 228 </p> 229 229 </div> ··· 234 234 235 235 if (!card) { 236 236 return ( 237 - <div className="min-h-screen bg-white dark:bg-slate-900 flex items-center justify-center"> 237 + <div className="min-h-screen bg-white dark:bg-zinc-900 flex items-center justify-center"> 238 238 <p className="text-red-600 dark:text-red-400 text-lg">Card not found</p> 239 239 </div> 240 240 ); ··· 252 252 .sort((a, b) => (b.released_at ?? "").localeCompare(a.released_at ?? "")); 253 253 254 254 return ( 255 - <div className="min-h-screen bg-white dark:bg-slate-900"> 255 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 256 256 <div className="max-w-7xl mx-auto px-6 py-8"> 257 257 <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 items-start"> 258 - <div className="sticky top-0 z-10 bg-white dark:bg-slate-900 py-4 -mx-6 px-6 lg:mx-0 lg:px-0 lg:py-0 lg:bg-transparent lg:dark:bg-transparent lg:top-8 flex justify-center lg:justify-end"> 258 + <div className="sticky top-0 z-10 bg-white dark:bg-zinc-900 py-4 -mx-6 px-6 lg:mx-0 lg:px-0 lg:py-0 lg:bg-transparent lg:dark:bg-transparent lg:top-8 flex justify-center lg:justify-end"> 259 259 <CardImage 260 260 card={displayCard} 261 261 size="large" ··· 267 267 {getAllFaces(card).map((face, idx) => ( 268 268 <div key={face.name}> 269 269 {idx > 0 && ( 270 - <div className="border-t border-gray-300 dark:border-slate-600 mb-4" /> 270 + <div className="border-t border-gray-300 dark:border-zinc-600 mb-4" /> 271 271 )} 272 272 <FaceInfo 273 273 face={face} ··· 285 285 }} 286 286 > 287 287 <div className="min-w-0"> 288 - <p className="text-gray-600 dark:text-gray-400">Set</p> 288 + <p className="text-gray-600 dark:text-zinc-300">Set</p> 289 289 <p 290 290 className="text-gray-900 dark:text-white truncate" 291 291 title={ ··· 299 299 {displayCard.set_name} ({displayCard.set?.toUpperCase()}) 300 300 </> 301 301 ) : ( 302 - <span className="text-gray-400 dark:text-gray-600">—</span> 302 + <span className="text-gray-400 dark:text-zinc-600">—</span> 303 303 )} 304 304 </p> 305 305 </div> 306 306 <div className="min-w-0"> 307 - <p className="text-gray-600 dark:text-gray-400">Rarity</p> 307 + <p className="text-gray-600 dark:text-zinc-300">Rarity</p> 308 308 <p className="text-gray-900 dark:text-white capitalize truncate"> 309 309 {displayCard.rarity ?? ( 310 - <span className="text-gray-400 dark:text-gray-600">—</span> 310 + <span className="text-gray-400 dark:text-zinc-600">—</span> 311 311 )} 312 312 </p> 313 313 </div> 314 314 <div className="min-w-0"> 315 - <p className="text-gray-600 dark:text-gray-400">Artist</p> 315 + <p className="text-gray-600 dark:text-zinc-300">Artist</p> 316 316 <p 317 317 className="text-gray-900 dark:text-white truncate" 318 318 title={displayCard.artist} 319 319 > 320 320 {displayCard.artist ?? ( 321 - <span className="text-gray-400 dark:text-gray-600">—</span> 321 + <span className="text-gray-400 dark:text-zinc-600">—</span> 322 322 )} 323 323 </p> 324 324 </div> 325 325 <div className="min-w-0"> 326 - <p className="text-gray-600 dark:text-gray-400"> 326 + <p className="text-gray-600 dark:text-zinc-300"> 327 327 Collector Number 328 328 </p> 329 329 <p className="text-gray-900 dark:text-white truncate"> 330 330 {displayCard.collector_number ?? ( 331 - <span className="text-gray-400 dark:text-gray-600">—</span> 331 + <span className="text-gray-400 dark:text-zinc-600">—</span> 332 332 )} 333 333 </p> 334 334 </div> ··· 337 337 <div className="h-10 overflow-x-auto overflow-y-hidden"> 338 338 {volatileLoading ? ( 339 339 <div className="flex gap-3 items-center"> 340 - <span className="px-2.5 py-1 w-16 bg-gray-200 dark:bg-slate-700 rounded text-sm animate-pulse"> 340 + <span className="px-2.5 py-1 w-16 bg-gray-200 dark:bg-zinc-700 rounded text-sm animate-pulse"> 341 341 &nbsp; 342 342 </span> 343 - <span className="px-2.5 py-1 w-20 bg-gray-200 dark:bg-slate-700 rounded text-sm animate-pulse"> 343 + <span className="px-2.5 py-1 w-20 bg-gray-200 dark:bg-zinc-700 rounded text-sm animate-pulse"> 344 344 &nbsp; 345 345 </span> 346 - <span className="px-2.5 py-1 w-24 bg-gray-200 dark:bg-slate-700 rounded text-sm animate-pulse"> 346 + <span className="px-2.5 py-1 w-24 bg-gray-200 dark:bg-zinc-700 rounded text-sm animate-pulse"> 347 347 &nbsp; 348 348 </span> 349 349 </div> ··· 355 355 volatileData.edhrecRank) ? ( 356 356 <div className="flex gap-3 items-center"> 357 357 {volatileData.edhrecRank && ( 358 - <span className="px-2.5 py-1 bg-gray-100 dark:bg-slate-700 text-gray-700 dark:text-gray-300 rounded text-sm whitespace-nowrap"> 358 + <span className="px-2.5 py-1 bg-gray-100 dark:bg-zinc-700 text-gray-700 dark:text-zinc-300 rounded text-sm whitespace-nowrap"> 359 359 #{volatileData.edhrecRank.toLocaleString()} EDHREC 360 360 </span> 361 361 )} ··· 401 401 <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-3"> 402 402 Printings 403 403 </h2> 404 - <div className="max-h-96 overflow-y-auto border border-gray-300 dark:border-slate-700 rounded-lg p-3 bg-gray-50 dark:bg-slate-800/50"> 404 + <div className="max-h-96 overflow-y-auto border border-gray-300 dark:border-zinc-600 rounded-lg p-3 bg-gray-50 dark:bg-zinc-800/50"> 405 405 <div className="flex flex-wrap gap-2"> 406 406 {Array.from({ length: 8 }).map((_, i) => ( 407 407 <div 408 408 // biome-ignore lint/suspicious/noArrayIndexKey: static skeleton 409 409 key={i} 410 - className="h-8 w-32 bg-gray-300 dark:bg-slate-700 rounded animate-pulse" 410 + className="h-8 w-32 bg-gray-300 dark:bg-zinc-700 rounded animate-pulse" 411 411 /> 412 412 ))} 413 413 </div> ··· 420 420 </h2> 421 421 <div 422 422 ref={printingsContainerRef} 423 - className="max-h-96 overflow-y-auto border border-gray-300 dark:border-slate-700 rounded-lg p-3 bg-gray-50 dark:bg-slate-800/50" 423 + className="max-h-96 overflow-y-auto border border-gray-300 dark:border-zinc-600 rounded-lg p-3 bg-gray-50 dark:bg-zinc-800/50" 424 424 > 425 425 <div className="flex flex-wrap gap-2"> 426 426 {allPrintings.map((printing) => ( ··· 435 435 onMouseLeave={() => setHoveredPrintingId(null)} 436 436 className={`px-3 py-1.5 text-sm rounded transition-colors whitespace-nowrap ${ 437 437 printing.id === id 438 - ? "bg-cyan-500 text-white font-medium" 439 - : "bg-gray-200 dark:bg-slate-700 text-gray-900 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-slate-600" 438 + ? "bg-cyan-400 text-gray-900 font-medium" 439 + : "bg-gray-200 dark:bg-zinc-700 text-gray-900 dark:text-zinc-200 hover:bg-gray-300 dark:hover:bg-zinc-600" 440 440 }`} 441 441 > 442 442 {printing.set_name} ··· 455 455 {card.legalities && <LegalityTable legalities={card.legalities} />} 456 456 457 457 {card.oracle_id && ( 458 - <div className="border border-gray-200 dark:border-slate-700 rounded-lg overflow-hidden"> 458 + <div className="border border-gray-200 dark:border-zinc-600 rounded-lg overflow-hidden"> 459 459 <CommentsPanel 460 460 subject={{ 461 461 $type: "com.deckbelcher.social.comment#cardSubject", ··· 510 510 <div className="flex items-center justify-between gap-3"> 511 511 {face.type_line && ( 512 512 <p 513 - className={`text-gray-600 dark:text-gray-400 ${primary ? "text-lg" : ""}`} 513 + className={`text-gray-600 dark:text-zinc-300 ${primary ? "text-lg" : ""}`} 514 514 > 515 515 {face.type_line} 516 516 </p> ··· 525 525 </div> 526 526 527 527 {face.oracle_text && ( 528 - <div className="bg-gray-100 dark:bg-slate-800 rounded-lg p-4 border border-gray-300 dark:border-slate-700 text-gray-900 dark:text-gray-100"> 528 + <div className="bg-gray-100 dark:bg-zinc-800 rounded-lg p-4 border border-gray-300 dark:border-zinc-600 text-gray-900 dark:text-zinc-100"> 529 529 <OracleText text={face.oracle_text} /> 530 530 </div> 531 531 )} 532 532 533 533 {hasStats && ( 534 - <div className="flex gap-4 text-gray-700 dark:text-gray-300"> 534 + <div className="flex gap-4 text-gray-700 dark:text-zinc-300"> 535 535 {face.power && face.toughness && ( 536 536 <span> 537 - <span className="text-gray-600 dark:text-gray-400">P/T:</span>{" "} 537 + <span className="text-gray-600 dark:text-zinc-300">P/T:</span>{" "} 538 538 <span className="font-semibold"> 539 539 {face.power}/{face.toughness} 540 540 </span> ··· 542 542 )} 543 543 {face.loyalty && ( 544 544 <span> 545 - <span className="text-gray-600 dark:text-gray-400">Loyalty:</span>{" "} 545 + <span className="text-gray-600 dark:text-zinc-300">Loyalty:</span>{" "} 546 546 <span className="font-semibold">{face.loyalty}</span> 547 547 </span> 548 548 )} 549 549 {face.defense && ( 550 550 <span> 551 - <span className="text-gray-600 dark:text-gray-400">Defense:</span>{" "} 551 + <span className="text-gray-600 dark:text-zinc-300">Defense:</span>{" "} 552 552 <span className="font-semibold">{face.defense}</span> 553 553 </span> 554 554 )} ··· 571 571 <div className="grid grid-cols-2 sm:grid-cols-3 gap-4"> 572 572 {FORMAT_GROUPS.map((group) => ( 573 573 <div key={group.label}> 574 - <h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1.5"> 574 + <h3 className="text-sm font-medium text-gray-500 dark:text-zinc-300 mb-1.5"> 575 575 {group.label} 576 576 </h3> 577 577 <div className="space-y-1"> ··· 582 582 key={format.value} 583 583 className="flex items-center justify-between text-sm" 584 584 > 585 - <span className="text-gray-700 dark:text-gray-300"> 585 + <span className="text-gray-700 dark:text-zinc-300"> 586 586 {format.label} 587 587 </span> 588 588 <LegalityBadge legality={legality} /> ··· 605 605 "bg-amber-100 dark:bg-amber-900/40 text-amber-800 dark:text-amber-300", 606 606 banned: "bg-red-100 dark:bg-red-900/40 text-red-800 dark:text-red-300", 607 607 not_legal: 608 - "bg-gray-100 dark:bg-slate-700/50 text-gray-500 dark:text-gray-500", 608 + "bg-gray-100 dark:bg-zinc-700/50 text-gray-500 dark:text-zinc-400", 609 609 }; 610 610 611 611 const labels: Record<string, string> = {
+4 -4
src/routes/cards/index.tsx
··· 343 343 const firstPage = firstPageQuery.data; 344 344 345 345 return ( 346 - <div className="min-h-screen bg-white dark:bg-slate-900"> 346 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 347 347 <div className="max-w-7xl w-full mx-auto px-6 pt-8 pb-4"> 348 348 <div className="mb-4 flex flex-col gap-2"> 349 349 <div className="flex items-center justify-between gap-2"> ··· 360 360 replace: true, 361 361 }) 362 362 } 363 - className="appearance-none h-9 w-9 sm:w-auto pl-2 sm:pl-3 pr-2 sm:pr-8 py-1.5 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-transparent sm:text-gray-900 dark:sm:text-white text-sm focus:outline-none focus:border-cyan-500 transition-colors cursor-pointer" 363 + className="appearance-none h-9 w-9 sm:w-auto pl-2 sm:pl-3 pr-2 sm:pr-8 py-1.5 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-transparent sm:text-gray-900 dark:sm:text-white text-sm focus:outline-none focus:border-cyan-500 transition-colors cursor-pointer" 364 364 > 365 365 {SORT_OPTIONS.map((opt) => ( 366 366 <option key={opt.value} value={opt.value}> ··· 383 383 replace: true, 384 384 }) 385 385 } 386 - className="appearance-none h-9 w-9 sm:w-auto pl-2 sm:pl-3 pr-2 sm:pr-8 py-1.5 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-transparent sm:text-gray-900 dark:sm:text-white text-sm focus:outline-none focus:border-cyan-500 transition-colors cursor-pointer" 386 + className="appearance-none h-9 w-9 sm:w-auto pl-2 sm:pl-3 pr-2 sm:pr-8 py-1.5 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-transparent sm:text-gray-900 dark:sm:text-white text-sm focus:outline-none focus:border-cyan-500 transition-colors cursor-pointer" 387 387 > 388 388 <option value="">then...</option> 389 389 {SORT_OPTIONS.filter( ··· 427 427 <div className="text-sm mt-2 space-y-1"> 428 428 {firstPage?.description && ( 429 429 <p 430 - className={`text-gray-500 dark:text-gray-400 ${isDebouncing ? "opacity-50" : ""}`} 430 + className={`text-gray-500 dark:text-zinc-300 ${isDebouncing ? "opacity-50" : ""}`} 431 431 > 432 432 <OracleText text={firstPage.description} /> 433 433 </p>
+15 -15
src/routes/deck/new.tsx
··· 53 53 // Cube gets special treatment 54 54 if (info.isCube) { 55 55 return ( 56 - <div className="bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-xl p-6"> 56 + <div className="bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-xl p-6"> 57 57 <div className="flex items-baseline justify-between gap-4 mb-4"> 58 58 <h3 className="text-lg font-semibold text-gray-900 dark:text-white"> 59 59 {displayName} 60 60 </h3> 61 61 {info.tagline && ( 62 - <span className="text-sm text-gray-500 dark:text-gray-400 whitespace-nowrap"> 62 + <span className="text-sm text-gray-500 dark:text-zinc-300 whitespace-nowrap"> 63 63 {info.tagline} 64 64 </span> 65 65 )} ··· 80 80 </span> 81 81 </div> 82 82 83 - <p className="text-sm text-gray-600 dark:text-gray-400"> 83 + <p className="text-sm text-gray-600 dark:text-zinc-300"> 84 84 Set your own rules for deck size, card pool, and restrictions. 85 85 </p> 86 86 </div> ··· 88 88 } 89 89 90 90 return ( 91 - <div className="bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-xl p-6"> 91 + <div className="bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-xl p-6"> 92 92 <div className="flex items-baseline justify-between gap-4 mb-4"> 93 93 <h3 className="text-lg font-semibold text-gray-900 dark:text-white"> 94 94 {displayName} 95 95 </h3> 96 96 {info.tagline && ( 97 - <span className="text-sm text-gray-500 dark:text-gray-400 whitespace-nowrap"> 97 + <span className="text-sm text-gray-500 dark:text-zinc-300 whitespace-nowrap"> 98 98 {info.tagline} 99 99 </span> 100 100 )} ··· 126 126 )} 127 127 128 128 {info.hasSideboard && ( 129 - <span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-slate-100 dark:bg-slate-700/50 text-slate-600 dark:text-slate-300 text-sm font-medium rounded-full"> 129 + <span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-slate-100 dark:bg-zinc-700/50 text-slate-600 dark:text-zinc-300 text-sm font-medium rounded-full"> 130 130 15-card sideboard 131 131 </span> 132 132 )} 133 133 </div> 134 134 135 135 {info.commanderType && ( 136 - <p className="text-sm text-gray-600 dark:text-gray-400"> 136 + <p className="text-sm text-gray-600 dark:text-zinc-300"> 137 137 {getCommanderHint(info.commanderType)} 138 138 </p> 139 139 )} ··· 163 163 }; 164 164 165 165 return ( 166 - <div className="min-h-screen bg-white dark:bg-slate-900"> 166 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 167 167 <div className="max-w-xl mx-auto px-6 py-16"> 168 168 <div className="text-center mb-10"> 169 169 <h1 className="text-4xl font-bold text-gray-900 dark:text-white mb-2"> 170 170 New Deck 171 171 </h1> 172 - <p className="text-gray-600 dark:text-gray-400"> 172 + <p className="text-gray-600 dark:text-zinc-300"> 173 173 Choose a format and give your deck a name 174 174 </p> 175 175 </div> ··· 178 178 <div> 179 179 <label 180 180 htmlFor={nameId} 181 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" 181 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2" 182 182 > 183 183 Deck Name 184 184 </label> ··· 189 189 onChange={(e) => setName(e.target.value)} 190 190 placeholder="Untitled Deck" 191 191 autoComplete="off" 192 - className="w-full px-4 py-3 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" 192 + className="w-full px-4 py-3 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" 193 193 /> 194 194 </div> 195 195 196 196 <div> 197 197 <label 198 198 htmlFor={formatId} 199 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" 199 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2" 200 200 > 201 201 Format 202 202 </label> ··· 204 204 id={formatId} 205 205 value={format} 206 206 onChange={(e) => setFormat(e.target.value)} 207 - className="w-full px-4 py-3 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" 207 + className="w-full px-4 py-3 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-500 transition-colors" 208 208 > 209 209 {FORMAT_GROUPS.map((group) => ( 210 210 <optgroup key={group.label} label={group.label}> ··· 224 224 <button 225 225 type="submit" 226 226 disabled={mutation.isPending || !name.trim()} 227 - className="flex-1 px-6 py-3 bg-cyan-600 hover:bg-cyan-700 disabled:bg-gray-400 dark:disabled:bg-slate-600 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors" 227 + className="flex-1 px-6 py-3 bg-cyan-400 hover:bg-cyan-300 disabled:bg-gray-400 dark:disabled:bg-zinc-600 disabled:cursor-not-allowed text-gray-900 font-medium rounded-lg transition-colors" 228 228 > 229 229 {mutation.isPending ? "Creating..." : "Create Deck"} 230 230 </button> 231 231 <button 232 232 type="button" 233 233 onClick={() => navigate({ to: "/" })} 234 - className="px-6 py-3 bg-gray-200 dark:bg-slate-800 hover:bg-gray-300 dark:hover:bg-slate-700 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 234 + className="px-6 py-3 bg-gray-200 dark:bg-zinc-800 hover:bg-gray-300 dark:hover:bg-zinc-700 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 235 235 > 236 236 Cancel 237 237 </button>
+11 -11
src/routes/dev/migrate.tsx
··· 320 320 }; 321 321 322 322 return ( 323 - <div className="min-h-screen bg-white dark:bg-slate-900 p-8"> 323 + <div className="min-h-screen bg-white dark:bg-zinc-900 p-8"> 324 324 <div className="max-w-4xl mx-auto space-y-6"> 325 325 <div> 326 326 <h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-2"> 327 327 Record Migration 328 328 </h1> 329 - <p className="text-gray-600 dark:text-gray-400"> 329 + <p className="text-gray-600 dark:text-zinc-300"> 330 330 Migrate old format records (scryfallId) to new format (cardRef with 331 331 scryfallUri + oracleUri). 332 332 </p> ··· 336 336 <div className="space-y-2"> 337 337 <label 338 338 htmlFor={inputId} 339 - className="block text-sm font-medium text-gray-700 dark:text-gray-300" 339 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300" 340 340 > 341 341 Old Format (paste JSON) 342 342 </label> ··· 344 344 id={inputId} 345 345 value={input} 346 346 onChange={(e) => setInput(e.target.value)} 347 - className="w-full h-96 p-3 font-mono text-xs bg-gray-50 dark:bg-slate-800 border border-gray-300 dark:border-slate-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent text-gray-900 dark:text-gray-100" 347 + className="w-full h-96 p-3 font-mono text-xs bg-gray-50 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent text-gray-900 dark:text-zinc-100" 348 348 placeholder='{"$type": "com.deckbelcher.deck.list", ...}' 349 349 /> 350 350 </div> ··· 352 352 <div className="space-y-2"> 353 353 <label 354 354 htmlFor={outputId} 355 - className="block text-sm font-medium text-gray-700 dark:text-gray-300" 355 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300" 356 356 > 357 357 New Format (output) 358 358 </label> ··· 360 360 id={outputId} 361 361 value={output} 362 362 readOnly 363 - className="w-full h-96 p-3 font-mono text-xs bg-gray-100 dark:bg-slate-800/50 border border-gray-300 dark:border-slate-600 rounded-lg text-gray-900 dark:text-gray-100" 363 + className="w-full h-96 p-3 font-mono text-xs bg-gray-100 dark:bg-zinc-800/50 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-zinc-100" 364 364 placeholder="Migrated output will appear here..." 365 365 /> 366 366 </div> ··· 397 397 )} 398 398 399 399 <details className="text-sm"> 400 - <summary className="cursor-pointer text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 font-medium"> 400 + <summary className="cursor-pointer text-gray-600 dark:text-zinc-300 hover:text-gray-800 dark:hover:text-zinc-200 font-medium"> 401 401 Migration Details 402 402 </summary> 403 - <div className="mt-2 p-4 bg-gray-50 dark:bg-slate-800 rounded-lg text-gray-700 dark:text-gray-300 space-y-2"> 403 + <div className="mt-2 p-4 bg-gray-50 dark:bg-zinc-800 rounded-lg text-gray-700 dark:text-zinc-300 space-y-2"> 404 404 <p> 405 405 <strong>Old format:</strong>{" "} 406 - <code className="text-xs bg-gray-200 dark:bg-slate-700 px-1 rounded"> 406 + <code className="text-xs bg-gray-200 dark:bg-zinc-700 px-1 rounded"> 407 407 scryfallId: "uuid" 408 408 </code> 409 409 </p> 410 410 <p> 411 411 <strong>New format:</strong>{" "} 412 - <code className="text-xs bg-gray-200 dark:bg-slate-700 px-1 rounded"> 412 + <code className="text-xs bg-gray-200 dark:bg-zinc-700 px-1 rounded"> 413 413 {`ref: { scryfallUri: "scry:uuid", oracleUri: "oracle:uuid" }`} 414 414 </code> 415 415 </p> 416 - <p className="text-xs text-gray-500 dark:text-gray-400"> 416 + <p className="text-xs text-gray-500 dark:text-zinc-300"> 417 417 Supports both com.deckbelcher.deck.list and 418 418 com.deckbelcher.collection.list records. 419 419 </p>
+10 -10
src/routes/dev/pm-demo.tsx
··· 88 88 }, [savedDoc]); 89 89 90 90 return ( 91 - <div className="min-h-screen bg-white dark:bg-slate-900 p-8"> 91 + <div className="min-h-screen bg-white dark:bg-zinc-900 p-8"> 92 92 <div className="max-w-3xl mx-auto space-y-8"> 93 93 <div> 94 94 <h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-2"> 95 95 ProseMirror Editor Demo 96 96 </h1> 97 - <p className="text-gray-600 dark:text-gray-400"> 97 + <p className="text-gray-600 dark:text-zinc-300"> 98 98 Testing the new WYSIWYG editor. Use toolbar buttons or markdown 99 99 shortcuts. 100 100 </p> ··· 116 116 <h2 className="text-lg font-semibold text-gray-900 dark:text-white"> 117 117 Read-only View 118 118 </h2> 119 - <div className="p-4 border border-gray-200 dark:border-slate-700 rounded-lg bg-gray-50 dark:bg-slate-800/50"> 119 + <div className="p-4 border border-gray-200 dark:border-zinc-600 rounded-lg bg-gray-50 dark:bg-zinc-800/50"> 120 120 <RichtextSection document={savedDoc} readOnly /> 121 121 </div> 122 122 </div> 123 123 124 124 {lastSaved && ( 125 - <p className="text-sm text-gray-500 dark:text-gray-400"> 125 + <p className="text-sm text-gray-500 dark:text-zinc-300"> 126 126 Last saved: {lastSaved} 127 127 </p> 128 128 )} 129 129 130 130 <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> 131 131 <details className="text-sm" open> 132 - <summary className="cursor-pointer text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 font-medium"> 132 + <summary className="cursor-pointer text-gray-600 dark:text-zinc-300 hover:text-gray-800 dark:hover:text-zinc-200 font-medium"> 133 133 Lexicon (storage format) 134 134 </summary> 135 - <pre className="mt-2 p-4 bg-gray-100 dark:bg-slate-800 rounded overflow-auto text-xs max-h-96"> 135 + <pre className="mt-2 p-4 bg-gray-100 dark:bg-zinc-800 rounded overflow-auto text-xs max-h-96"> 136 136 {JSON.stringify(savedDoc, null, 2)} 137 137 </pre> 138 138 </details> 139 139 140 140 <details className="text-sm" open> 141 - <summary className="cursor-pointer text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 font-medium"> 141 + <summary className="cursor-pointer text-gray-600 dark:text-zinc-300 hover:text-gray-800 dark:hover:text-zinc-200 font-medium"> 142 142 Tree (ProseMirror) 143 143 </summary> 144 - <pre className="mt-2 p-4 bg-gray-100 dark:bg-slate-800 rounded overflow-auto text-xs max-h-96"> 144 + <pre className="mt-2 p-4 bg-gray-100 dark:bg-zinc-800 rounded overflow-auto text-xs max-h-96"> 145 145 {JSON.stringify(pmTreeDoc, null, 2)} 146 146 </pre> 147 147 </details> 148 148 </div> 149 149 150 150 <details className="text-sm"> 151 - <summary className="cursor-pointer text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 font-medium"> 151 + <summary className="cursor-pointer text-gray-600 dark:text-zinc-300 hover:text-gray-800 dark:hover:text-zinc-200 font-medium"> 152 152 Roundtrip (lexicon → tree → lexicon) 153 153 </summary> 154 - <pre className="mt-2 p-4 bg-gray-100 dark:bg-slate-800 rounded overflow-auto text-xs max-h-96"> 154 + <pre className="mt-2 p-4 bg-gray-100 dark:bg-zinc-800 rounded overflow-auto text-xs max-h-96"> 155 155 {JSON.stringify(roundtrippedDoc, null, 2)} 156 156 </pre> 157 157 {roundtrippedDoc && savedDoc && (
+21 -21
src/routes/index.tsx
··· 9 9 const { session } = useAuth(); 10 10 11 11 return ( 12 - <div className="min-h-[calc(100vh-64px)] bg-gradient-to-b from-slate-50 to-white dark:from-slate-900 dark:to-slate-950"> 12 + <div className="min-h-[calc(100vh-64px)] bg-gradient-to-b from-slate-50 to-white dark:from-zinc-900 dark:to-zinc-950"> 13 13 <div className="max-w-5xl mx-auto px-6 py-16 md:py-24"> 14 14 <div className="text-center mb-16"> 15 15 <h1 className="inline-block text-5xl md:text-6xl font-medium text-gray-900 dark:text-white mb-4 tracking-tight font-display [font-variation-settings:'WONK'_1,'SOFT'_70,'opsz'_72] motion-safe:hover:[font-variation-settings:'WONK'_1,'SOFT'_100,'opsz'_25] motion-safe:transition-[font-variation-settings] motion-safe:duration-500 ease-in-out cursor-default"> 16 16 deck belcher dot com 17 17 </h1> 18 - <p className="text-xl text-gray-600 dark:text-gray-400 max-w-xl mx-auto"> 18 + <p className="text-xl text-gray-600 dark:text-zinc-300 max-w-xl mx-auto"> 19 19 organize, build, and share decks on the atmosphere 20 20 </p> 21 21 </div> ··· 24 24 {session ? ( 25 25 <Link 26 26 to="/deck/new" 27 - className="group flex flex-col items-center p-6 bg-white dark:bg-slate-800/50 border border-gray-200 dark:border-slate-700 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 27 + className="group flex flex-col items-center p-6 bg-white dark:bg-zinc-800/50 border border-gray-200 dark:border-zinc-600 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 28 28 > 29 29 <div className="w-12 h-12 bg-cyan-100 dark:bg-cyan-900/30 rounded-full flex items-center justify-center mb-4 group-hover:bg-cyan-200 dark:group-hover:bg-cyan-800/40 transition-colors"> 30 30 <Plus size={24} className="text-cyan-600 dark:text-cyan-400" /> ··· 32 32 <span className="font-semibold text-gray-900 dark:text-white motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'wght'_600] motion-safe:group-hover:[font-variation-settings:'wght'_700]"> 33 33 Create Deck 34 34 </span> 35 - <span className="text-sm text-gray-500 dark:text-gray-400 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 35 + <span className="text-sm text-gray-500 dark:text-zinc-300 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 36 36 Start building 37 37 </span> 38 38 </Link> 39 39 ) : ( 40 40 <Link 41 41 to="/signin" 42 - className="group flex flex-col items-center p-6 bg-white dark:bg-slate-800/50 border border-gray-200 dark:border-slate-700 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 42 + className="group flex flex-col items-center p-6 bg-white dark:bg-zinc-800/50 border border-gray-200 dark:border-zinc-600 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 43 43 > 44 44 <div className="w-12 h-12 bg-cyan-100 dark:bg-cyan-900/30 rounded-full flex items-center justify-center mb-4 group-hover:bg-cyan-200 dark:group-hover:bg-cyan-800/40 transition-colors"> 45 45 <User size={24} className="text-cyan-600 dark:text-cyan-400" /> ··· 47 47 <span className="font-semibold text-gray-900 dark:text-white motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'wght'_600] motion-safe:group-hover:[font-variation-settings:'wght'_700]"> 48 48 Sign In 49 49 </span> 50 - <span className="text-sm text-gray-500 dark:text-gray-400 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 50 + <span className="text-sm text-gray-500 dark:text-zinc-300 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 51 51 Get started 52 52 </span> 53 53 </Link> ··· 57 57 <Link 58 58 to="/profile/$did" 59 59 params={{ did: session.info.sub }} 60 - className="group flex flex-col items-center p-6 bg-white dark:bg-slate-800/50 border border-gray-200 dark:border-slate-700 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 60 + className="group flex flex-col items-center p-6 bg-white dark:bg-zinc-800/50 border border-gray-200 dark:border-zinc-600 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 61 61 > 62 - <div className="w-12 h-12 bg-gray-100 dark:bg-slate-700 rounded-full flex items-center justify-center mb-4 group-hover:bg-gray-200 dark:group-hover:bg-slate-600 transition-colors"> 63 - <User size={24} className="text-gray-600 dark:text-gray-300" /> 62 + <div className="w-12 h-12 bg-gray-100 dark:bg-zinc-700 rounded-full flex items-center justify-center mb-4 group-hover:bg-gray-200 dark:group-hover:bg-zinc-600 transition-colors"> 63 + <User size={24} className="text-gray-600 dark:text-zinc-300" /> 64 64 </div> 65 65 <span className="font-semibold text-gray-900 dark:text-white motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'wght'_600] motion-safe:group-hover:[font-variation-settings:'wght'_700]"> 66 66 My Decks 67 67 </span> 68 - <span className="text-sm text-gray-500 dark:text-gray-400 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 68 + <span className="text-sm text-gray-500 dark:text-zinc-300 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 69 69 View your collection 70 70 </span> 71 71 </Link> 72 72 ) : ( 73 - <div className="flex flex-col items-center p-6 bg-gray-50 dark:bg-slate-800/30 border border-gray-200 dark:border-slate-700/50 rounded-xl opacity-50 cursor-not-allowed"> 74 - <div className="w-12 h-12 bg-gray-100 dark:bg-slate-700/50 rounded-full flex items-center justify-center mb-4"> 75 - <User size={24} className="text-gray-400 dark:text-gray-500" /> 73 + <div className="flex flex-col items-center p-6 bg-gray-50 dark:bg-zinc-800/30 border border-gray-200 dark:border-zinc-600/50 rounded-xl opacity-50 cursor-not-allowed"> 74 + <div className="w-12 h-12 bg-gray-100 dark:bg-zinc-700/50 rounded-full flex items-center justify-center mb-4"> 75 + <User size={24} className="text-gray-400 dark:text-zinc-400" /> 76 76 </div> 77 - <span className="font-semibold text-gray-400 dark:text-gray-500"> 77 + <span className="font-semibold text-gray-400 dark:text-zinc-400"> 78 78 My Decks 79 79 </span> 80 - <span className="text-sm text-gray-400 dark:text-gray-500 mt-1"> 80 + <span className="text-sm text-gray-400 dark:text-zinc-400 mt-1"> 81 81 Sign in to view 82 82 </span> 83 83 </div> ··· 86 86 <Link 87 87 to="/cards" 88 88 search={{ q: "", sort: undefined, sort2: undefined }} 89 - className="group flex flex-col items-center p-6 bg-white dark:bg-slate-800/50 border border-gray-200 dark:border-slate-700 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 89 + className="group flex flex-col items-center p-6 bg-white dark:bg-zinc-800/50 border border-gray-200 dark:border-zinc-600 rounded-xl hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 90 90 > 91 - <div className="w-12 h-12 bg-gray-100 dark:bg-slate-700 rounded-full flex items-center justify-center mb-4 group-hover:bg-gray-200 dark:group-hover:bg-slate-600 transition-colors"> 92 - <Search size={24} className="text-gray-600 dark:text-gray-300" /> 91 + <div className="w-12 h-12 bg-gray-100 dark:bg-zinc-700 rounded-full flex items-center justify-center mb-4 group-hover:bg-gray-200 dark:group-hover:bg-zinc-600 transition-colors"> 92 + <Search size={24} className="text-gray-600 dark:text-zinc-300" /> 93 93 </div> 94 94 <span className="font-semibold text-gray-900 dark:text-white motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'wght'_600] motion-safe:group-hover:[font-variation-settings:'wght'_700]"> 95 95 Browse Cards 96 96 </span> 97 - <span className="text-sm text-gray-500 dark:text-gray-400 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 97 + <span className="text-sm text-gray-500 dark:text-zinc-300 mt-1 motion-safe:transition-[font-variation-settings] motion-safe:duration-200 motion-safe:ease-out [font-variation-settings:'CASL'_0] motion-safe:group-hover:[font-variation-settings:'CASL'_1]"> 98 98 Search the database 99 99 </span> 100 100 </Link> ··· 104 104 <h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-1 text-center"> 105 105 Recent Activity 106 106 </h2> 107 - <p className="text-sm text-gray-500 dark:text-gray-400 mb-6 text-center"> 107 + <p className="text-sm text-gray-500 dark:text-zinc-300 mb-6 text-center"> 108 108 powered by{" "} 109 109 <a 110 110 href="https://ufos.microcosm.blue" ··· 119 119 </div> 120 120 121 121 <div className="mt-16 text-center"> 122 - <p className="text-sm text-gray-500 dark:text-gray-500 [font-variation-settings:'CASL'_0.5]"> 122 + <p className="text-sm text-gray-500 dark:text-zinc-400 [font-variation-settings:'CASL'_0.5]"> 123 123 built on{" "} 124 124 <a 125 125 href="https://atproto.com"
+6 -6
src/routes/oauth/callback.tsx
··· 100 100 }; 101 101 102 102 return ( 103 - <div className="min-h-screen flex items-center justify-center bg-white dark:bg-slate-900 p-4"> 103 + <div className="min-h-screen flex items-center justify-center bg-white dark:bg-zinc-900 p-4"> 104 104 <div 105 - className={`max-w-md w-full bg-white dark:bg-slate-800 ${colorClasses.border} rounded-lg shadow-lg overflow-hidden`} 105 + className={`max-w-md w-full bg-white dark:bg-zinc-800 ${colorClasses.border} rounded-lg shadow-lg overflow-hidden`} 106 106 > 107 107 <div 108 108 className={`${colorClasses.headerBg} border-b ${colorClasses.headerBorder} p-6`} ··· 112 112 </h1> 113 113 </div> 114 114 <div className="p-6"> 115 - <p className="text-gray-700 dark:text-gray-300 mb-6 leading-relaxed"> 115 + <p className="text-gray-700 dark:text-zinc-300 mb-6 leading-relaxed"> 116 116 {error} 117 117 </p> 118 118 <div className="flex gap-3"> 119 119 <button 120 120 type="button" 121 121 onClick={() => navigate({ to: "/signin" })} 122 - className="flex-1 px-4 py-2 bg-cyan-600 hover:bg-cyan-700 text-white rounded-lg transition-colors font-medium" 122 + className="flex-1 px-4 py-2 bg-cyan-400 hover:bg-cyan-300 text-gray-900 rounded-lg transition-colors font-medium" 123 123 > 124 124 Try Again 125 125 </button> 126 126 <button 127 127 type="button" 128 128 onClick={() => navigate({ to: "/" })} 129 - className="flex-1 px-4 py-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white rounded-lg transition-colors font-medium" 129 + className="flex-1 px-4 py-2 bg-gray-200 hover:bg-gray-300 dark:bg-zinc-700 dark:hover:bg-zinc-600 text-gray-900 dark:text-white rounded-lg transition-colors font-medium" 130 130 > 131 131 Return Home 132 132 </button> ··· 138 138 } 139 139 140 140 return ( 141 - <div className="min-h-screen flex items-center justify-center bg-white dark:bg-slate-900"> 141 + <div className="min-h-screen flex items-center justify-center bg-white dark:bg-zinc-900"> 142 142 <div className="text-center"> 143 143 <div className="inline-block h-8 w-8 animate-spin rounded-full border-4 border-solid border-cyan-600 border-r-transparent mb-4" /> 144 144 <p className="text-gray-900 dark:text-white text-lg">
+11 -11
src/routes/profile/$did/deck/$rkey/bulk-edit.tsx
··· 287 287 }, [textLines, resolvedMap, errorMap, parsedByRaw, savedCardIds]); 288 288 289 289 return ( 290 - <div className="min-h-screen bg-white dark:bg-slate-900"> 290 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 291 291 <div className="max-w-6xl mx-auto px-6 py-8"> 292 292 <div className="mb-6"> 293 293 <Link ··· 300 300 <h1 className="text-2xl font-bold text-gray-900 dark:text-white mt-2"> 301 301 Bulk Edit: {deck.name} 302 302 </h1> 303 - <p className="text-gray-600 dark:text-gray-400 mt-1"> 303 + <p className="text-gray-600 dark:text-zinc-300 mt-1"> 304 304 Edit cards in text format. One card per line. 305 305 </p> 306 306 </div> 307 307 308 308 {/* Section tabs */} 309 - <div className="flex gap-1 mb-4 border-b border-gray-200 dark:border-slate-700"> 309 + <div className="flex gap-1 mb-4 border-b border-gray-200 dark:border-zinc-600"> 310 310 {SECTIONS.map((section) => { 311 311 const isActive = activeSection === section.value; 312 312 const isDisabled = isDirty && !isActive; ··· 320 320 isActive 321 321 ? "text-blue-600 dark:text-blue-400 border-b-2 border-blue-600 dark:border-blue-400" 322 322 : isDisabled 323 - ? "text-gray-400 dark:text-gray-600 cursor-not-allowed" 324 - : "text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white" 323 + ? "text-gray-400 dark:text-zinc-600 cursor-not-allowed" 324 + : "text-gray-600 dark:text-zinc-300 hover:text-gray-900 dark:hover:text-white" 325 325 }`} 326 326 > 327 327 {section.label} ··· 339 339 </div> 340 340 341 341 {/* Format hint */} 342 - <div className="mb-4 p-3 bg-gray-50 dark:bg-slate-800 rounded-lg text-sm text-gray-600 dark:text-gray-400"> 342 + <div className="mb-4 p-3 bg-gray-50 dark:bg-zinc-800 rounded-lg text-sm text-gray-600 dark:text-zinc-300"> 343 343 <strong>Format:</strong>{" "} 344 - <code className="bg-gray-200 dark:bg-slate-700 px-1 rounded"> 344 + <code className="bg-gray-200 dark:bg-zinc-700 px-1 rounded"> 345 345 &lt;quantity&gt; &lt;card name&gt; (SET) &lt;collector#&gt; #tag1 346 346 #tag2 347 347 </code> ··· 352 352 </div> 353 353 354 354 {/* Editor container */} 355 - <div className="overflow-auto max-h-96 border border-gray-300 dark:border-slate-700 rounded-lg bg-white dark:bg-slate-800"> 355 + <div className="overflow-auto max-h-96 border border-gray-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800"> 356 356 <div className="flex"> 357 357 <textarea 358 358 value={text} ··· 362 362 }} 363 363 disabled={!isOwner || isSaving} 364 364 wrap="off" 365 - className="flex-1 p-4 font-mono text-sm leading-[1.5] resize-none overflow-x-auto overflow-y-hidden bg-transparent text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none disabled:opacity-50 [font-variant-ligatures:none]" 365 + className="flex-1 p-4 font-mono text-sm leading-[1.5] resize-none overflow-x-auto overflow-y-hidden bg-transparent text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-zinc-500 focus:outline-none disabled:opacity-50 [font-variant-ligatures:none]" 366 366 style={{ 367 367 height: `calc(${Math.max(textLines.length, 10)} * 1.5em + 2rem)`, 368 368 }} ··· 373 373 </div> 374 374 375 375 {/* Stats */} 376 - <div className="mt-2 text-sm text-gray-500 dark:text-gray-400"> 376 + <div className="mt-2 text-sm text-gray-500 dark:text-zinc-300"> 377 377 {lineCount} {lineCount === 1 ? "card" : "cards"}, {cardCount} total 378 378 </div> 379 379 ··· 416 416 type="button" 417 417 onClick={handleReset} 418 418 disabled={isSaving || !isDirty} 419 - className="px-4 py-2 bg-gray-200 dark:bg-slate-700 hover:bg-gray-300 dark:hover:bg-slate-600 disabled:opacity-50 disabled:cursor-not-allowed text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 419 + className="px-4 py-2 bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 disabled:opacity-50 disabled:cursor-not-allowed text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 420 420 > 421 421 Reset 422 422 </button>
+15 -15
src/routes/profile/$did/deck/$rkey/export.tsx
··· 152 152 const lineCount = exportText.split("\n").filter((l) => l.trim()).length; 153 153 154 154 return ( 155 - <div className="min-h-screen bg-white dark:bg-slate-900"> 155 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 156 156 <div className="max-w-4xl mx-auto px-6 py-8"> 157 157 <div className="mb-6"> 158 158 <Link ··· 165 165 <h1 className="text-2xl font-bold text-gray-900 dark:text-white mt-2"> 166 166 Export: {deck.name} 167 167 </h1> 168 - <p className="text-gray-600 dark:text-gray-400 mt-1"> 168 + <p className="text-gray-600 dark:text-zinc-300 mt-1"> 169 169 Export your deck to various formats for use in other tools. 170 170 </p> 171 171 </div> 172 172 173 173 {/* Format selector */} 174 174 <div className="mb-6"> 175 - <span className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> 175 + <span className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2"> 176 176 Format 177 177 </span> 178 178 <div className="grid grid-cols-2 sm:grid-cols-4 gap-2"> ··· 187 187 className={`px-3 py-2 text-sm rounded-lg border transition-colors text-left ${ 188 188 format === f 189 189 ? "border-blue-500 bg-blue-50 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300" 190 - : "border-gray-300 dark:border-slate-700 hover:border-gray-400 dark:hover:border-slate-600 text-gray-700 dark:text-gray-300" 190 + : "border-gray-300 dark:border-zinc-600 hover:border-gray-400 dark:hover:border-slate-600 text-gray-700 dark:text-zinc-300" 191 191 }`} 192 192 > 193 193 <div className="font-medium">{meta.label}</div> ··· 201 201 {/* Options */} 202 202 <div className="mb-6 space-y-2"> 203 203 {getCardsInSection(deck, "maybeboard").length > 0 && ( 204 - <label className="flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 cursor-pointer"> 204 + <label className="flex items-center gap-2 text-sm text-gray-700 dark:text-zinc-300 cursor-pointer"> 205 205 <input 206 206 type="checkbox" 207 207 checked={includeMaybeboard} 208 208 onChange={(e) => setIncludeMaybeboard(e.target.checked)} 209 - className="rounded border-gray-300 dark:border-slate-600 text-blue-600 focus:ring-blue-500" 209 + className="rounded border-gray-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500" 210 210 /> 211 211 Include maybeboard ( 212 212 {getCardsInSection(deck, "maybeboard").reduce( ··· 219 219 <label 220 220 className={`flex items-center gap-2 text-sm ${ 221 221 formatOptions.tags 222 - ? "text-gray-700 dark:text-gray-300 cursor-pointer" 223 - : "text-gray-400 dark:text-gray-600 cursor-not-allowed" 222 + ? "text-gray-700 dark:text-zinc-300 cursor-pointer" 223 + : "text-gray-400 dark:text-zinc-600 cursor-not-allowed" 224 224 }`} 225 225 > 226 226 <input ··· 228 228 checked={formatOptions.tags && includeTags} 229 229 onChange={(e) => setIncludeTags(e.target.checked)} 230 230 disabled={!formatOptions.tags} 231 - className="rounded border-gray-300 dark:border-slate-600 text-blue-600 focus:ring-blue-500 disabled:opacity-50" 231 + className="rounded border-gray-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500 disabled:opacity-50" 232 232 /> 233 233 Include tags 234 234 </label> 235 235 <label 236 236 className={`flex items-center gap-2 text-sm ${ 237 237 formatOptions.setcodes 238 - ? "text-gray-700 dark:text-gray-300 cursor-pointer" 239 - : "text-gray-400 dark:text-gray-600 cursor-not-allowed" 238 + ? "text-gray-700 dark:text-zinc-300 cursor-pointer" 239 + : "text-gray-400 dark:text-zinc-600 cursor-not-allowed" 240 240 }`} 241 241 > 242 242 <input ··· 244 244 checked={formatOptions.setcodes && includeSetCodes} 245 245 onChange={(e) => setIncludeSetCodes(e.target.checked)} 246 246 disabled={!formatOptions.setcodes} 247 - className="rounded border-gray-300 dark:border-slate-600 text-blue-600 focus:ring-blue-500 disabled:opacity-50" 247 + className="rounded border-gray-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500 disabled:opacity-50" 248 248 /> 249 249 Include set codes 250 250 </label> ··· 253 253 {/* Preview */} 254 254 <div className="mb-4"> 255 255 <div className="flex items-center justify-between mb-2"> 256 - <span className="text-sm font-medium text-gray-700 dark:text-gray-300"> 256 + <span className="text-sm font-medium text-gray-700 dark:text-zinc-300"> 257 257 Preview ({lineCount} lines) 258 258 </span> 259 259 <div className="flex gap-2"> ··· 268 268 <button 269 269 type="button" 270 270 onClick={handleDownload} 271 - className="flex items-center gap-1.5 px-3 py-1.5 text-sm bg-gray-200 dark:bg-slate-700 hover:bg-gray-300 dark:hover:bg-slate-600 text-gray-900 dark:text-white rounded-lg transition-colors" 271 + className="flex items-center gap-1.5 px-3 py-1.5 text-sm bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 text-gray-900 dark:text-white rounded-lg transition-colors" 272 272 > 273 273 <Download size={14} /> 274 274 Download 275 275 </button> 276 276 </div> 277 277 </div> 278 - <pre className="p-4 bg-gray-50 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg overflow-x-auto text-sm font-mono text-gray-900 dark:text-gray-100 max-h-[60vh] overflow-y-auto whitespace-pre"> 278 + <pre className="p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg overflow-x-auto text-sm font-mono text-gray-900 dark:text-zinc-100 max-h-[60vh] overflow-y-auto whitespace-pre"> 279 279 {exportText} 280 280 </pre> 281 281 </div>
+2 -2
src/routes/profile/$did/deck/$rkey/index.tsx
··· 634 634 ); 635 635 636 636 return ( 637 - <div className="min-h-screen bg-white dark:bg-slate-900"> 637 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 638 638 {/* Deck name and format */} 639 639 <div className="max-w-7xl 2xl:max-w-[96rem] mx-auto px-6 pt-8 pb-4 space-y-4"> 640 640 <DeckHeader ··· 659 659 </div> 660 660 661 661 {/* Sticky header with search */} 662 - <div className="sticky top-0 z-10 bg-white dark:bg-slate-900 border-b border-gray-200 dark:border-slate-800 shadow-sm"> 662 + <div className="sticky top-0 z-10 bg-white dark:bg-zinc-900 border-b border-gray-200 dark:border-zinc-700 shadow-sm"> 663 663 <div className="max-w-7xl 2xl:max-w-[96rem] mx-auto px-6 py-3 flex items-center justify-between gap-4"> 664 664 <div className="flex items-center gap-2"> 665 665 <DeckActionsMenu
+5 -5
src/routes/profile/$did/deck/$rkey/play.tsx
··· 58 58 59 59 if (!cardMap) { 60 60 return ( 61 - <div className="h-screen flex items-center justify-center bg-white dark:bg-slate-950"> 62 - <span className="text-gray-500 dark:text-gray-400"> 61 + <div className="h-screen flex items-center justify-center bg-white dark:bg-zinc-950"> 62 + <span className="text-gray-500 dark:text-zinc-300"> 63 63 Loading cards... 64 64 </span> 65 65 </div> ··· 67 67 } 68 68 69 69 return ( 70 - <div className="h-screen flex flex-col bg-white dark:bg-slate-950"> 71 - <header className="flex items-center gap-4 px-4 py-2 border-b border-gray-200 dark:border-slate-800"> 70 + <div className="h-screen flex flex-col bg-white dark:bg-zinc-950"> 71 + <header className="flex items-center gap-4 px-4 py-2 border-b border-gray-200 dark:border-zinc-700"> 72 72 <Link 73 73 to="/profile/$did/deck/$rkey" 74 74 params={{ did, rkey }} 75 - className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white" 75 + className="flex items-center gap-2 text-gray-600 dark:text-zinc-300 hover:text-gray-900 dark:hover:text-white" 76 76 > 77 77 <ArrowLeft className="w-4 h-4" /> 78 78 Back to Editor
+10 -10
src/routes/profile/$did/index.tsx
··· 188 188 <select 189 189 value={search.sort ?? "updated-desc"} 190 190 onChange={handleSortChange} 191 - className="px-4 py-2 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" 191 + className="px-4 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" 192 192 > 193 193 {SORT_OPTIONS.map((opt) => ( 194 194 <option key={opt.value} value={opt.value}> ··· 201 201 <select 202 202 value={search.format ?? ""} 203 203 onChange={handleFormatChange} 204 - className="px-4 py-2 bg-gray-100 dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" 204 + className="px-4 py-2 bg-gray-100 dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-white focus:outline-none focus:border-cyan-500" 205 205 > 206 206 <option value="">All Formats</option> 207 207 {availableFormats.map((format) => ( ··· 216 216 {isOwner && ( 217 217 <Link 218 218 to="/deck/new" 219 - className="flex items-center gap-2 px-4 py-2 bg-cyan-600 hover:bg-cyan-700 text-white font-medium rounded-lg transition-colors" 219 + className="flex items-center gap-2 px-4 py-2 bg-cyan-400 hover:bg-cyan-300 text-gray-900 font-medium rounded-lg transition-colors" 220 220 > 221 221 <Plus className="w-4 h-4" /> 222 222 New Deck ··· 225 225 </div> 226 226 227 227 {isLoading ? ( 228 - <div className="text-center py-8 bg-gray-50 dark:bg-slate-800 rounded-lg"> 229 - <p className="text-gray-600 dark:text-gray-400"> 228 + <div className="text-center py-8 bg-gray-50 dark:bg-zinc-800 rounded-lg"> 229 + <p className="text-gray-600 dark:text-zinc-300"> 230 230 Loading decklists... 231 231 </p> 232 232 </div> 233 233 ) : decks.length === 0 ? ( 234 - <div className="text-center py-8 bg-gray-50 dark:bg-slate-800 rounded-lg"> 235 - <p className="text-gray-600 dark:text-gray-400 mb-4"> 234 + <div className="text-center py-8 bg-gray-50 dark:bg-zinc-800 rounded-lg"> 235 + <p className="text-gray-600 dark:text-zinc-300 mb-4"> 236 236 {isOwner ? "No decklists yet" : "No decklists"} 237 237 </p> 238 238 {isOwner && ( 239 239 <Link 240 240 to="/deck/new" 241 - className="inline-block px-6 py-3 bg-cyan-600 hover:bg-cyan-700 text-white font-medium rounded-lg transition-colors" 241 + className="inline-block px-6 py-3 bg-cyan-400 hover:bg-cyan-300 text-gray-900 font-medium rounded-lg transition-colors" 242 242 > 243 243 Create Your First Deck 244 244 </Link> 245 245 )} 246 246 </div> 247 247 ) : filteredAndSorted.length === 0 ? ( 248 - <div className="text-center py-8 bg-gray-50 dark:bg-slate-800 rounded-lg"> 249 - <p className="text-gray-600 dark:text-gray-400 mb-4"> 248 + <div className="text-center py-8 bg-gray-50 dark:bg-zinc-800 rounded-lg"> 249 + <p className="text-gray-600 dark:text-zinc-300 mb-4"> 250 250 No decks match your filters 251 251 </p> 252 252 {hasActiveFilters && (
+16 -16
src/routes/profile/$did/list/$rkey/index.tsx
··· 113 113 114 114 if (isLoading || !list) { 115 115 return ( 116 - <div className="min-h-screen bg-white dark:bg-slate-900 flex items-center justify-center"> 117 - <p className="text-gray-600 dark:text-gray-400">Loading list...</p> 116 + <div className="min-h-screen bg-white dark:bg-zinc-900 flex items-center justify-center"> 117 + <p className="text-gray-600 dark:text-zinc-300">Loading list...</p> 118 118 </div> 119 119 ); 120 120 } ··· 168 168 const dateString = list.updatedAt ?? list.createdAt; 169 169 170 170 return ( 171 - <div className="min-h-screen bg-white dark:bg-slate-900"> 171 + <div className="min-h-screen bg-white dark:bg-zinc-900"> 172 172 <div className="max-w-4xl mx-auto px-6 py-8"> 173 173 <div className="flex items-start justify-between gap-4 mb-2"> 174 174 <div className="flex-1 min-w-0"> ··· 202 202 )} 203 203 </div> 204 204 205 - <p className="text-sm text-gray-500 dark:text-gray-500 mb-1"> 205 + <p className="text-sm text-gray-500 dark:text-zinc-400 mb-1"> 206 206 {handle ? ( 207 207 <> 208 208 by{" "} ··· 215 215 </Link> 216 216 </> 217 217 ) : ( 218 - <span className="inline-block h-4 w-20 bg-gray-200 dark:bg-slate-700 rounded animate-pulse align-middle" /> 218 + <span className="inline-block h-4 w-20 bg-gray-200 dark:bg-zinc-700 rounded animate-pulse align-middle" /> 219 219 )} 220 220 </p> 221 - <p className="text-sm text-gray-500 dark:text-gray-500 mb-4"> 221 + <p className="text-sm text-gray-500 dark:text-zinc-400 mb-4"> 222 222 Updated <ClientDate dateString={dateString} /> 223 223 </p> 224 224 ··· 235 235 </div> 236 236 237 237 {list.items.length === 0 ? ( 238 - <p className="text-gray-600 dark:text-gray-400 text-center py-12"> 238 + <p className="text-gray-600 dark:text-zinc-300 text-center py-12"> 239 239 This list is empty. 240 240 </p> 241 241 ) : ( ··· 274 274 275 275 if (isLoading || !card) { 276 276 return ( 277 - <div className="flex items-center gap-4 p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg animate-pulse"> 278 - <div className="w-16 h-22 bg-gray-300 dark:bg-slate-700 rounded" /> 277 + <div className="flex items-center gap-4 p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg animate-pulse"> 278 + <div className="w-16 h-22 bg-gray-300 dark:bg-zinc-700 rounded" /> 279 279 <div className="flex-1"> 280 - <div className="h-5 w-32 bg-gray-300 dark:bg-slate-700 rounded mb-2" /> 281 - <div className="h-4 w-24 bg-gray-200 dark:bg-slate-600 rounded" /> 280 + <div className="h-5 w-32 bg-gray-300 dark:bg-zinc-700 rounded mb-2" /> 281 + <div className="h-4 w-24 bg-gray-200 dark:bg-zinc-600 rounded" /> 282 282 </div> 283 283 </div> 284 284 ); ··· 289 289 <Link 290 290 to="/card/$id" 291 291 params={{ id: item.scryfallId }} 292 - className="group flex-1 flex items-start gap-4 p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 292 + className="group flex-1 flex items-start gap-4 p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg hover:border-cyan-500 dark:hover:border-cyan-500 motion-safe:hover:shadow-lg transition-colors motion-safe:transition-shadow" 293 293 > 294 294 <CardImage 295 295 card={{ id: item.scryfallId, name: card.name }} ··· 309 309 /> 310 310 )} 311 311 </div> 312 - <div className="flex items-center justify-between gap-3 text-xs text-gray-600 dark:text-gray-300"> 312 + <div className="flex items-center justify-between gap-3 text-xs text-gray-600 dark:text-zinc-300"> 313 313 <span className="truncate">{card.type_line}</span> 314 314 {card.set && ( 315 315 <SetSymbol setCode={card.set} rarity={card.rarity} size="small" /> 316 316 )} 317 317 </div> 318 318 {getPrimaryFace(card).oracle_text && ( 319 - <p className="text-xs text-gray-500 dark:text-gray-400 line-clamp-3 leading-tight"> 319 + <p className="text-xs text-gray-500 dark:text-zinc-300 line-clamp-3 leading-tight"> 320 320 <OracleText 321 321 text={getPrimaryFace(card).oracle_text ?? ""} 322 322 symbolSize="text" ··· 356 356 357 357 if (isError || !data) { 358 358 return ( 359 - <div className="flex items-center gap-4 p-4 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg opacity-50"> 359 + <div className="flex items-center gap-4 p-4 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg opacity-50"> 360 360 <div className="flex-1"> 361 - <p className="text-gray-600 dark:text-gray-400"> 361 + <p className="text-gray-600 dark:text-zinc-300"> 362 362 Deck no longer exists 363 363 </p> 364 364 </div>
+5 -5
src/routes/profile/$did/lists.tsx
··· 60 60 type="button" 61 61 onClick={() => createListMutation.mutate({ name: "New List" })} 62 62 disabled={createListMutation.isPending} 63 - className="flex items-center gap-2 px-4 py-2 bg-cyan-600 hover:bg-cyan-700 disabled:bg-cyan-600/50 text-white font-medium rounded-lg transition-colors" 63 + className="flex items-center gap-2 px-4 py-2 bg-cyan-400 hover:bg-cyan-300 disabled:bg-cyan-400/50 text-gray-900 font-medium rounded-lg transition-colors" 64 64 > 65 65 <Plus className="w-4 h-4" /> 66 66 New List ··· 69 69 </div> 70 70 71 71 {isLoading ? ( 72 - <div className="text-center py-8 bg-gray-50 dark:bg-slate-800 rounded-lg"> 73 - <p className="text-gray-600 dark:text-gray-400">Loading lists...</p> 72 + <div className="text-center py-8 bg-gray-50 dark:bg-zinc-800 rounded-lg"> 73 + <p className="text-gray-600 dark:text-zinc-300">Loading lists...</p> 74 74 </div> 75 75 ) : lists.length === 0 ? ( 76 - <div className="text-center py-8 bg-gray-50 dark:bg-slate-800 rounded-lg"> 77 - <p className="text-gray-600 dark:text-gray-400"> 76 + <div className="text-center py-8 bg-gray-50 dark:bg-zinc-800 rounded-lg"> 77 + <p className="text-gray-600 dark:text-zinc-300"> 78 78 {isOwner ? "No lists yet" : "No lists"} 79 79 </p> 80 80 </div>
+12 -12
src/routes/signin.tsx
··· 134 134 } 135 135 136 136 return ( 137 - <div className="min-h-screen flex flex-col items-center justify-center bg-white dark:bg-slate-900 px-4 py-8"> 138 - <div className="max-w-md w-full bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg shadow-lg p-8"> 137 + <div className="min-h-screen flex flex-col items-center justify-center bg-white dark:bg-zinc-900 px-4 py-8"> 138 + <div className="max-w-md w-full bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg p-8"> 139 139 <div className="flex items-center justify-center mb-6"> 140 140 <div className="p-3 bg-cyan-600 rounded-full"> 141 141 <LogIn size={32} className="text-white" /> ··· 144 144 <h1 className="text-3xl font-bold text-gray-900 dark:text-white text-center mb-2 font-display"> 145 145 Sign In 146 146 </h1> 147 - <p className="text-gray-600 dark:text-gray-400 text-center mb-8"> 147 + <p className="text-gray-600 dark:text-zinc-300 text-center mb-8"> 148 148 Sign in with an Atmosphere account to continue 149 149 </p> 150 150 151 151 <form onSubmit={handleSubmit}> 152 152 <label 153 153 htmlFor={handleId} 154 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" 154 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2" 155 155 > 156 156 Handle 157 157 </label> ··· 168 168 onFocus={() => setIsFocused(true)} 169 169 onKeyDown={handleKeyDown} 170 170 placeholder="alice.bsky.social" 171 - className="w-full px-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-600 disabled:opacity-50 disabled:cursor-not-allowed" 171 + className="w-full px-4 py-3 border border-gray-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-cyan-600 disabled:opacity-50 disabled:cursor-not-allowed" 172 172 disabled={isLoading} 173 173 required 174 174 role="combobox" ··· 185 185 id={listboxId} 186 186 role="listbox" 187 187 aria-labelledby={handleId} 188 - className="absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-lg shadow-lg max-h-60 overflow-y-auto" 188 + className="absolute z-50 w-full mt-1 bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg max-h-60 overflow-y-auto" 189 189 > 190 190 {results.map((result, index) => ( 191 191 <button ··· 198 198 role="option" 199 199 aria-selected={index === selectedIndex} 200 200 onClick={() => selectResult(result.handle)} 201 - className={`w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors ${ 201 + className={`w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-gray-100 dark:hover:bg-zinc-700 transition-colors ${ 202 202 index === selectedIndex 203 203 ? "bg-cyan-100 dark:bg-cyan-900/30" 204 204 : "" ··· 211 211 className="w-10 h-10 rounded-full" 212 212 /> 213 213 ) : ( 214 - <div className="w-10 h-10 rounded-full bg-gray-300 dark:bg-gray-600" /> 214 + <div className="w-10 h-10 rounded-full bg-gray-300 dark:bg-zinc-600" /> 215 215 )} 216 216 <div className="flex-1 min-w-0"> 217 217 {result.displayName && ( ··· 219 219 {result.displayName} 220 220 </div> 221 221 )} 222 - <div className="text-sm text-gray-600 dark:text-gray-400 truncate"> 222 + <div className="text-sm text-gray-600 dark:text-zinc-300 truncate"> 223 223 @{result.handle} 224 224 </div> 225 225 </div> ··· 240 240 <button 241 241 type="submit" 242 242 disabled={isLoading} 243 - className="w-full px-4 py-3 bg-cyan-600 hover:bg-cyan-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white rounded-lg transition-colors font-medium text-lg flex items-center justify-center gap-2" 243 + className="w-full px-4 py-3 bg-cyan-400 hover:bg-cyan-300 disabled:bg-gray-400 disabled:cursor-not-allowed text-gray-900 rounded-lg transition-colors font-medium text-lg flex items-center justify-center gap-2" 244 244 > 245 245 {isLoading ? ( 246 246 <> 247 - <div className="inline-block h-5 w-5 animate-spin rounded-full border-3 border-solid border-white border-r-transparent" /> 247 + <div className="inline-block h-5 w-5 animate-spin rounded-full border-3 border-solid border-gray-900 border-r-transparent" /> 248 248 <span>Signing in...</span> 249 249 </> 250 250 ) : ( ··· 253 253 </button> 254 254 </form> 255 255 256 - <p className="mt-6 text-center text-gray-600 dark:text-gray-400"> 256 + <p className="mt-6 text-center text-gray-600 dark:text-zinc-300"> 257 257 Don't have an account?{" "} 258 258 <Link 259 259 to="/signup"
+20 -20
src/routes/signup.tsx
··· 47 47 } 48 48 49 49 return ( 50 - <div className="min-h-screen flex flex-col items-center justify-center bg-white dark:bg-slate-900 px-4 py-8"> 51 - <div className="max-w-md w-full bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700 rounded-lg shadow-lg p-8"> 50 + <div className="min-h-screen flex flex-col items-center justify-center bg-white dark:bg-zinc-900 px-4 py-8"> 51 + <div className="max-w-md w-full bg-white dark:bg-zinc-800 border border-gray-300 dark:border-zinc-600 rounded-lg shadow-lg p-8"> 52 52 <div className="flex items-center justify-center mb-6"> 53 53 <div className="p-3 bg-emerald-600 rounded-full"> 54 54 <UserPlus size={32} className="text-white" /> ··· 57 57 <h1 className="text-3xl font-bold text-gray-900 dark:text-white text-center mb-2 font-display"> 58 58 Create Account 59 59 </h1> 60 - <p className="text-gray-600 dark:text-gray-400 text-center mb-6"> 60 + <p className="text-gray-600 dark:text-zinc-300 text-center mb-6"> 61 61 New to the Atmosphere? Create an account on a PDS host. 62 62 </p> 63 63 ··· 67 67 className={`block mb-4 p-4 rounded-lg border-2 cursor-pointer transition-colors ${ 68 68 selectedPds === DEFAULT_PDS_HOST.url 69 69 ? "border-emerald-500 bg-emerald-50 dark:bg-emerald-900/20" 70 - : "border-gray-300 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800" 70 + : "border-gray-300 dark:border-zinc-600 hover:bg-gray-50 dark:hover:bg-zinc-800" 71 71 }`} 72 72 > 73 73 <div className="flex items-center gap-3"> ··· 86 86 <div className="font-medium text-gray-900 dark:text-white"> 87 87 {DEFAULT_PDS_HOST.name} 88 88 </div> 89 - <div className="text-sm text-gray-600 dark:text-gray-400"> 89 + <div className="text-sm text-gray-600 dark:text-zinc-300"> 90 90 {DEFAULT_PDS_HOST.description} 91 91 </div> 92 92 </div> ··· 94 94 </label> 95 95 96 96 {/* Other hosts - collapsible */} 97 - <div className="border-t border-gray-200 dark:border-gray-700 pt-4 mb-4"> 97 + <div className="border-t border-gray-200 dark:border-zinc-600 pt-4 mb-4"> 98 98 <button 99 99 type="button" 100 100 onClick={() => setShowOtherHosts(!showOtherHosts)} 101 - className="w-full flex items-center justify-between text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white" 101 + className="w-full flex items-center justify-between text-sm text-gray-600 dark:text-zinc-300 hover:text-gray-900 dark:hover:text-white" 102 102 > 103 103 <span>Other hosting options</span> 104 104 <ChevronDown ··· 115 115 className={`block p-3 rounded-lg border cursor-pointer transition-colors ${ 116 116 selectedPds === host.url 117 117 ? "border-emerald-500 bg-emerald-50 dark:bg-emerald-900/20" 118 - : "border-gray-300 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800" 118 + : "border-gray-300 dark:border-zinc-600 hover:bg-gray-50 dark:hover:bg-zinc-800" 119 119 }`} 120 120 > 121 121 <div className="flex items-center gap-3"> ··· 134 134 <div className="font-medium text-gray-900 dark:text-white"> 135 135 {host.name} 136 136 </div> 137 - <div className="text-sm text-gray-600 dark:text-gray-400"> 137 + <div className="text-sm text-gray-600 dark:text-zinc-300"> 138 138 {host.description} 139 139 </div> 140 140 </div> ··· 145 145 className={`block p-3 rounded-lg border cursor-pointer transition-colors ${ 146 146 selectedPds === "custom" 147 147 ? "border-emerald-500 bg-emerald-50 dark:bg-emerald-900/20" 148 - : "border-gray-300 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800" 148 + : "border-gray-300 dark:border-zinc-600 hover:bg-gray-50 dark:hover:bg-zinc-800" 149 149 }`} 150 150 > 151 151 <div className="flex items-center gap-3"> ··· 164 164 <div className="font-medium text-gray-900 dark:text-white"> 165 165 Other... 166 166 </div> 167 - <div className="text-sm text-gray-600 dark:text-gray-400"> 167 + <div className="text-sm text-gray-600 dark:text-zinc-300"> 168 168 Enter a custom PDS URL 169 169 </div> 170 170 </div> ··· 175 175 <div className="ml-6 mt-2"> 176 176 <label 177 177 htmlFor={customPdsId} 178 - className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" 178 + className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2" 179 179 > 180 180 PDS URL 181 181 </label> ··· 185 185 value={customPdsUrl} 186 186 onChange={(e) => setCustomPdsUrl(e.target.value)} 187 187 placeholder="https://pds.example.com" 188 - className="w-full px-4 py-3 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-emerald-600" 188 + className="w-full px-4 py-3 border border-gray-300 dark:border-zinc-600 rounded-lg bg-white dark:bg-zinc-800 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-emerald-600" 189 189 required 190 190 /> 191 191 </div> ··· 196 196 197 197 {/* Acknowledgment checkbox for hosts with policy links */} 198 198 {needsAcknowledgment && ( 199 - <label className="flex items-start gap-3 mb-4 p-3 bg-amber-50 dark:bg-slate-800 border border-amber-200 dark:border-amber-700/50 rounded-lg cursor-pointer"> 199 + <label className="flex items-start gap-3 mb-4 p-3 bg-amber-50 dark:bg-zinc-800 border border-amber-200 dark:border-amber-700/50 rounded-lg cursor-pointer"> 200 200 <input 201 201 type="checkbox" 202 202 checked={acknowledgedPolicy} 203 203 onChange={(e) => setAcknowledgedPolicy(e.target.checked)} 204 204 className="mt-0.5 text-amber-600 focus:ring-amber-500" 205 205 /> 206 - <span className="text-sm text-gray-700 dark:text-gray-300"> 206 + <span className="text-sm text-gray-700 dark:text-zinc-300"> 207 207 I've read the{" "} 208 208 <a 209 209 href={selectedHost?.learnMoreUrl} ··· 242 242 </form> 243 243 244 244 {selectedHost && selectedPds !== "custom" && ( 245 - <div className="mt-4 p-3 bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg"> 246 - <div className="text-sm text-gray-600 dark:text-gray-400"> 245 + <div className="mt-4 p-3 bg-gray-50 dark:bg-zinc-800 border border-gray-200 dark:border-zinc-600 rounded-lg"> 246 + <div className="text-sm text-gray-600 dark:text-zinc-300"> 247 247 Available handles on {selectedHost.name}: 248 248 </div> 249 249 <div className="mt-1.5 flex flex-wrap gap-1"> 250 250 {selectedHost.handles.map((handle) => ( 251 251 <span 252 252 key={handle} 253 - className="px-2 py-0.5 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-full" 253 + className="px-2 py-0.5 text-xs bg-gray-200 dark:bg-zinc-700 text-gray-700 dark:text-zinc-300 rounded-full" 254 254 > 255 255 .{handle} 256 256 </span> ··· 267 267 size={16} 268 268 className="text-blue-600 dark:text-blue-400 flex-shrink-0 mt-0.5" 269 269 /> 270 - <p className="text-sm text-gray-700 dark:text-gray-300 leading-relaxed"> 270 + <p className="text-sm text-gray-700 dark:text-zinc-300 leading-relaxed"> 271 271 Each host has its own policies and backup systems. Your data lives 272 272 on the host you choose, but you can migrate later. 273 273 {selectedHost && ··· 302 302 </p> 303 303 </div> 304 304 305 - <p className="mt-6 text-center text-gray-600 dark:text-gray-400"> 305 + <p className="mt-6 text-center text-gray-600 dark:text-zinc-300"> 306 306 Already have an account?{" "} 307 307 <Link 308 308 to="/signin"
+9 -9
src/styles.css
··· 65 65 @custom-variant dark (&:where(.dark, .dark *)); 66 66 67 67 html { 68 - @apply bg-white dark:bg-slate-900; 68 + @apply bg-white dark:bg-zinc-900; 69 69 color-scheme: light; 70 70 } 71 71 72 72 body { 73 - @apply m-0 bg-white dark:bg-slate-900 font-sans; 73 + @apply m-0 bg-white dark:bg-zinc-900 font-sans; 74 74 -webkit-font-smoothing: antialiased; 75 75 -moz-osx-font-smoothing: grayscale; 76 76 } ··· 85 85 .dark { 86 86 color-scheme: dark; 87 87 /* Firefox scrollbar */ 88 - scrollbar-color: var(--color-gray-600) var(--color-gray-800); 88 + scrollbar-color: var(--color-zinc-600) var(--color-zinc-800); 89 89 } 90 90 91 91 .dark ::-webkit-scrollbar { ··· 94 94 } 95 95 96 96 .dark ::-webkit-scrollbar-track { 97 - background: var(--color-gray-800); 97 + background: var(--color-zinc-800); 98 98 } 99 99 100 100 .dark ::-webkit-scrollbar-thumb { 101 - background: var(--color-gray-600); 101 + background: var(--color-zinc-600); 102 102 border-radius: 6px; 103 - border: 2px solid var(--color-gray-800); 103 + border: 2px solid var(--color-zinc-800); 104 104 } 105 105 106 106 .dark ::-webkit-scrollbar-thumb:hover { 107 - background: var(--color-gray-500); 107 + background: var(--color-zinc-500); 108 108 } 109 109 110 110 /* Hide scrollbar utility */ ··· 141 141 } 142 142 143 143 .dark .prosemirror-editor .ProseMirror p.is-editor-empty:first-child::before { 144 - color: var(--color-gray-500); 144 + color: var(--color-zinc-500); 145 145 } 146 146 147 147 /* Empty editor placeholder using data attribute */ ··· 153 153 } 154 154 155 155 .dark .prosemirror-editor .ProseMirror:has(> p:only-child:empty)::before { 156 - color: var(--color-gray-500); 156 + color: var(--color-zinc-500); 157 157 }