From de37d81eaea5d6a68d580b8b44a2facc3d485746 Mon Sep 17 00:00:00 2001 From: Amolith Date: Sat, 8 Nov 2025 14:18:04 -0700 Subject: [PATCH] feat: add OKLCH palette and visual enhancements Introduces a comprehensive OKLCH-based color system via palette.css, replacing the previous RGB/hex approach with perceptually uniform colors. Adds visual feedback for top-voted items with checkmark indicator and 3D tactile button press effects. Room URLs now auto-update to include the room code for easier sharing. The new palette provides better dark mode support and color consistency across the interface while maintaining the existing green theme identity. Assisted-by: Claude Sonnet 4.5 via Crush --- server.ts | 4 + static/app.js | 42 ++++- static/index.html | 1 + static/palette.css | 113 +++++++++++++ static/style.css | 385 +++++++++++++++++++++++++++++++++------------ 5 files changed, 442 insertions(+), 103 deletions(-) create mode 100644 static/palette.css diff --git a/server.ts b/server.ts index cacb8e9e129ffc111e45c4d6d1abefd706ef2f0b..39639e64651d927f35ccbd200eb0c3834a44bd68 100644 --- a/server.ts +++ b/server.ts @@ -542,6 +542,10 @@ serve(async (req) => { const css = await Deno.readTextFile("./static/style.css"); return new Response(css, { headers: { "content-type": "text/css" } }); } + if (url.pathname === "/palette.css") { + const css = await Deno.readTextFile("./static/palette.css"); + return new Response(css, { headers: { "content-type": "text/css" } }); + } if (url.pathname === "/app.js") { const js = await Deno.readTextFile("./static/app.js"); return new Response(js, { headers: { "content-type": "application/javascript" } }); diff --git a/static/app.js b/static/app.js index b364517bbee794c02815d730f6bf455550a2acdf..a4732da6d60fee072cfc2bd35bf0be06bf834741 100644 --- a/static/app.js +++ b/static/app.js @@ -50,6 +50,9 @@ document.getElementById('leave-btn').addEventListener('click', () => { items = []; messageQueue = []; listContainer.innerHTML = ''; + + // Clear URL when leaving room + history.replaceState(null, '', location.pathname); }); document.getElementById('copy-btn').addEventListener('click', async () => { @@ -229,6 +232,11 @@ function handleMessage(msg) { } isReady = true; setUIEnabled(true); + + // Update URL to include room code for easy copying + const newUrl = `${location.origin}${location.pathname}?room=${currentRoom}`; + history.replaceState(null, '', newUrl); + renderTitle(); render(); break; @@ -305,6 +313,13 @@ function vote(itemId, voteType) { const sorted = getSortedItems(); selectedPosition = sorted.findIndex(i => i.id === itemId); + // Keep the button visually pressed briefly to avoid flicker + const btn = document.querySelector(`[data-item-id="${itemId}"] [data-action="vote"][data-vote-type="${voteType}"]`); + if (btn) { + btn.classList.add('press-lock'); + setTimeout(() => btn.classList.remove('press-lock'), 220); + } + lastAction = { type: 'vote', itemId, previousVote: currentVote }; if (currentVote === voteType) { @@ -569,15 +584,31 @@ function render() { // Sort: vetoed items last, then by score const sorted = getSortedItems(); + // Check if any votes have been cast + const hasAnyVotes = sorted.some(item => Object.keys(item.votes).length > 0); + + // Calculate highest score among non-vetoed items + const nonVetoedItems = sorted.filter(item => + !Object.values(item.votes).includes('veto') + ); + const highestScore = nonVetoedItems.length > 0 + ? Math.max(...nonVetoedItems.map(item => + Object.values(item.votes).reduce((sum, v) => + sum + (v === 'up' ? 1 : v === 'down' ? -1 : 0), 0) + )) + : -Infinity; + listContainer.innerHTML = sorted.map(item => { const myVote = item.votes[userId]; const score = Object.values(item.votes).reduce((sum, v) => sum + (v === 'up' ? 1 : v === 'down' ? -1 : 0), 0); const isVetoed = Object.values(item.votes).includes('veto'); const isSelected = item.id === selectedItemId; + const isTopVoted = hasAnyVotes && !isVetoed && score === highestScore && nonVetoedItems.length > 0; return ` -
+
+ ${isTopVoted ? '' : ''}
${escapeHtml(item.text)}
${score > 0 ? '+' : ''}${score}
@@ -662,6 +693,15 @@ listContainer.addEventListener('dblclick', (e) => { editItem(itemId); }); +// Minimal press-lock for non-vote buttons to smooth release +document.addEventListener('click', (e) => { + const btn = e.target.closest('button'); + if (!btn) return; + if (btn.classList.contains('vote-btn')) return; // handled in vote() + btn.classList.add('press-lock'); + setTimeout(() => btn.classList.remove('press-lock'), 180); +}); + // Make functions global window.vote = vote; window.deleteItem = deleteItem; diff --git a/static/index.html b/static/index.html index 6df8731dc25e52aa79aa35c8398411c0a42a4782..94e15797ca7340aa7d8d6b1ee70b20c19822fc38 100644 --- a/static/index.html +++ b/static/index.html @@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later Sift + diff --git a/static/palette.css b/static/palette.css new file mode 100644 index 0000000000000000000000000000000000000000..ce44f16fe75b8b777f0d23cd9b502da643f73249 --- /dev/null +++ b/static/palette.css @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: Amolith + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +/* + Colors generated by Theme Machine | MIT License + https://tools.keithjgrant.com/theme-machine/ +*/ +:root { + --stone-1: oklch(98% 0.003 121); + --stone-2: oklch(97% 0.006 121); + --stone-3: oklch(93% 0.01 121); + --stone-4: oklch(84% 0.011 121); + --stone-5: oklch(80% 0.015 121); + --stone-6: oklch(71% 0.018 121); + --stone-7: oklch(66% 0.019 121); + --stone-8: oklch(58% 0.02 121); + --stone-9: oklch(53% 0.019 121); + --stone-10: oklch(49% 0.018 121); + --stone-11: oklch(42% 0.016 121); + --stone-12: oklch(35% 0.014 121); + --stone-13: oklch(27% 0.011 121); + --stone-14: oklch(20% 0.009 121); + --stone-15: oklch(16% 0.007 121); + --stone-16: oklch(10% 0.005 121); + --stone: var(--stone-8); + + --ash-1: oklch(98% 0.003 301); + --ash-2: oklch(97% 0.006 301); + --ash-3: oklch(93% 0.01 301); + --ash-4: oklch(84% 0.011 301); + --ash-5: oklch(80% 0.015 301); + --ash-6: oklch(71% 0.018 301); + --ash-7: oklch(66% 0.019 301); + --ash-8: oklch(58% 0.02 301); + --ash-9: oklch(53% 0.019 301); + --ash-10: oklch(49% 0.018 301); + --ash-11: oklch(42% 0.016 301); + --ash-12: oklch(35% 0.014 301); + --ash-13: oklch(27% 0.011 301); + --ash-14: oklch(20% 0.009 301); + --ash-15: oklch(16% 0.007 301); + --ash-16: oklch(10% 0.005 301); + --ash: var(--ash-8); + + --avocado-1: oklch(98% 0.018 121); + --avocado-2: oklch(97% 0.038 121); + --avocado-3: oklch(93% 0.062 121); + --avocado-4: oklch(84% 0.074 121); + --avocado-5: oklch(80% 0.099 121); + --avocado-6: oklch(71% 0.117 121); + --avocado-7: oklch(66% 0.124 121); + --avocado-8: oklch(58% 0.13 121); + --avocado-9: oklch(53% 0.124 121); + --avocado-10: oklch(49% 0.117 121); + --avocado-11: oklch(42% 0.105 121); + --avocado-12: oklch(35% 0.092 121); + --avocado-13: oklch(27% 0.074 121); + --avocado-14: oklch(20% 0.056 121); + --avocado-15: oklch(16% 0.043 121); + --avocado-16: oklch(10% 0.028 122); + --avocado: var(--avocado-8); + + --lilac-1: oklch(97.9% 0.014 306); + --lilac-2: oklch(96.7% 0.024 311); + --lilac-3: oklch(92.7% 0.049 306); + --lilac-4: oklch(84% 0.074 301); + --lilac-5: oklch(80% 0.099 301); + --lilac-6: oklch(71% 0.117 301); + --lilac-7: oklch(66% 0.124 301); + --lilac-8: oklch(58% 0.13 301); + --lilac-9: oklch(53% 0.124 301); + --lilac-10: oklch(49% 0.117 301); + --lilac-11: oklch(42% 0.105 301); + --lilac-12: oklch(35% 0.092 301); + --lilac-13: oklch(27% 0.074 301); + --lilac-14: oklch(20% 0.056 301); + --lilac-15: oklch(16% 0.043 301); + --lilac-16: oklch(10% 0.031 301); + --lilac: var(--lilac-8); + + --cranberry-1: oklch(98% 0.01 25); + --cranberry-2: oklch(96% 0.03 25); + --cranberry-3: oklch(92% 0.06 25); + --cranberry-4: oklch(84% 0.09 25); + --cranberry-5: oklch(80% 0.12 25); + --cranberry-6: oklch(72% 0.15 25); + --cranberry-7: oklch(66% 0.17 25); + --cranberry-8: oklch(58% 0.18 25); + --cranberry-9: oklch(53% 0.19 25); + --cranberry-10: oklch(49% 0.18 25); + --cranberry-11: oklch(42% 0.16 25); + --cranberry-12: oklch(35% 0.14 25); + --cranberry-13: oklch(28% 0.12 25); + --cranberry-14: oklch(22% 0.1 25); + --cranberry-15: oklch(17% 0.08 25); + --cranberry-16: oklch(12% 0.06 25); + --cranberry: var(--cranberry-8); + --danger-color: var(--cranberry-9); + + --background-1: var(--stone-3); + --background-2: var(--stone-2); + --background-3: var(--ash-4); + --background-dark-1: var(--stone-14); + --background-dark-2: var(--stone-13); + --background-dark-3: var(--stone-11); + --text-1: var(--stone-12); + --text-2: var(--stone-13); + --brand-color: var(--avocado-8); + --shadow-color: var(--stone-16); +} \ No newline at end of file diff --git a/static/style.css b/static/style.css index 67b11c04ce2519dddf64e3cbfa5ecf766ae78012..a1ca4e433f54e8181a37db78c756b72c03c1dd92 100644 --- a/static/style.css +++ b/static/style.css @@ -6,43 +6,6 @@ :root { color-scheme: light dark; - - /* Light theme (default) */ - --bg-page: #f5f5f5; - --bg-surface: white; - --bg-header-code: #e8f5e0; - - --text-primary: #333; - --text-on-accent: white; - - --accent: #5a8c3a; - --accent-hover: #4a7230; - --accent-dark: #2d5016; - --accent-danger: #b22222; - - --border: #ddd; - --border-accent: #5a8c3a; - --shadow: rgba(0, 0, 0, 0.1); -} - -@media (prefers-color-scheme: dark) { - :root { - --bg-page: #1a1a1a; - --bg-surface: #2a2a2a; - --bg-header-code: #3a4a34; - - --text-primary: #e0e0e0; - --text-on-accent: white; - - --accent: #7ab859; - --accent-hover: #8cc96f; - --accent-dark: #5a8c3a; - --accent-danger: #d84444; - - --border: #444; - --border-accent: #7ab859; - --shadow: rgba(0, 0, 0, 0.3); - } } * { @@ -53,8 +16,8 @@ body { font-family: "Atkinson Hyperlegible Next", system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif; - background: var(--bg-page); - color: var(--text-primary); + background: var(--background-1); + color: var(--text-1); line-height: 1.6; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -78,7 +41,7 @@ body { #start-screen h1 { margin-bottom: 3rem; - color: var(--accent-dark); + color: var(--avocado-11); } .buttons { @@ -95,43 +58,69 @@ body { button { padding: 0.75rem 1.5rem; - background: var(--accent); - color: var(--text-on-accent); + background: var(--brand-color); + color: var(--stone-1); border: none; - border-radius: 6px; + border-radius: 8px; cursor: pointer; font-size: 1rem; - transition: background 0.2s, transform 0.05s, box-shadow 0.2s; + position: relative; + --btn-color: var(--brand-color); + transform: translateY(0); + box-shadow: + 0 6px 0 color-mix(in oklch, var(--btn-color) 60%, black), + 0 12px 18px color-mix(in oklch, var(--stone-16) 30%, transparent), + inset 0 1px 0 color-mix(in oklch, white 20%, transparent); + transition: + transform 140ms cubic-bezier(0.2, 0.7, 0.1, 1), + box-shadow 140ms cubic-bezier(0.2, 0.7, 0.1, 1), + background 140ms ease; } button:hover { - background: var(--accent-hover); + box-shadow: + 0 7px 0 color-mix(in oklch, var(--btn-color) 60%, black), + 0 14px 20px color-mix(in oklch, var(--stone-16) 35%, transparent), + inset 0 1px 0 color-mix(in oklch, white 25%, transparent); } button:active { - transform: translateY(1px); + transform: translateY(4px); + box-shadow: + 0 2px 0 color-mix(in oklch, var(--btn-color) 60%, black), + 0 6px 12px color-mix(in oklch, var(--stone-16) 25%, transparent), + inset 0 -1px 0 color-mix(in oklch, var(--btn-color) 50%, black); +} + +button.press-lock { + transform: translateY(4px); + box-shadow: + 0 2px 0 color-mix(in oklch, var(--btn-color) 60%, black), + 0 6px 12px color-mix(in oklch, var(--stone-16) 25%, transparent), + inset 0 -1px 0 color-mix(in oklch, var(--btn-color) 50%, black); } button:focus-visible, input:focus-visible, textarea:focus-visible { - outline: 2px solid var(--border-accent); + outline: 2px solid var(--avocado-7); outline-offset: 2px; } -input, textarea { +input, +textarea { padding: 0.75rem; - border: 1px solid var(--border); + border: 1px solid var(--stone-5); border-radius: 6px; font-size: 1rem; font-family: inherit; - background: var(--bg-surface); - color: var(--text-primary); + background: var(--stone-1); + color: var(--text-1); } input::placeholder, textarea::placeholder { - color: color-mix(in srgb, var(--text-primary) 50%, transparent); + color: color-mix(in oklch, var(--text-1) 50%, transparent); } #join-code { @@ -146,7 +135,7 @@ textarea::placeholder { .expiry-notice { font-size: 0.85rem; - color: color-mix(in srgb, var(--text-primary) 60%, transparent); + color: color-mix(in oklch, var(--text-1) 60%, transparent); margin-top: 1rem; } @@ -166,7 +155,7 @@ textarea::placeholder { align-items: center; margin-bottom: 2rem; padding-bottom: 1rem; - border-bottom: 2px solid var(--border-accent); + border-bottom: 2px solid var(--brand-color); } #list-screen header h2 { @@ -178,33 +167,37 @@ textarea::placeholder { align-items: center; gap: 0.5rem; font-size: 0.85rem; - color: color-mix(in srgb, var(--text-primary) 70%, transparent); + color: color-mix(in oklch, var(--text-1) 70%, transparent); } .status-dot { width: 8px; height: 8px; border-radius: 50%; - background: #888; + background: var(--stone-8); } .status-dot.connected { - background: #4caf50; - box-shadow: 0 0 4px #4caf50; + background: var(--brand-color); + box-shadow: 0 0 4px color-mix(in oklch, var(--brand-color) 60%, transparent); } .status-dot.connecting { - background: #ff9800; + background: var(--cranberry-7); animation: pulse 1.5s ease-in-out infinite; } .status-dot.disconnected { - background: #f44336; + background: var(--cranberry-12); } @keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } } .header-actions { @@ -214,15 +207,19 @@ textarea::placeholder { #room-code { font-family: monospace; - background: var(--bg-header-code); + background: var(--background-2); padding: 0.25rem 0.5rem; border-radius: 6px; } -#copy-btn, #copy-link-btn, #set-title-btn, #reset-votes-btn { - background: transparent; - color: var(--text-primary); - border: 1px solid var(--border); +#copy-btn, +#copy-link-btn, +#set-title-btn, +#reset-votes-btn { + background: var(--stone-1); + --btn-color: var(--stone-1); + color: var(--text-1); + border: none; width: 40px; height: 40px; padding: 0; @@ -231,9 +228,11 @@ textarea::placeholder { place-items: center; } -#copy-btn:hover, #copy-link-btn:hover, #set-title-btn:hover, #reset-votes-btn:hover { - background: var(--bg-header-code); - border-color: var(--border-accent); +#copy-btn:hover, +#copy-link-btn:hover, +#set-title-btn:hover, +#reset-votes-btn:hover { + filter: brightness(1.03); } .header-actions button svg { @@ -243,13 +242,14 @@ textarea::placeholder { } #leave-btn { - background: transparent; - color: var(--accent-dark); - border: 1px solid var(--border-accent); + background: var(--stone-1); + --btn-color: var(--stone-1); + color: var(--avocado-12); + border: none; } #leave-btn:hover { - background: var(--bg-header-code); + filter: brightness(1.03); } .add-section { @@ -280,11 +280,12 @@ textarea::placeholder { } .list-item { - background: var(--bg-surface); + position: relative; + background: var(--stone-1); padding: 1rem; margin-bottom: 0.5rem; border-radius: 8px; - box-shadow: 0 1px 3px var(--shadow); + box-shadow: 0 1px 3px color-mix(in oklch, var(--shadow-color) 20%, transparent); display: flex; justify-content: space-between; align-items: center; @@ -294,12 +295,13 @@ textarea::placeholder { .list-item:hover { transform: translateY(-1px); - box-shadow: 0 4px 12px var(--shadow); + box-shadow: 0 4px 12px color-mix(in oklch, var(--shadow-color) 25%, transparent); } .list-item.selected { - outline: 2px solid var(--border-accent); + outline: 2px solid var(--brand-color); outline-offset: 2px; + border-radius: 10px; } .list-item.vetoed { @@ -308,13 +310,15 @@ textarea::placeholder { overflow: hidden; } -.list-item:has(.vote-btn.active) { - border-left-color: var(--accent); +.top-check { + position: absolute; + left: -40px; + top: 50%; + transform: translateY(-50%); + color: var(--avocado-9); + flex-shrink: 0; } -.list-item:has(.vote-btn.veto-active) { - border-left-color: var(--accent-danger); -} .list-item-text { flex: 1; @@ -346,25 +350,40 @@ textarea::placeholder { .delete-btn { padding: 0.5rem; font-size: 0.9rem; - background: var(--accent-danger); - opacity: 0.7; + background: var(--danger-color); + --btn-color: var(--danger-color); + color: var(--stone-1); + opacity: 0.8; transition: opacity 0.2s, background 0.2s; } .delete-btn:hover { opacity: 1; - background: var(--accent-danger); + background: var(--cranberry-8); } .vote-btn.active { - background: var(--accent-dark); + background: var(--avocado-11); + color: var(--stone-1); + transform: translateY(4px); + box-shadow: + 0 2px 0 color-mix(in oklch, var(--btn-color) 60%, black), + 0 6px 12px color-mix(in oklch, var(--stone-16) 25%, transparent), + inset 0 -1px 0 color-mix(in oklch, var(--btn-color) 50%, black); } .vote-btn.veto-active { - background: var(--accent-danger); + background: var(--avocado-11); + color: var(--stone-1); + transform: translateY(4px); + box-shadow: + 0 2px 0 color-mix(in oklch, var(--btn-color) 60%, black), + 0 6px 12px color-mix(in oklch, var(--stone-16) 25%, transparent), + inset 0 -1px 0 color-mix(in oklch, var(--btn-color) 50%, black); } -.vote-btn svg, .delete-btn svg { +.vote-btn svg, +.delete-btn svg { width: 16px; height: 16px; display: block; @@ -374,8 +393,8 @@ textarea::placeholder { min-width: 40px; text-align: center; font-weight: bold; - color: var(--accent); - background: var(--bg-header-code); + color: var(--brand-color); + background: var(--stone-2); padding: 0.25rem 0.5rem; border-radius: 999px; } @@ -387,7 +406,7 @@ textarea::placeholder { left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, 0.5); + background: color-mix(in oklch, var(--stone-16) 60%, transparent); display: flex; align-items: center; justify-content: center; @@ -395,14 +414,14 @@ textarea::placeholder { } .modal-content { - background: var(--bg-surface); + background: var(--stone-1); padding: 2rem; border-radius: 8px; max-width: 500px; width: 90%; max-height: 80vh; overflow-y: auto; - box-shadow: 0 4px 20px var(--shadow); + box-shadow: 0 4px 20px color-mix(in oklch, var(--shadow-color) 35%, transparent); } .modal-header { @@ -411,17 +430,17 @@ textarea::placeholder { align-items: center; margin-bottom: 1.5rem; padding-bottom: 0.5rem; - border-bottom: 2px solid var(--border); + border-bottom: 2px solid var(--stone-5); } .modal-header h3 { margin: 0; - color: var(--accent-dark); + color: var(--avocado-12); } .modal-close { background: transparent; - color: var(--text-primary); + color: var(--text-1); border: none; font-size: 2rem; line-height: 1; @@ -432,11 +451,11 @@ textarea::placeholder { } .modal-close:hover { - color: var(--accent-danger); + color: var(--cranberry-9); } .modal-body h4 { - color: var(--accent); + color: var(--brand-color); margin-top: 1rem; margin-bottom: 0.5rem; } @@ -459,10 +478,10 @@ kbd { padding: 0.2rem 0.4rem; font-size: 0.85rem; font-family: monospace; - background: var(--bg-header-code); - border: 1px solid var(--border); + background: var(--background-2); + border: 1px solid var(--stone-5); border-radius: 4px; - box-shadow: 0 1px 2px var(--shadow); + box-shadow: 0 1px 2px color-mix(in oklch, var(--shadow-color) 20%, transparent); } /* Screen reader only */ @@ -484,3 +503,165 @@ kbd { animation: none !important; } } + +@media (prefers-color-scheme: dark) { + body { + background: var(--background-dark-1); + color: var(--stone-3); + } + + button { + background: var(--avocado-9); + --btn-color: var(--avocado-9); + color: var(--stone-1); + } + + button:hover { + background: var(--avocado-8); + } + + input, + textarea { + background: var(--background-dark-2); + border: 1px solid var(--stone-9); + color: var(--stone-3); + } + + input::placeholder, + textarea::placeholder { + color: color-mix(in oklch, var(--stone-3) 50%, transparent); + } + + .expiry-notice { + color: color-mix(in oklch, var(--stone-3) 60%, transparent); + } + + #list-screen header { + border-bottom: 2px solid var(--avocado-9); + } + + .connection-status { + color: color-mix(in oklch, var(--stone-3) 60%, transparent); + } + + .status-dot { + background: var(--stone-10); + } + + .status-dot.connected { + background: var(--avocado-9); + box-shadow: 0 0 4px color-mix(in oklch, var(--avocado-9) 60%, transparent); + } + + .status-dot.connecting { + background: var(--cranberry-8); + } + + .status-dot.disconnected { + background: var(--cranberry-13); + } + + #room-code { + background: var(--background-dark-2); + color: var(--stone-3); + } + + #copy-btn, + #copy-link-btn, + #set-title-btn, + #reset-votes-btn { + background: var(--background-dark-2); + --btn-color: var(--background-dark-2); + color: var(--stone-3); + border: none; + } + + #copy-btn:hover, + #copy-link-btn:hover, + #set-title-btn:hover, + #reset-votes-btn:hover { + filter: brightness(1.04); + } + + #leave-btn { + background: var(--background-dark-2); + color: var(--stone-3); + border: none; + --btn-color: var(--background-dark-2); + } + + #leave-btn:hover { + filter: brightness(1.04); + } + + .list-item { + background: var(--background-dark-2); + box-shadow: 0 1px 3px color-mix(in oklch, var(--shadow-color) 30%, transparent); + } + + .list-item:hover { + box-shadow: 0 4px 12px color-mix(in oklch, var(--shadow-color) 45%, transparent); + } + + .list-item.selected { + outline-color: var(--avocado-9); + } + + + .delete-btn { + background: var(--cranberry-10); + --btn-color: var(--cranberry-10); + } + + .delete-btn:hover { + background: var(--cranberry-9); + } + + .vote-btn.active { + background: var(--avocado-11); + } + + .vote-btn.veto-active { + background: var(--avocado-12); + } + + .score { + color: var(--avocado-8); + background: var(--stone-14); + } + + .modal { + background: color-mix(in oklch, var(--background-dark-3) 75%, transparent); + } + + .modal-content { + background: var(--background-dark-2); + box-shadow: 0 4px 20px color-mix(in oklch, var(--shadow-color) 70%, transparent); + } + + .modal-header { + border-bottom: 2px solid var(--stone-11); + } + + .modal-header h3 { + color: var(--avocado-8); + } + + .modal-close { + color: var(--stone-3); + } + + .modal-close:hover { + color: var(--cranberry-8); + } + + .modal-body h4 { + color: var(--avocado-8); + } + + kbd { + background: var(--background-dark-2); + border: 1px solid var(--stone-11); + box-shadow: 0 1px 2px color-mix(in oklch, var(--shadow-color) 50%, transparent); + } +}