diff --git a/scripts/ui-shots.mjs b/scripts/ui-shots.mjs index 4239161..330b965 100644 --- a/scripts/ui-shots.mjs +++ b/scripts/ui-shots.mjs @@ -271,6 +271,40 @@ const SCENES = [ await sleep(600) } }, + { + // The date fields appear only with "A range" chosen; they are what had no border colour (#268). + name: 'modal-export-range', + setup: async (p) => { + await openChannel(p, '#general') + await p.evaluate(click('.header-nameplate')) + await sleep(300) + await p.evaluate(click('.context-menu-item', 'Export')) + await sleep(500) + await p.evaluate(`[...document.querySelectorAll('.reason-prompt label')].find((l) => l.innerText.includes('A range'))?.click()`) + await sleep(400) + } + }, + { + // The pointer over a channel and over a member: how visible a hover is. + name: 'irc-hover-rows', + setup: async (p) => { + await openChannel(p, '#general') + const c = await centre(p, '.buffer-row', 'dev') + if (c) await mouse(p, 'mouseMoved', c.x, c.y) + await sleep(300) + }, + clip: { x: 0, y: 44, width: 420, height: 300 } + }, + { + name: 'irc-hover-member', + setup: async (p) => { + await openChannel(p, '#general') + const c = await centre(p, '.nick-row', 'carol') + if (c) await mouse(p, 'mouseMoved', c.x, c.y) + await sleep(300) + }, + clip: { x: 860, y: 44, width: 420, height: 300 } + }, { name: 'toasts', setup: async (p) => { diff --git a/src/renderer/src/app.css b/src/renderer/src/app.css index 3ea49cb..4fd7c06 100644 --- a/src/renderer/src/app.css +++ b/src/renderer/src/app.css @@ -42,7 +42,7 @@ .titlebar-title { font-size: var(--font-size-large); - font-weight: 500; + font-weight: var(--weight-medium); } .titlebar-status { @@ -51,7 +51,7 @@ gap: var(--spacing-xxs); margin-left: var(--spacing-s); padding: 2px var(--spacing-s); - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--surface-container-highest); color: var(--warning); font-size: var(--font-size-small); @@ -145,7 +145,7 @@ tools ran out of room too and spilled leftwards over the name. */ flex: 1 1 0; min-width: 0; - font-weight: 500; + font-weight: var(--weight-medium); } .main-body { @@ -196,64 +196,6 @@ padding: var(--spacing-m); } -.bufferlist-footer { - display: flex; - flex: none; - padding: var(--spacing-xs); - gap: var(--spacing-xs); -} - -.footer-button { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: var(--spacing-xs); - padding: 6px; - border-radius: var(--corner-radius-small); - color: var(--surface-variant-text); - font-size: var(--font-size-small); -} - -.footer-button:hover { - background: var(--primary-hover-light); - color: var(--surface-text); -} - -.account-header, -.group-header { - display: flex; - align-items: center; - padding: 0 var(--spacing-xs); - margin-top: var(--spacing-xs); -} - -.account-header-main, -.group-header-main { - flex: 1; - min-width: 0; - display: flex; - align-items: center; - gap: var(--spacing-xs); - padding: 4px var(--spacing-xs); - border-radius: var(--corner-radius-small); - color: var(--surface-variant-text); - font-size: var(--font-size-small); - font-weight: 500; - text-transform: uppercase; - letter-spacing: 0.03em; -} - -.account-header-main:hover, -.group-header-main:hover { - background: var(--surface-hover); - color: var(--surface-text); -} - -.guild-group .group-header { - padding-left: var(--spacing-m); -} - .connection-dot { width: 6px; height: 6px; @@ -291,7 +233,7 @@ .buffer-row.highlight .buffer-name { color: var(--surface-text); - font-weight: 600; + font-weight: var(--weight-semibold); } .buffer-name { @@ -317,7 +259,7 @@ display: flex; align-items: center; justify-content: center; - font-weight: 600; + font-weight: var(--weight-semibold); color: var(--primary-text); } @@ -334,10 +276,10 @@ flex: none; min-width: 18px; padding: 0 5px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--surface-container-highest); color: var(--surface-text); - font-size: 11px; + font-size: var(--font-size-xs); line-height: 18px; text-align: center; } @@ -345,7 +287,7 @@ .unread-badge.highlight { background: var(--primary); color: var(--primary-text); - font-weight: 600; + font-weight: var(--weight-semibold); } @@ -356,7 +298,7 @@ panel it used to live in is usually closed when one does. */ .verification-dialog { position: fixed; - z-index: 70; + z-index: var(--z-notice); right: var(--spacing-m); bottom: var(--spacing-m); width: min(360px, calc(100vw - var(--spacing-m) * 2)); @@ -367,7 +309,7 @@ background: var(--surface-container-high); border: 1px solid var(--outline-strong); border-radius: var(--corner-radius); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-2); } .verification-head { @@ -383,7 +325,7 @@ viewport, a panel can be as wide as it needs while the row stays narrow. */ .header-popover { position: fixed; - z-index: 60; + z-index: var(--z-popover); display: flex; flex-direction: column; gap: var(--spacing-xs); @@ -393,7 +335,7 @@ background: var(--surface-container-high); border: 1px solid var(--outline-strong); border-radius: var(--corner-radius); - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-2); } .popover-field { @@ -434,7 +376,7 @@ .search-scope .link-button.active { color: var(--primary); - font-weight: 600; + font-weight: var(--weight-semibold); } /* Inside a panel the results are the panel, so they drop the floating shell @@ -570,10 +512,10 @@ position: relative; flex: none; padding: 0 var(--spacing-xs); - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--success); - color: #fff; - font-weight: 700; + color: var(--on-accent); + font-weight: var(--weight-bold); } .poll-option.winner { @@ -594,7 +536,7 @@ border: 1px solid var(--outline-light); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35); + box-shadow: var(--shadow-2); overflow: hidden; } @@ -610,7 +552,7 @@ } .poll-title { - font-weight: 600; + font-weight: var(--weight-semibold); } .poll-buttons { @@ -650,7 +592,7 @@ inset: 0 auto 0 0; background: var(--primary); opacity: 0.28; - transition: width 0.3s ease; + transition: width var(--motion) ease; } /* The one you picked, which is worth seeing at a glance in a list of rows @@ -666,7 +608,7 @@ .poll-label, .poll-count { position: relative; - font-weight: 600; + font-weight: var(--weight-semibold); } .poll-label { @@ -691,7 +633,7 @@ display: block; height: 100%; background: var(--success); - transition: width 0.5s linear; + transition: width var(--motion-slow) linear; } /* Folded away: still running, still one click from being answered. */ @@ -721,13 +663,13 @@ .live-badge { flex: none; padding: 0 5px; - border-radius: 999px; + border-radius: var(--radius-pill); /* The same solid red as the hang-up button rather than --error, which is a pale pink for text and reads as decorative when used as a fill. */ - background: #c9403c; - color: #fff; + background: var(--danger); + color: var(--on-accent); font-size: 9px; - font-weight: 700; + font-weight: var(--weight-bold); letter-spacing: 0.05em; line-height: 18px; text-align: center; @@ -818,7 +760,7 @@ border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container); - box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35); + box-shadow: var(--shadow-2); } .command-picker-head { @@ -865,14 +807,14 @@ } .command-name { - font-weight: 500; + font-weight: var(--weight-medium); } /* The arguments are not the name: same line, quieter, so the name still reads as the thing being chosen. */ .command-usage { color: var(--surface-variant-text); - font-weight: 400; + font-weight: var(--weight-regular); } .command-source { @@ -916,10 +858,10 @@ -webkit-app-region: no-drag; right: var(--spacing-m); bottom: 90px; - z-index: 40; + z-index: var(--z-raised); width: 340px; margin: 0; - box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45); + box-shadow: var(--shadow-2); } /* @@ -1083,7 +1025,7 @@ button.video-tile { padding: 1px 6px; border-radius: var(--corner-radius-small); background: rgba(0, 0, 0, 0.55); - color: #fff; + color: var(--on-accent); } .call-stage-controls { @@ -1117,14 +1059,14 @@ button.video-tile { padding: var(--spacing-m); border-radius: var(--corner-radius); background: var(--surface-container); - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-2); } .screen-picker-head { display: flex; align-items: center; gap: var(--spacing-s); - font-weight: 500; + font-weight: var(--weight-medium); } .screen-picker-head .icon-button { @@ -1158,7 +1100,7 @@ button.video-tile { width: 100%; aspect-ratio: 16 / 9; object-fit: contain; - background: #000; + background: var(--media-backdrop); border-radius: var(--corner-radius-small); } @@ -1330,7 +1272,7 @@ button.video-tile { padding: 5px; border-radius: var(--corner-radius-small); background: var(--surface-container-highest); - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-1); } .message-row { @@ -1390,7 +1332,7 @@ button.video-tile { animation: none; transform: rotate(-90deg); stroke-linecap: butt; - transition: stroke-dasharray 150ms linear; + transition: stroke-dasharray var(--motion-fast) linear; } @keyframes upload-spin { @@ -1419,7 +1361,7 @@ button.video-tile { } .message-row.system .message-body { - color: var(--surface-variant-text); + color: var(--text-muted); font-style: italic; } @@ -1485,7 +1427,7 @@ button.video-tile { become a paragraph of text on a wide window. */ max-width: min(72%, 34rem); padding: var(--spacing-xs) var(--spacing-s); - border-radius: 18px; + border-radius: var(--radius-bubble); background: var(--bubble-them); color: var(--bubble-them-text); } @@ -1516,13 +1458,13 @@ button.video-tile { } .message-row.bubbles .message-from { - font-size: 12px; + font-size: var(--font-size-small); } .message-row.bubbles .bubble-time { display: block; margin-top: 2px; - font-size: 10px; + font-size: var(--font-size-xxs); text-align: right; font-variant-numeric: tabular-nums; /* Against a filled bubble rather than the page, so the muted grey used @@ -1575,7 +1517,7 @@ button.video-tile { width: 42px; text-align: right; font-variant-numeric: tabular-nums; - font-size: 11px; + font-size: var(--font-size-xs); } .message-avatar { @@ -1601,8 +1543,8 @@ button.video-tile { align-items: center; justify-content: center; color: #101418; - font-weight: 600; - font-size: 13px; + font-weight: var(--weight-semibold); + font-size: var(--font-size-compact); } .message-content { @@ -1619,7 +1561,7 @@ button.video-tile { } .message-from { - font-weight: 600; + font-weight: var(--weight-semibold); } /* Comfy and bubble layouts give the byline its own line; the compact log @@ -1630,7 +1572,7 @@ button.video-tile { } .edited-tag { - font-size: 11px; + font-size: var(--font-size-xs); } .reply-preview { @@ -1648,7 +1590,7 @@ button.video-tile { } .reply-from { - font-weight: 600; + font-weight: var(--weight-semibold); flex: none; } @@ -1666,8 +1608,8 @@ button.video-tile { gap: var(--spacing-s); margin: var(--spacing-s) var(--spacing-m); color: var(--error); - font-size: 11px; - font-weight: 600; + font-size: var(--font-size-xs); + font-weight: var(--weight-semibold); text-transform: uppercase; } @@ -1698,7 +1640,7 @@ button.video-tile { background: var(--surface-container-highest); color: var(--surface-text); font-size: var(--font-size-small); - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-1); } .jump-to-present:hover { @@ -1862,7 +1804,7 @@ img.composer-emoji { padding: var(--spacing-s) var(--spacing-s) var(--spacing-xxs); text-transform: uppercase; letter-spacing: 0.03em; - font-weight: 500; + font-weight: var(--weight-medium); } .nicklist-empty { @@ -1926,7 +1868,7 @@ img.composer-emoji { .panel-heading { margin: 0 0 var(--spacing-s); font-size: var(--font-size-medium); - font-weight: 600; + font-weight: var(--weight-semibold); color: var(--surface-variant-text); } @@ -2085,13 +2027,13 @@ img.composer-emoji { .context-menu { position: fixed; - z-index: 1000; + z-index: var(--z-menu); min-width: 170px; padding: var(--spacing-xs); border-radius: var(--corner-radius); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-2); } .context-menu-item { @@ -2141,7 +2083,7 @@ img.composer-emoji { border-radius: var(--corner-radius); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6); + box-shadow: var(--shadow-2); } .leave-confirm-head { @@ -2149,7 +2091,7 @@ img.composer-emoji { align-items: center; gap: var(--spacing-s); font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); margin-bottom: var(--spacing-s); } @@ -2196,12 +2138,12 @@ img.composer-emoji { border-radius: var(--corner-radius); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6); + box-shadow: var(--shadow-2); } .membership-rules-head { font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); margin-bottom: var(--spacing-s); } @@ -2226,7 +2168,7 @@ img.composer-emoji { border-radius: var(--corner-radius); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6); + box-shadow: var(--shadow-2); } .drop-confirm-head { @@ -2234,7 +2176,7 @@ img.composer-emoji { align-items: center; gap: var(--spacing-s); font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); margin-bottom: var(--spacing-m); } @@ -2294,7 +2236,7 @@ img.composer-emoji { left: 0; right: 0; bottom: 0; - z-index: 60; + z-index: var(--z-popover); display: flex; flex-direction: column; align-items: center; @@ -2302,9 +2244,9 @@ img.composer-emoji { gap: var(--spacing-s); pointer-events: none; background: rgba(0, 0, 0, 0.45); - color: #fff; + color: var(--on-accent); font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); outline: 2px dashed var(--primary); outline-offset: -10px; } @@ -2312,8 +2254,8 @@ img.composer-emoji { /* The one button in the app that destroys something. Not --error, which is a pale text colour and reads as decorative when used as a fill. */ .button.danger { - background: #c9403c; - color: #fff; + background: var(--danger); + color: var(--on-accent); } /* --- mentions ---------------------------------------------------------- */ @@ -2369,7 +2311,7 @@ img.composer-emoji { } .mention-from { - font-weight: 600; + font-weight: var(--weight-semibold); } /* Pushed to the far edge: the when is the least of the three things on this @@ -2407,11 +2349,11 @@ img.composer-emoji { pointer-events: none; min-width: 15px; padding: 0 3px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--primary); color: var(--primary-text); - font-size: 10px; - font-weight: 600; + font-size: var(--font-size-xxs); + font-weight: var(--weight-semibold); line-height: 15px; text-align: center; } @@ -2442,7 +2384,7 @@ img.composer-emoji { /* Inside the panel the rows sit against its own padding, not the sidebar's. */ .mentions-panel .mention-row { padding: var(--spacing-xs) var(--spacing-s); - border-radius: var(--spacing-xs); + border-radius: var(--radius-xs); } .mentions-panel .mention-row:hover { @@ -2481,7 +2423,7 @@ img.composer-emoji { flex-direction: column-reverse; gap: var(--spacing-s); /* Above the toasts, which are the only other floating thing this low. */ - z-index: 2100; + z-index: var(--z-call); max-width: 360px; } @@ -2493,7 +2435,7 @@ img.composer-emoji { border-radius: var(--corner-radius); background: var(--surface-container-highest); border: 1px solid var(--outline-medium); - box-shadow: 0 6px 22px rgba(0, 0, 0, 0.55); + box-shadow: var(--shadow-2); /* Breathes in time with the ringtone, so the panel reads as ringing rather than as one more notification that happens to have buttons. */ animation: call-pulse 2.6s ease-in-out infinite; @@ -2525,7 +2467,7 @@ img.composer-emoji { } .incoming-call-name { - font-weight: 600; + font-weight: var(--weight-semibold); } /* Green to answer and red to hang up, which is the one piece of visual @@ -2539,7 +2481,7 @@ img.composer-emoji { height: 36px; flex: none; border-radius: 50%; - color: #fff; + color: var(--on-accent); } .call-answer { @@ -2549,7 +2491,7 @@ img.composer-emoji { /* Not --error: that token is a pale pink meant for text on a dark surface, and a hang-up button filled with it reads as decorative. */ .call-decline { - background: #c9403c; + background: var(--danger); } .call-answer:hover, @@ -2564,7 +2506,7 @@ img.composer-emoji { display: flex; flex-direction: column; gap: var(--spacing-xs); - z-index: 2000; + z-index: var(--z-toast); max-width: 420px; } @@ -2576,7 +2518,7 @@ img.composer-emoji { border-radius: var(--corner-radius); background: var(--surface-container-highest); border: 1px solid var(--outline-medium); - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45); + box-shadow: var(--shadow-2); font-size: var(--font-size-small); } @@ -2694,7 +2636,7 @@ img.smilie { .rich-embed-title { display: block; - font-weight: 600; + font-weight: var(--weight-semibold); margin-bottom: 2px; } @@ -2703,7 +2645,7 @@ img.smilie { } .rich-embed-author { - font-weight: 600; + font-weight: var(--weight-semibold); margin-bottom: 2px; } @@ -2778,7 +2720,7 @@ img.smilie { width: min(420px, 100%); aspect-ratio: 16 / 9; border-radius: var(--corner-radius-small); - background: #000; + background: var(--media-backdrop); } /* The player, at the thumbnail's width and YouTube's shape. */ @@ -2788,7 +2730,7 @@ img.smilie { aspect-ratio: 16 / 9; border: none; border-radius: var(--corner-radius-small); - background: #000; + background: var(--media-backdrop); } .media-embed.youtube.playing { @@ -2806,10 +2748,10 @@ img.smilie { border: none; border-radius: var(--corner-radius-small); background: rgba(0, 0, 0, 0.6); - color: #fff; + color: var(--on-accent); cursor: pointer; opacity: 0; - transition: opacity 120ms; + transition: opacity var(--motion-fast); } .media-embed.youtube:hover .youtube-outside, @@ -2823,7 +2765,7 @@ img.smilie { display: flex; align-items: center; justify-content: center; - color: #fff; + color: var(--on-accent); text-shadow: 0 2px 8px rgba(0, 0, 0, 0.7); } @@ -2846,7 +2788,7 @@ img.smilie { align-items: center; gap: var(--spacing-xxs); padding: 1px var(--spacing-s); - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--surface-container-high); border: 1px solid transparent; line-height: 1.5; @@ -2893,7 +2835,7 @@ img.smilie { border-radius: var(--corner-radius-small); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-1); z-index: 5; } @@ -2918,9 +2860,9 @@ img.smilie { justify-content: center; width: 26px; height: 24px; - border-radius: 4px; + border-radius: var(--radius-xs); color: var(--surface-variant-text); - font-size: 14px; + font-size: var(--font-size-medium); } .toolbar-button:hover { @@ -2932,7 +2874,7 @@ img.smilie { .emoji-picker { position: fixed; - z-index: 1500; + z-index: var(--z-picker); width: min(420px, calc(100vw - 8px)); /* A fixed height, so the rail down the side always has the room the list has, as Discord's does. */ @@ -2945,7 +2887,7 @@ img.smilie { border-radius: var(--corner-radius); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 8px 28px rgba(0, 0, 0, 0.55); + box-shadow: var(--shadow-2); } .emoji-scroll { @@ -2957,7 +2899,7 @@ img.smilie { padding: var(--spacing-s) 2px var(--spacing-xxs); text-transform: uppercase; letter-spacing: 0.03em; - font-weight: 500; + font-weight: var(--weight-medium); } .emoji-grid { @@ -2987,7 +2929,7 @@ img.smilie { justify-content: center; height: 34px; border-radius: var(--corner-radius-small); - font-size: 20px; + font-size: var(--font-size-xlarge); line-height: 1; } @@ -3028,7 +2970,7 @@ img.smilie { .emoji-cell.emoji-token { overflow: hidden; padding: 0 2px; - font-size: 10px; + font-size: var(--font-size-xxs); line-height: 1.1; word-break: break-all; } @@ -3088,11 +3030,7 @@ img.smilie { .settings-rail-item.active { background: var(--primary-container); - font-weight: 500; -} - -.settings-rail-item.soon { - color: var(--surface-variant-text); + font-weight: var(--weight-medium); } .settings-content { @@ -3112,7 +3050,7 @@ img.smilie { .settings-section-title { margin: 0 0 var(--spacing-xxs); font-size: var(--font-size-medium); - font-weight: 600; + font-weight: var(--weight-semibold); color: var(--surface-variant-text); } @@ -3177,7 +3115,7 @@ img.smilie { border-radius: 10px; background: var(--surface-container-high); cursor: pointer; - transition: background-color 120ms ease, border-color 120ms ease; + transition: background-color var(--motion-fast) ease, border-color var(--motion-fast) ease; } .switch.on { @@ -3193,7 +3131,7 @@ img.smilie { height: 14px; border-radius: 50%; background: var(--surface-text); - transition: transform 120ms ease; + transition: transform var(--motion-fast) ease; } .switch.on .switch-knob { @@ -3252,7 +3190,7 @@ img.smilie { .setting-segmented button.active { background: var(--primary); color: var(--primary-text); - font-weight: 500; + font-weight: var(--weight-medium); } .button-row { @@ -3384,7 +3322,7 @@ img.smilie { } .invite-name { - font-weight: 600; + font-weight: var(--weight-semibold); } .invite-actions { @@ -3430,7 +3368,7 @@ img.smilie { } .join-friends-header .setting-text { - font-weight: 600; + font-weight: var(--weight-semibold); } .tab { @@ -3440,7 +3378,7 @@ img.smilie { .tab.active { color: var(--primary); - font-weight: 500; + font-weight: var(--weight-medium); } .friend-row { @@ -3495,7 +3433,7 @@ img.smilie { font-size: var(--font-size-small); } -.presence-dot { +.status-dot { width: 8px; height: 8px; border-radius: 50%; @@ -3503,15 +3441,15 @@ img.smilie { background: var(--outline); } -.presence-dot.online { +.status-dot.online { background: var(--success); } -.presence-dot.idle { +.status-dot.idle { background: var(--warning); } -.presence-dot.dnd { +.status-dot.dnd { background: var(--error); } @@ -3708,7 +3646,7 @@ img.smilie { display: block; height: 100%; background: var(--primary); - transition: width 120ms linear; + transition: width var(--motion-fast) linear; } /* --- a voice message ------------------------------------------------- */ @@ -3727,7 +3665,7 @@ img.smilie { background: var(--surface-container-high); /* A large radius rather than the small one the media cards use: this is a control, and the shape is most of what says so at a glance. */ - border-radius: 999px; + border-radius: var(--radius-pill); width: max-content; max-width: 100%; } @@ -3786,7 +3724,7 @@ img.smilie { border-radius: 2px; background: var(--outline-strong); align-self: center; - transition: background-color 90ms linear; + transition: background-color var(--motion-fast) linear; } /* How far in the listener is: the played part changes colour and keeps its @@ -3813,7 +3751,7 @@ img.smilie { .voice-speed { padding: 2px 7px; border: none; - border-radius: 999px; + border-radius: var(--radius-pill); font: inherit; font-size: var(--font-size-small); font-variant-numeric: tabular-nums; @@ -3857,7 +3795,7 @@ img.smilie { background: var(--surface-container-highest); border: 1px solid var(--outline); border-radius: var(--corner-radius-small); - box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35); + box-shadow: var(--shadow-2); z-index: 3; } @@ -4008,7 +3946,7 @@ img.smilie { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .forward-picker-list { @@ -4055,14 +3993,14 @@ img.smilie { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .discord-modal-head { display: flex; align-items: center; gap: var(--spacing-s); - font-weight: 500; + font-weight: var(--weight-medium); } .discord-modal-field { @@ -4086,14 +4024,14 @@ img.smilie { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .reason-prompt-head { display: flex; align-items: center; gap: var(--spacing-s); - font-weight: 500; + font-weight: var(--weight-medium); } .reason-prompt-box { @@ -4127,7 +4065,7 @@ img.smilie { left: 0; right: 0; bottom: 0; - z-index: 200; + z-index: var(--z-lightbox); /* Belt and braces: nothing in the viewer should ever be draggable. */ -webkit-app-region: no-drag; background: rgba(0, 0, 0, 0.85); @@ -4259,7 +4197,7 @@ video.lightbox-media { border-radius: 0 3px 3px 0; background: var(--surface-text); opacity: 0; - transition: height 120ms ease, opacity 120ms ease; + transition: height var(--motion-fast) ease, opacity var(--motion-fast) ease; } .rail-pill.active { @@ -4283,7 +4221,7 @@ video.lightbox-media { color: var(--surface-variant-text); /* Squircle-to-circle on hover and selection, the way Discord's does. */ border-radius: 34%; - transition: border-radius 120ms ease, background 120ms ease, color 120ms ease; + transition: border-radius var(--motion-fast) ease, background var(--motion-fast) ease, color var(--motion-fast) ease; } .rail-tile:hover .rail-face, @@ -4308,7 +4246,7 @@ video.lightbox-media { .rail-initials { font-size: var(--font-size-medium); - font-weight: 600; + font-weight: var(--weight-semibold); letter-spacing: 0.02em; } @@ -4322,7 +4260,7 @@ video.lightbox-media { width: 100%; height: 100%; border-radius: inherit; - color: #ffffff; + color: var(--on-accent); } /* Which service a tile belongs to, in the corner. Small and quiet - it @@ -4366,12 +4304,12 @@ video.lightbox-media { min-width: 18px; height: 18px; padding: 0 5px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--surface-container-highest); color: var(--surface-text); border: 2px solid var(--surface-container-lowest); - font-size: 11px; - font-weight: 600; + font-size: var(--font-size-xs); + font-weight: var(--weight-semibold); line-height: 14px; text-align: center; } @@ -4401,7 +4339,7 @@ video.lightbox-media { .group-title-name { flex: 1; min-width: 0; - font-weight: 600; + font-weight: var(--weight-semibold); } /* A brand mark kept in its own colours. Unlike a guild icon it is a logo @@ -4573,7 +4511,7 @@ video.lightbox-media { .render-error h2 { font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); } .render-error-detail { @@ -4607,7 +4545,7 @@ video.lightbox-media { width: 100%; max-height: 340px; border-radius: var(--corner-radius); - background: #000; + background: var(--media-backdrop); } .video-expand { @@ -4623,7 +4561,7 @@ video.lightbox-media { background: rgba(0, 0, 0, 0.55); border: none; border-radius: var(--corner-radius-small); - color: #fff; + color: var(--on-accent); opacity: 0; } @@ -4645,8 +4583,8 @@ video.lightbox-media { color: var(--surface-variant-text); text-transform: uppercase; letter-spacing: 0.06em; - font-size: 11px; - font-weight: 600; + font-size: var(--font-size-xs); + font-weight: var(--weight-semibold); } .category-head:hover { @@ -4684,7 +4622,7 @@ video.lightbox-media { .category-count { margin-left: auto; - font-weight: 400; + font-weight: var(--weight-regular); } .category-empty { @@ -4723,8 +4661,8 @@ video.lightbox-media { border-radius: var(--corner-radius-small); color: var(--surface-text); font-family: inherit; - font-size: 11px; - font-weight: 600; + font-size: var(--font-size-xs); + font-weight: var(--weight-semibold); letter-spacing: 0.06em; text-transform: uppercase; outline: none; @@ -4736,7 +4674,7 @@ video.lightbox-media { padding: var(--spacing-s) var(--spacing-s) var(--spacing-xxs); text-transform: uppercase; letter-spacing: 0.06em; - font-size: 11px; + font-size: var(--font-size-xs); } .voice-channel { @@ -4788,7 +4726,7 @@ video.lightbox-media { .voice-you { margin-left: auto; - font-size: 11px; + font-size: var(--font-size-xs); } /* The reason an account is not connected, under its name. Constrained rather @@ -4863,7 +4801,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-2); } /* Says what the button will actually do, which differs between a group and a @@ -5023,7 +4961,7 @@ video.lightbox-media { .channel-browser-name { flex: none; max-width: 40%; - font-weight: 500; + font-weight: var(--weight-medium); } /* Right-aligned and tabular so the counts line up as a column somebody can @@ -5052,7 +4990,7 @@ video.lightbox-media { background: var(--surface-container-highest); color: var(--surface-variant-text); font-size: 9px; - font-weight: 700; + font-weight: var(--weight-bold); letter-spacing: 0.04em; vertical-align: middle; } @@ -5146,7 +5084,7 @@ video.lightbox-media { position: absolute; top: calc(100% + var(--spacing-xs)); right: 0; - z-index: 40; + z-index: var(--z-raised); width: 380px; max-height: 420px; overflow-y: auto; @@ -5154,7 +5092,7 @@ video.lightbox-media { background: var(--surface-container-high); border: 1px solid var(--outline-strong); border-radius: var(--corner-radius); - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + box-shadow: var(--shadow-2); } .search-results-head, @@ -5170,7 +5108,7 @@ video.lightbox-media { padding: var(--spacing-xs) var(--spacing-s); background: none; border: none; - border-radius: var(--spacing-xs); + border-radius: var(--radius-xs); text-align: left; color: var(--surface-text); } @@ -5186,7 +5124,7 @@ video.lightbox-media { } .search-result-from { - font-weight: 600; + font-weight: var(--weight-semibold); } .search-result-body { @@ -5197,7 +5135,7 @@ video.lightbox-media { wall of similar rows. */ .message-row.found { background: var(--primary-pressed); - transition: background 0.4s ease; + transition: background var(--motion-slow) ease; } /* --- voice panel ------------------------------------------------------ */ @@ -5224,13 +5162,13 @@ video.lightbox-media { flex: 1; min-width: 0; color: var(--success); - font-weight: 600; + font-weight: var(--weight-semibold); font-size: var(--font-size-small); } /* Rising bars, so a glance says whether the microphone is hearing anything rather than only that a connection exists. */ -.voice-meter { +.voice-level { display: flex; align-items: flex-end; gap: 2px; @@ -5238,23 +5176,23 @@ video.lightbox-media { flex: none; } -.voice-meter-bar { +.voice-level-bar { width: 3px; background: var(--outline); border-radius: 1px; } -.voice-meter-bar:nth-child(1) { +.voice-level-bar:nth-child(1) { height: 4px; } -.voice-meter-bar:nth-child(2) { +.voice-level-bar:nth-child(2) { height: 8px; } -.voice-meter-bar:nth-child(3) { +.voice-level-bar:nth-child(3) { height: 12px; } -.voice-meter-bar.lit { +.voice-level-bar.lit { background: var(--success); } @@ -5281,11 +5219,11 @@ video.lightbox-media { .modal-scrim { position: fixed; inset: 0; - z-index: 60; + z-index: var(--z-dialog); display: flex; align-items: center; justify-content: center; - background: rgba(0, 0, 0, 0.6); + background: var(--scrim); } .modal { @@ -5298,7 +5236,7 @@ video.lightbox-media { background: var(--surface-container); border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .modal-head { @@ -5309,7 +5247,7 @@ video.lightbox-media { .modal-head h2 { font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); } .folder-field { @@ -5335,7 +5273,7 @@ video.lightbox-media { height: 34px; border: 2px solid transparent; border-radius: var(--corner-radius-small); - color: #fff; + color: var(--on-accent); } .swatch.chosen { @@ -5353,7 +5291,7 @@ video.lightbox-media { color: var(--primary-text); border: none; border-radius: var(--corner-radius-small); - font-weight: 600; + font-weight: var(--weight-semibold); } /* --- rail folders ------------------------------------------------------ */ @@ -5463,7 +5401,7 @@ video.lightbox-media { padding: var(--spacing-xxs); background: none; border: none; - border-radius: var(--spacing-xs); + border-radius: var(--radius-xs); text-align: left; color: inherit; } @@ -5483,7 +5421,7 @@ video.lightbox-media { padding: 0; background: none; border: none; - border-radius: var(--spacing-xs); + border-radius: var(--radius-xs); color: var(--surface-variant-text); } @@ -5505,7 +5443,7 @@ video.lightbox-media { } .user-name { - font-weight: 500; + font-weight: var(--weight-medium); color: var(--surface-text); } @@ -5521,7 +5459,7 @@ video.lightbox-media { display: flex; flex-direction: column-reverse; gap: var(--spacing-s); - z-index: 2100; + z-index: var(--z-call); width: 340px; max-width: calc(100vw - var(--spacing-xl)); } @@ -5534,7 +5472,7 @@ video.lightbox-media { border-radius: var(--corner-radius); background: var(--surface-container-highest); border: 1px solid var(--outline-medium); - box-shadow: 0 6px 22px rgba(0, 0, 0, 0.55); + box-shadow: var(--shadow-2); } .transfer-head { @@ -5583,7 +5521,7 @@ video.lightbox-media { .transfer-bar-fill { height: 100%; background: var(--primary); - transition: width 0.2s linear; + transition: width var(--motion) linear; } .transfer-panel p { @@ -5697,12 +5635,12 @@ video.lightbox-media { min-width: 17px; height: 17px; padding: 0 4px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--primary); color: var(--primary-text); border: 2px solid var(--surface-container-lowest); - font-size: 10px; - font-weight: 600; + font-size: var(--font-size-xxs); + font-weight: var(--weight-semibold); font-variant-numeric: tabular-nums; } @@ -5779,7 +5717,7 @@ video.lightbox-media { width: 9px; height: 9px; margin: 0 4px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--primary); flex: none; } @@ -5794,7 +5732,7 @@ video.lightbox-media { border-radius: 6px; background: var(--surface-container-lowest); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; - font-size: 13px; + font-size: var(--font-size-compact); letter-spacing: 0.06em; line-height: 1.7; overflow-wrap: anywhere; @@ -5851,8 +5789,8 @@ video.lightbox-media { } .emoji-jump-initial { - font-size: 12px; - font-weight: 600; + font-size: var(--font-size-small); + font-weight: var(--weight-semibold); } /* Same reasoning as the tab: shown, plainly unusable, and the title says @@ -5910,7 +5848,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius) var(--corner-radius) 0 0; background: var(--surface-container-high); - box-shadow: 0 -8px 28px rgba(0, 0, 0, 0.45); + box-shadow: var(--shadow-up); overflow: hidden; } @@ -6045,7 +5983,7 @@ video.lightbox-media { gap: 3px; margin-left: var(--spacing-xs); padding: 0 6px; - border-radius: 999px; + border-radius: var(--radius-pill); border: 1px solid var(--outline-medium); color: var(--surface-variant-text); font-style: normal; @@ -6083,7 +6021,7 @@ video.lightbox-media { gap: 3px; margin-left: var(--spacing-xs); padding: 0 6px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--whisper-tint); color: var(--whisper); font-style: normal; @@ -6189,7 +6127,7 @@ video.lightbox-media { window - it opens from the right-hand gutter, so it grows leftwards. */ .reader-list { position: fixed; - z-index: 40; + z-index: var(--z-raised); min-width: 180px; max-width: 260px; max-height: 320px; @@ -6201,7 +6139,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-2); } .reader-list-head { @@ -6242,7 +6180,7 @@ video.lightbox-media { .thread-title { flex: 1; - font-weight: 600; + font-weight: var(--weight-semibold); } .thread-body { @@ -6325,7 +6263,7 @@ video.lightbox-media { background: var(--surface-container); border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); overflow: hidden; } @@ -6555,7 +6493,7 @@ video.lightbox-media { background: var(--surface-container); border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .profile-head { @@ -6573,7 +6511,7 @@ video.lightbox-media { .profile-name { font-size: var(--font-size-large); - font-weight: 600; + font-weight: var(--weight-semibold); } .profile-roles { @@ -6681,8 +6619,8 @@ video.lightbox-media { width: 34px; height: 34px; border-radius: var(--corner-radius); - color: #fff; - font-weight: 600; + color: var(--on-accent); + font-weight: var(--weight-semibold); overflow: hidden; } @@ -6736,7 +6674,7 @@ video.lightbox-media { .account-group-name { flex: 1; - font-weight: 600; + font-weight: var(--weight-semibold); } /* --- tagging someone ----------------------------------------------------- @@ -6751,7 +6689,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.35); + box-shadow: var(--shadow-up); } .mention-option { @@ -6901,7 +6839,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); overflow-y: auto; } @@ -7063,7 +7001,7 @@ video.lightbox-media { .room-search-suggested-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--spacing-xxs) var(--spacing-m); max-height: 180px; overflow-y: auto; } .room-search-suggestion { display: flex; flex-direction: column; align-items: flex-start; text-align: left; background: none; border: 0; padding: var(--spacing-xxs) 0; color: inherit; cursor: pointer; font: inherit; } .room-search-suggestion:hover .room-search-suggestion-name { text-decoration: underline; } -.room-search-suggestion-name { font-weight: 600; } +.room-search-suggestion-name { font-weight: var(--weight-semibold); } /* A room being looked into, in the pane a conversation would fill. */ .peek-view { flex: 1; min-height: 0; display: flex; flex-direction: column; } @@ -7083,7 +7021,7 @@ video.lightbox-media { .stage { position: relative; flex: none; - background: #000; + background: var(--media-backdrop); color: #f2f3f5; overflow: hidden; user-select: none; @@ -7099,7 +7037,7 @@ video.lightbox-media { .stage-window-root { position: fixed; inset: 0; - background: #000; + background: var(--media-backdrop); } .stage.collapsed { @@ -7147,12 +7085,12 @@ video.lightbox-media { display: flex; align-items: center; gap: var(--spacing-xs); - font-weight: 600; + font-weight: var(--weight-semibold); } .stage-subtitle { - font-weight: 400; - font-size: 12px; + font-weight: var(--weight-regular); + font-size: var(--font-size-small); color: #b5bac1; margin-left: var(--spacing-xs); } @@ -7176,8 +7114,8 @@ video.lightbox-media { } .stage-head-button:hover { - background: rgba(255, 255, 255, 0.12); - color: #fff; + background: var(--overlay-control); + color: var(--on-accent); } .stage-area { @@ -7190,7 +7128,7 @@ video.lightbox-media { } .stage-empty { - color: #949ba4; + color: var(--text-muted); } .stage-grid { @@ -7229,7 +7167,7 @@ video.lightbox-media { justify-content: center; cursor: pointer; outline: none; - transition: box-shadow 0.12s ease; + transition: box-shadow var(--motion-fast) ease; } .stage-tile.strip { @@ -7242,12 +7180,12 @@ video.lightbox-media { /* Who is talking: the green ring Discord draws. */ .stage-tile.speaking { - box-shadow: inset 0 0 0 3px #23a55a; + box-shadow: inset 0 0 0 3px var(--speaking); } .stage-tile-face .avatar-fallback, .stage-tile-face img { - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); + box-shadow: var(--shadow-2); } .stage-picture { @@ -7256,7 +7194,7 @@ video.lightbox-media { width: 100%; height: 100%; object-fit: contain; - background: #000; + background: var(--media-backdrop); } .stage-tile-name { @@ -7269,22 +7207,22 @@ video.lightbox-media { gap: 4px; max-width: calc(100% - 16px); padding: 2px 8px; - border-radius: 4px; + border-radius: var(--radius-xs); background: rgba(0, 0, 0, 0.6); - color: #fff; - font-size: 13px; - font-weight: 500; + color: var(--on-accent); + font-size: var(--font-size-compact); + font-weight: var(--weight-medium); } .stage-tile.strip .stage-tile-name { left: 4px; bottom: 4px; - font-size: 11px; + font-size: var(--font-size-xs); padding: 1px 6px; } .stage-tile-state { - color: #f23f43; + color: var(--danger-text); } .stage-tile-live { @@ -7293,11 +7231,11 @@ video.lightbox-media { left: 8px; z-index: 1; padding: 1px 6px; - border-radius: 4px; - background: #da373c; - color: #fff; - font-size: 11px; - font-weight: 700; + border-radius: var(--radius-xs); + background: var(--danger); + color: var(--on-accent); + font-size: var(--font-size-xs); + font-weight: var(--weight-bold); letter-spacing: 0.04em; } @@ -7306,11 +7244,11 @@ video.lightbox-media { z-index: 1; padding: 8px 16px; border: 0; - border-radius: 4px; + border-radius: var(--radius-xs); background: rgba(0, 0, 0, 0.72); - color: #fff; + color: var(--on-accent); font: inherit; - font-weight: 600; + font-weight: var(--weight-semibold); cursor: pointer; } @@ -7331,7 +7269,7 @@ video.lightbox-media { border: 0; border-radius: 50%; background: rgba(0, 0, 0, 0.6); - color: #fff; + color: var(--on-accent); cursor: pointer; } @@ -7367,7 +7305,7 @@ video.lightbox-media { background: #2b2d31; color: #f2f3f5; cursor: pointer; - transition: background 0.12s ease; + transition: background var(--motion-fast) ease; } .stage-button.compact { @@ -7388,16 +7326,16 @@ video.lightbox-media { /* Something switched off that normally is on: a muted microphone. */ .stage-button.off { background: #f2f3f5; - color: #da373c; + color: var(--danger); } .stage-button.danger { - background: #da373c; - color: #fff; + background: var(--danger); + color: var(--on-accent); } .stage-button.danger:hover { - background: #a12828; + background: var(--danger-hover); } .stage-resize { @@ -7411,7 +7349,7 @@ video.lightbox-media { } .stage-resize:hover { - background: rgba(255, 255, 255, 0.12); + background: var(--overlay-control); } /* The line left above the conversation while the call is in its own window. */ @@ -7427,7 +7365,7 @@ video.lightbox-media { /* Something a call button asks before it acts, above the button. */ .stage-popover { position: fixed; - z-index: 1000; + z-index: var(--z-menu); transform: translateX(-50%); } @@ -7442,7 +7380,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .go-live-row { @@ -7508,8 +7446,8 @@ video.lightbox-media { padding: 2px 7px; border-radius: 10px; background: rgba(0, 0, 0, 0.6); - color: #fff; - font-size: 11px; + color: var(--on-accent); + font-size: var(--font-size-xs); font-variant-numeric: tabular-nums; pointer-events: none; } @@ -7573,7 +7511,7 @@ video.lightbox-media { background: transparent; color: var(--surface-variant-text, inherit); font: inherit; - font-weight: 600; + font-weight: var(--weight-semibold); cursor: pointer; } @@ -7652,7 +7590,7 @@ video.lightbox-media { color: var(--surface-variant-text, inherit); cursor: pointer; overflow: hidden; - transition: border-radius 0.12s; + transition: border-radius var(--motion-fast); } .emoji-rail-item:hover, @@ -7693,7 +7631,7 @@ video.lightbox-media { display: flex; flex-direction: column; min-width: 0; - font-weight: 600; + font-weight: var(--weight-semibold); } /* A small panel above a call button: the call's volume, the soundboard. */ @@ -7702,7 +7640,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-3); } .call-volume-panel { @@ -7775,7 +7713,7 @@ video.lightbox-media { } .soundboard-emoji { - font-size: 16px; + font-size: var(--font-size-large); line-height: 1; } @@ -7811,7 +7749,7 @@ video.lightbox-media { margin: 0; border: none; border-radius: 0; - background: #000; + background: var(--media-backdrop); } .call-stage.in-window .call-stage-title { @@ -7871,7 +7809,7 @@ video.lightbox-media { border: 1px solid var(--outline-medium); border-radius: var(--corner-radius); background: var(--surface-container-high); - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55); + box-shadow: var(--shadow-3); overflow: hidden; } @@ -7883,8 +7821,8 @@ video.lightbox-media { } .events-pane-count { - font-size: 16px; - font-weight: 600; + font-size: var(--font-size-large); + font-weight: var(--weight-semibold); } .events-pane-sep { @@ -7923,7 +7861,7 @@ video.lightbox-media { } .event-card.live { - border-color: #3ba55d; + border-color: var(--live); } .event-card-image { @@ -7944,13 +7882,13 @@ video.lightbox-media { display: flex; align-items: center; gap: 8px; - font-size: 13px; - font-weight: 600; + font-size: var(--font-size-compact); + font-weight: var(--weight-semibold); color: var(--primary); } .event-card.live .event-card-when { - color: #3ba55d; + color: var(--live); } .event-card-count { @@ -7966,7 +7904,7 @@ video.lightbox-media { .event-card-name { font-size: 18px; - font-weight: 600; + font-weight: var(--weight-semibold); } .event-card-desc { @@ -7998,7 +7936,7 @@ video.lightbox-media { background: var(--surface-container-highest); color: var(--surface-text, inherit); font: inherit; - font-weight: 500; + font-weight: var(--weight-medium); cursor: pointer; } @@ -8040,8 +7978,8 @@ video.lightbox-media { } .event-create-title { - font-size: 16px; - font-weight: 600; + font-size: var(--font-size-large); + font-weight: var(--weight-semibold); } .event-where { @@ -8070,7 +8008,7 @@ video.lightbox-media { } .event-where-label { - font-weight: 600; + font-weight: var(--weight-semibold); } .event-field { @@ -8102,7 +8040,7 @@ video.lightbox-media { /* "Invite friends to event": over the events pane. */ .share-event-backdrop { - z-index: 1600; + z-index: var(--z-sheet); } .share-event { @@ -8139,7 +8077,7 @@ video.lightbox-media { .share-event-section { padding: 10px 0 4px; - font-weight: 600; + font-weight: var(--weight-semibold); } .share-row { @@ -8159,7 +8097,7 @@ video.lightbox-media { flex: 1; flex-direction: column; min-width: 0; - font-weight: 600; + font-weight: var(--weight-semibold); } .share-event-foot { @@ -8172,7 +8110,7 @@ video.lightbox-media { } .share-event-foot-title { - font-weight: 600; + font-weight: var(--weight-semibold); } .share-event-link { @@ -8214,13 +8152,13 @@ video.lightbox-media { width: 8px; height: 8px; border-radius: 50%; - background: #3ba55d; + background: var(--live); } .live-event-label { - color: #3ba55d; - font-weight: 600; - font-size: 13px; + color: var(--live); + font-weight: var(--weight-semibold); + font-size: var(--font-size-compact); } .live-event-name { @@ -8229,8 +8167,8 @@ video.lightbox-media { background: none; color: var(--surface-text, inherit); font: inherit; - font-size: 16px; - font-weight: 700; + font-size: var(--font-size-large); + font-weight: var(--weight-bold); text-align: left; cursor: pointer; } @@ -8247,15 +8185,15 @@ video.lightbox-media { padding: 8px; border: 0; border-radius: var(--corner-radius-small); - background: #248046; - color: #fff; + background: var(--go); + color: var(--on-accent); font: inherit; - font-weight: 600; + font-weight: var(--weight-semibold); cursor: pointer; } .live-event-join:hover:not(:disabled) { - background: #1a6334; + background: var(--go-hover); } .live-event-join:disabled { @@ -8315,7 +8253,7 @@ video.lightbox-media { } .service-banner-title { - font-weight: 600; + font-weight: var(--weight-semibold); } .service-banner-detail { @@ -8356,7 +8294,7 @@ video.lightbox-media { /* An account's routing: three positions on one track, the chosen one under a sliding thumb (#257). */ .route-level-head { - font-weight: 500; + font-weight: var(--weight-medium); } .route-level { @@ -8365,7 +8303,7 @@ video.lightbox-media { grid-template-columns: repeat(3, 1fr); margin-top: var(--spacing-xs); padding: 3px; - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--surface-container-high); } @@ -8375,10 +8313,10 @@ video.lightbox-media { bottom: 3px; left: 3px; width: calc((100% - 6px) / 3); - border-radius: 999px; + border-radius: var(--radius-pill); background: var(--primary-container); transform: translateX(calc(var(--route-index, 0) * 100%)); - transition: transform 160ms ease; + transition: transform var(--motion-fast) ease; } .route-level-option { @@ -8386,7 +8324,7 @@ video.lightbox-media { z-index: 1; padding: 5px 8px; border: none; - border-radius: 999px; + border-radius: var(--radius-pill); background: none; color: var(--surface-variant-text); font: inherit; @@ -8396,7 +8334,7 @@ video.lightbox-media { .route-level-option.on { color: var(--primary-text); - font-weight: 500; + font-weight: var(--weight-medium); } .route-level-desc { @@ -8428,7 +8366,7 @@ video.lightbox-media { flex-direction: column; gap: var(--spacing-s); padding: var(--spacing-s) var(--spacing-m); - border: 1px solid #c9403c; + border: 1px solid var(--danger); border-radius: var(--corner-radius-small); } @@ -8468,7 +8406,7 @@ video.lightbox-media { /* --- formatting in the message box ------------------------------------- */ /* The box shows a format as it will look. */ -.composer-input [data-fmt='bold'] { font-weight: 700; } +.composer-input [data-fmt='bold'] { font-weight: var(--weight-bold); } .composer-input [data-fmt='italic'] { font-style: italic; } .composer-input [data-fmt='underline'] { text-decoration: underline; } .composer-input [data-fmt='strike'] { text-decoration: line-through; } @@ -8491,7 +8429,7 @@ video.lightbox-media { /* The strip over selected text. Centred on the selection, above it. */ .format-bar { position: fixed; - z-index: 1000; + z-index: var(--z-menu); transform: translate(-50%, calc(-100% - 8px)); display: flex; flex-wrap: wrap; @@ -8501,7 +8439,7 @@ video.lightbox-media { border-radius: var(--corner-radius); background: var(--surface-container-high); border: 1px solid var(--outline-medium); - box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5); + box-shadow: var(--shadow-2); } .format-group { @@ -8546,8 +8484,15 @@ video.lightbox-media { justify-content: center; padding: 0; border: 1px solid var(--outline-medium); - border-radius: 4px; + border-radius: var(--radius-xs); cursor: pointer; color: var(--surface-variant-text); background: none; } + +/* Timestamps and reply previews are there, and quieter than what was said. The + second class is what lets this beat `.muted`, which they also carry. */ +.message-time.muted, +.reply-preview.muted { + color: var(--text-muted); +} diff --git a/src/renderer/src/components/AddToConversation.tsx b/src/renderer/src/components/AddToConversation.tsx index 8ef6159..fdde782 100644 --- a/src/renderer/src/components/AddToConversation.tsx +++ b/src/renderer/src/components/AddToConversation.tsx @@ -158,7 +158,7 @@ export function AddToConversation({ buffer }: { buffer: BufferEntry }): JSX.Elem )} {f.globalName || f.username} - + ))} diff --git a/src/renderer/src/components/Icon.tsx b/src/renderer/src/components/Icon.tsx index 5327105..6f5e95c 100644 --- a/src/renderer/src/components/Icon.tsx +++ b/src/renderer/src/components/Icon.tsx @@ -20,7 +20,10 @@ export function Icon({ name, size = 20, color, fill, className, style }: Props): width: size, height: size, color, - ...(fill ? { fontVariationSettings: "'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24" } : {}), + // The glyph is drawn for its size: the font's optical-size axis runs + // 20-48, and small ones are given a little more weight, or they read + // as hairlines next to text. + fontVariationSettings: `'FILL' ${fill ? 1 : 0}, 'wght' ${size <= 14 ? 500 : 400}, 'GRAD' 0, 'opsz' ${Math.min(48, Math.max(20, size))}`, ...style }} > diff --git a/src/renderer/src/components/JoinPanel.tsx b/src/renderer/src/components/JoinPanel.tsx index ff9a764..706f639 100644 --- a/src/renderer/src/components/JoinPanel.tsx +++ b/src/renderer/src/components/JoinPanel.tsx @@ -886,7 +886,7 @@ function DiscordJoin({ account }: { account: Account }): JSX.Element { )} {f.globalName || f.username} {f.username} - + ))} diff --git a/src/renderer/src/components/VoicePanel.tsx b/src/renderer/src/components/VoicePanel.tsx index 3b774b0..9a7b3ba 100644 --- a/src/renderer/src/components/VoicePanel.tsx +++ b/src/renderer/src/components/VoicePanel.tsx @@ -57,9 +57,9 @@ export function VoicePanel(): JSX.Element | null {
- + {[0, 1, 2].map((i) => ( - + ))} Voice Connected diff --git a/src/renderer/src/styles.test.ts b/src/renderer/src/styles.test.ts new file mode 100644 index 0000000..ac4a59a --- /dev/null +++ b/src/renderer/src/styles.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from 'vitest' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' + +const css = ['theme.css', 'app.css'].map((f) => readFileSync(join(__dirname, f), 'utf8')).join('\n') + +describe('the stylesheets', () => { + it('only use custom properties that something defines, or that carry a fallback', () => { + const defined = new Set([...css.matchAll(/(--[a-z0-9-]+)\s*:/gi)].map((m) => m[1])) + // `var(--x)` with no comma is a use with no fallback. + const used = [...css.matchAll(/var\((--[a-z0-9-]+)\s*\)/gi)].map((m) => m[1]) + const missing = [...new Set(used.filter((name) => !defined.has(name)))] + // An undefined property draws a border in the text colour and text in + // whatever it inherited - which is how seven of them went unnoticed (#268). + expect(missing).toEqual([]) + }) +})