This commit is contained in:
Kalle
2026-09-17 17:34:36 +03:00
parent 4f81f2f3ce
commit 6ddc3985ae
90 changed files with 707 additions and 260 deletions

View File

@@ -56,6 +56,7 @@
## Styling
- use CSS modules
- hover/focus/selected state rules are in [styling.md](./docs/dev/styling.md)
- one file containing React code should have a matching CSS module file e.g. `Component.tsx` should have a file with the same root name i.e. `Component.module.css`
- prefer using [CSS variables](./app/styles/vars.css) for theming
- for any CSS variable used, make sure it is defined either locally or in the `vars.css` file

View File

@@ -10,6 +10,12 @@
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.15s;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {
outline: var(--focus-ring);

View File

@@ -47,9 +47,11 @@
color: var(--color-text);
font-size: var(--font-sm);
cursor: pointer;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-higher);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {

View File

@@ -51,14 +51,21 @@
font-weight: var(--weight-semi);
cursor: pointer;
text-decoration: none;
transition: color 0.15s;
transition:
background-color 0.15s,
color 0.15s;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}
&:focus-visible {
outline: var(--focus-ring);
outline-offset: -1px;
}
&:hover,
&[data-active="true"] {
color: var(--color-text-accent);
}
@@ -235,10 +242,16 @@
aspect-ratio: 1 / 1;
border-radius: var(--radius-field);
margin-inline-start: auto;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
&:focus-visible {
outline: var(--focus-ring);
}
}
.panelIconContainer {
@@ -278,10 +291,6 @@
font-size: var(--font-xs);
font-weight: var(--weight-semi);
text-align: center;
&:hover {
color: var(--color-text-accent);
}
}
.navItemImage {
@@ -291,6 +300,16 @@
background-color: var(--color-bg-higher);
display: grid;
place-items: center;
transition: background-color 0.15s;
.navItem:hover &,
.navItem:focus-visible & {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}
.youPanelUserRow {
@@ -309,8 +328,10 @@
text-decoration: none;
color: var(--color-text);
border-radius: var(--radius-field);
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
@@ -329,8 +350,12 @@
border-radius: var(--radius-field);
height: var(--field-size);
aspect-ratio: 1 / 1;
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}
@@ -361,12 +386,16 @@
padding: 0 var(--s-3);
background-color: var(--color-bg-high);
border-radius: var(--radius-selector);
transition:
background-color 0.15s,
color 0.15s;
& svg {
stroke-width: 3;
}
&:hover {
&:hover,
&:focus-visible {
color: var(--color-text);
background-color: var(--color-bg-higher);
}

View File

@@ -21,10 +21,11 @@
color: var(--color-text);
cursor: pointer;
border-radius: var(--radius-full);
transition: opacity 0.15s ease;
transition: background-color 0.15s;
&:hover:not(:disabled) {
opacity: 0.7;
&:hover:not(:disabled),
&:focus-visible {
background-color: var(--color-bg-high);
}
&:disabled {
@@ -47,10 +48,11 @@
font-weight: var(--weight-semi);
cursor: pointer;
border-radius: var(--radius-full);
transition: background-color 0.15s ease;
transition: background-color 0.15s;
&:hover:not(.pageActive) {
background-color: var(--color-bg-higher);
&:hover:not(.pageActive),
&:focus-visible:not(.pageActive) {
background-color: var(--color-bg-high);
}
}
@@ -74,10 +76,11 @@
background: transparent;
cursor: pointer;
border-radius: var(--radius-full);
transition: background-color 0.15s ease;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-higher);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -18,8 +18,9 @@
align-items: center;
justify-content: space-between;
color: var(--color-text);
transition: 0.1s ease-in-out background-color;
transition: background-color 0.15s;
border-radius: 0;
text-decoration: none;
&:first-of-type {
border-radius: var(--radius-box) var(--radius-box) 0 0;
@@ -53,7 +54,8 @@
font-size: var(--font-xs);
}
a.row:hover {
a.row:hover,
a.row:focus-visible {
background-color: var(--color-bg-higher);
}

View File

@@ -218,6 +218,7 @@
& a {
color: var(--color-text-high);
text-decoration: none;
transition: color 0.15s;
&:hover {
color: var(--color-text);

View File

@@ -4,11 +4,23 @@
gap: var(--s-1);
background: none;
border: none;
padding: 0;
padding: 0 var(--s-1);
margin-inline: calc(-1 * var(--s-1));
border-radius: var(--radius-field);
font: inherit;
color: inherit;
cursor: pointer;
text-transform: inherit;
transition: background-color 0.15s;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {
outline: var(--focus-ring);
}
}
.sortIcon {
@@ -18,9 +30,4 @@
.sortIconInactive {
opacity: 0.4;
.sortHeader:hover &,
.sortHeader:focus-visible & {
opacity: 0.85;
}
}

View File

@@ -50,9 +50,17 @@
height: var(--selector-size-sm);
aspect-ratio: 1 / 1;
border-radius: var(--radius-selector);
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
color: var(--color-text);
background-color: var(--color-bg-higher);
}
&:focus-visible {
outline: var(--focus-ring);
}
}

View File

@@ -19,6 +19,7 @@
align-items: center;
color: var(--color-text);
gap: var(--s-1-5);
text-decoration: none;
&.active {
color: var(--color-text-accent);
@@ -39,6 +40,14 @@
font-size: var(--font-xs);
text-align: center;
white-space: nowrap;
transition:
background-color 0.15s,
color 0.15s;
.linkContainer:hover &,
.linkContainer:focus-visible & {
background-color: var(--color-bg-higher);
}
}
.linkSecondary {
@@ -48,6 +57,12 @@
font-size: var(--font-xs);
color: var(--color-text-high);
background-color: transparent;
.linkContainer:hover &,
.linkContainer:focus-visible & {
background-color: var(--color-bg-high);
color: var(--color-text);
}
}
.borderGuy {

View File

@@ -17,10 +17,6 @@
font-size: var(--font-2xs);
}
&:not(.noRowHover) tbody tr:hover {
background-color: var(--color-bg-high);
}
& > thead > tr > th {
padding: var(--s-2);
}

View File

@@ -1,20 +1,9 @@
import clsx from "clsx";
import styles from "./Table.module.css";
export function Table({
children,
noRowHover,
}: {
children: React.ReactNode;
noRowHover?: boolean;
}) {
export function Table({ children }: { children: React.ReactNode }) {
return (
<div className={styles.container}>
<table
className={clsx(styles.table, { [styles.noRowHover]: noRowHover })}
>
{children}
</table>
<table className={styles.table}>{children}</table>
</div>
);
}

View File

@@ -1,4 +1,11 @@
.button {
--button-bg: var(--color-text-accent);
--button-hover-bg: color-mix(
in oklch,
var(--button-bg) 85%,
var(--color-text)
);
--button-hover-border: var(--button-hover-bg);
display: flex;
width: auto;
align-items: center;
@@ -6,7 +13,7 @@
border: var(--border-style-accent);
border-radius: var(--radius-field);
appearance: none;
background: var(--color-text-accent);
background: var(--button-bg);
color: var(--color-text-inverse);
cursor: pointer;
font-size: var(--font-sm);
@@ -16,6 +23,16 @@
outline-color: var(--color-text-accent);
height: var(--field-size);
white-space: nowrap;
text-decoration: none;
transition:
background-color 0.15s,
border-color 0.15s;
&:hover:not(:disabled):not([data-pending]),
&:focus-visible {
background-color: var(--button-hover-bg);
border-color: var(--button-hover-border);
}
&:focus-visible {
outline-style: solid;
@@ -36,20 +53,26 @@
}
.outlined {
background-color: transparent;
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
--button-hover-border: var(--color-text-accent);
color: var(--color-text-accent);
}
.outlinedSuccess {
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
--button-hover-border: var(--color-success);
border-color: var(--color-success);
background-color: transparent;
color: var(--color-success);
outline-color: var(--color-success);
}
.outlinedDestructive {
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
--button-hover-border: var(--color-error);
border-color: var(--color-error);
background-color: transparent;
color: var(--color-error);
outline-color: var(--color-error);
}
@@ -69,21 +92,11 @@
height: var(--field-size-lg);
}
.square {
aspect-ratio: 1 / 1;
padding: 0;
}
.circle {
border-radius: 50%;
aspect-ratio: 1 / 1;
padding: 0;
}
.minimal {
padding: 0;
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
padding: 0 var(--s-1);
border: none;
background-color: transparent;
color: var(--color-text-accent);
outline: initial;
@@ -93,34 +106,47 @@
}
.minimalSuccess {
padding: 0;
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
padding: 0 var(--s-1);
border: none;
background-color: transparent;
color: var(--color-success);
outline-color: var(--color-success);
}
.success {
--button-bg: var(--color-success);
border-color: var(--color-success);
background-color: var(--color-success);
outline-color: var(--color-success);
}
.destructive {
--button-bg: var(--color-error);
border-color: var(--color-error);
background-color: var(--color-error);
color: var(--color-text-inverse);
outline-color: var(--color-error);
}
.minimalDestructive {
padding: 0;
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
padding: 0 var(--s-1);
border: none;
background-color: transparent;
color: var(--color-error);
outline-color: var(--color-error);
}
.square {
aspect-ratio: 1 / 1;
padding: 0;
}
.circle {
border-radius: 50%;
aspect-ratio: 1 / 1;
padding: 0;
}
.buttonIcon {
min-width: 20px;
max-width: 20px;

View File

@@ -60,6 +60,12 @@
color: var(--color-text);
cursor: pointer;
margin: 0 auto;
transition: background-color 0.15s;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {
outline: var(--focus-ring);
@@ -67,13 +73,9 @@
}
&[data-selected] {
background-color: var(--color-bg-high);
background-color: var(--color-bg-higher);
color: var(--color-text-accent);
}
&:hover {
background-color: var(--color-bg-high);
outline: initial;
font-weight: var(--weight-bold);
}
}
@@ -83,11 +85,14 @@
border-spacing: 0;
}
& tr:hover td,
& tr:has([data-selected]) td {
& tr:hover td {
background-color: var(--color-bg-high);
}
& tr:has([data-selected]) td {
background-color: var(--color-bg-higher);
}
& tr:hover td:first-child,
& tr:has([data-selected]) td:first-child {
border-start-start-radius: var(--radius-field);
@@ -101,7 +106,8 @@
}
& .cell {
&:hover {
&:hover,
&:focus-visible {
background-color: transparent;
}

View File

@@ -49,4 +49,22 @@
background-color: var(--color-text-accent);
color: var(--color-text-inverse);
}
&:not(:checked) + .label:hover,
&:not(:checked):focus-visible + .label {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
&:checked + .label:hover,
&:checked:focus-visible + .label {
background-color: color-mix(
in oklch,
var(--color-text-accent) 85%,
var(--color-text)
);
}
}

View File

@@ -47,6 +47,7 @@
}
.item {
text-decoration: none;
display: flex;
align-items: center;
font-weight: var(--weight-bold);
@@ -64,8 +65,8 @@
transition: background-color 0.15s;
cursor: pointer;
&:hover,
&:focus {
&:hover:not(.itemDisabled),
&:focus:not(.itemDisabled) {
background-color: var(--color-bg-higher);
}
}

View File

@@ -29,6 +29,12 @@
width: 100%;
cursor: pointer;
text-align: start;
transition: background-color 0.15s;
&:hover:not(:disabled),
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible,
&[aria-expanded="true"] {
@@ -187,6 +193,12 @@
padding: 0;
cursor: pointer;
color: var(--color-text-high);
transition: color 0.15s;
&:hover,
&:focus-visible {
color: var(--color-text);
}
}
.searchField[data-empty] .searchClearButton {

View File

@@ -8,7 +8,9 @@
display: inline-grid;
justify-items: center;
grid-template-columns: 0fr 1fr 1fr;
transition: grid-template-columns 200ms;
transition:
grid-template-columns 200ms,
background-color 0.15s;
&:before {
content: "";
@@ -50,6 +52,20 @@
outline-offset: 1px;
}
&:hover:not(:has(> .input:disabled)) .indicator,
&:has(> .input:focus-visible) .indicator {
background: var(--color-bg-high);
}
&:hover:not(:has(> .input:disabled)):has(> .input:checked) .indicator,
&:has(> .input:focus-visible:checked) .indicator {
background: color-mix(
in oklch,
var(--color-text-accent) 85%,
var(--color-text)
);
}
&:has(> .input:disabled) {
cursor: not-allowed;

View File

@@ -22,9 +22,12 @@
.tabContainer {
min-width: fit-content;
margin-bottom: -2px;
text-decoration: none;
& .tabButton {
background-color: transparent;
--button-bg: transparent;
--button-hover-bg: transparent;
--button-hover-border: var(--color-border-high);
border: none;
font-size: var(--font-xs);
border-radius: 0;
@@ -33,6 +36,9 @@
white-space: nowrap;
flex: 1;
transform: none !important;
transition:
border-color 0.15s,
color 0.15s;
& img {
min-width: 16px;
@@ -41,12 +47,17 @@
}
}
&:hover:not([data-selected]) .tabButton {
color: var(--color-text);
}
&:focus-visible {
outline: var(--focus-ring);
outline-offset: -2px;
}
&[data-selected] .tabButton {
--button-hover-border: var(--color-text-accent);
border-color: var(--color-text-accent);
color: var(--color-text);
}

View File

@@ -89,10 +89,6 @@
color: inherit;
opacity: 0.75;
&:hover {
opacity: 1;
}
& svg {
width: 1rem;
}

View File

@@ -17,8 +17,13 @@
background-color: var(--color-bg-higher);
transition: background-color 0.15s;
&:has(.trigger:hover) {
background-color: var(--color-bg-high);
&:has(.trigger:hover),
&:has(.trigger:focus-visible) {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}
@@ -56,14 +61,23 @@
background-color: transparent;
color: var(--color-text-high);
cursor: pointer;
transition:
background-color 0.15s,
color 0.15s;
& > svg {
width: 14px;
height: 14px;
}
&:hover {
color: var(--color-error);
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
color: var(--color-text);
}
&:focus-visible {
@@ -94,7 +108,8 @@
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}

View File

@@ -42,14 +42,20 @@
padding: 0;
border-radius: var(--radius-field);
margin-inline-start: auto;
transition: background-color 0.15s;
@media screen and (min-width: 600px) {
height: var(--field-size-sm);
}
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
&:focus-visible {
outline: var(--focus-ring);
}
}
.roomList {
@@ -81,9 +87,18 @@
letter-spacing: 0.04em;
color: var(--color-text-high);
border-radius: var(--radius-field);
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
color: var(--color-text);
}
&:focus-visible {
outline: var(--focus-ring);
}
}
@@ -133,10 +148,16 @@
height: var(--field-size-sm);
aspect-ratio: 1 / 1;
border-radius: var(--radius-field);
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
&:focus-visible {
outline: var(--focus-ring);
}
}
.backButtonBadge {
@@ -175,7 +196,8 @@
border-radius: var(--radius-field);
transition: background-color 0.15s;
&:is(a):hover {
&:is(a):hover,
&:is(a):focus-visible {
background-color: var(--color-bg-higher);
}
}

View File

@@ -113,6 +113,7 @@
}
.chip {
text-decoration: none;
display: block;
max-width: 250px;
overflow: hidden;
@@ -150,6 +151,7 @@
}
.card {
text-decoration: none;
display: flex;
align-items: center;
min-width: 10.5rem;

View File

@@ -13,7 +13,8 @@
height: var(--field-size-sm);
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}

View File

@@ -52,12 +52,16 @@
height: var(--selector-size);
background-color: var(--color-bg-high);
border-radius: var(--radius-field);
transition:
background-color 0.15s,
color 0.15s;
& svg {
stroke-width: 3;
}
&:hover {
&:hover,
&:focus-visible {
color: var(--color-text);
background-color: var(--color-bg-higher);
}

View File

@@ -14,6 +14,7 @@
outline: none;
color: inherit;
text-decoration: none;
transition: background-color 0.15s;
&:hover,
&:focus {

View File

@@ -118,6 +118,7 @@
}
.previewIcon {
text-decoration: none;
display: flex;
flex-shrink: 0;
padding: var(--s-1);

View File

@@ -19,9 +19,14 @@
cursor: pointer;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {
outline: var(--focus-ring);
}
}
.selectedWeaponName {

View File

@@ -48,9 +48,18 @@
color: var(--color-text-inverse);
text-decoration: none;
flex-shrink: 0;
transition: background-color 0.2s;
transition: background-color 0.15s;
line-height: 1;
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-text-accent) 85%,
var(--color-text)
);
}
&:focus-visible {
outline: var(--focus-ring);
outline-offset: 1px;
@@ -375,8 +384,10 @@ shown, so the popover's user agent styles are reset here.
margin-left: calc(-1 * var(--s-1));
flex: 1;
min-width: 0;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
@@ -405,8 +416,13 @@ shown, so the popover's user agent styles are reset here.
border-radius: var(--radius-field);
color: var(--color-text-high);
cursor: pointer;
text-decoration: none;
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}

View File

@@ -174,8 +174,8 @@
transition: background-color 0.15s;
height: 100%;
&:hover .checkCircle {
border-color: var(--color-accent-high);
&:hover {
background-color: var(--color-bg-higher);
}
@container (max-width: 599px) {

View File

@@ -84,7 +84,7 @@
width: 24px;
height: 24px;
border-radius: 100%;
background-color: var(--color-bg-higher);
--button-bg: var(--color-bg-higher);
border: none;
padding: 0;
cursor: pointer;

View File

@@ -159,6 +159,13 @@
font-weight: var(--weight-semi);
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text-high);
transition: color 0.15s;
&:hover,
&:focus-visible {
color: var(--color-text);
}
&::before,
&::after {
@@ -320,7 +327,6 @@
width: auto;
padding: 0;
border: none;
background: transparent;
color: inherit;
font-size: inherit;
font-weight: inherit;
@@ -433,7 +439,6 @@
display: flex;
align-items: center;
gap: var(--s-2);
background: transparent;
border: none;
padding: var(--s-0-5) var(--s-1);
border-radius: var(--radius-field);

View File

@@ -6,6 +6,16 @@
border-radius: var(--radius-full);
padding: var(--s-0-5) var(--s-1-5);
cursor: pointer;
transition: background-color 0.15s;
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
@container weapon-pool (max-width: 150px) {
display: grid;

View File

@@ -1,13 +1,9 @@
.thumbnail {
cursor: pointer;
transition: all 0.2s ease;
&:hover {
scale: 1.025;
}
}
.dialogTag {
text-decoration: none;
background-color: #fff;
border-radius: var(--radius-box);
color: #000;
@@ -17,6 +13,7 @@
}
.dialogTagUser {
text-decoration: none;
background-color: var(--color-accent);
}

View File

@@ -30,16 +30,23 @@
align-items: center;
gap: 2px;
align-self: end;
padding: 0;
padding: 0 var(--s-1);
margin-inline: calc(-1 * var(--s-1));
background: none;
border: none;
border-radius: var(--radius-field);
font-size: var(--font-3xs);
line-height: 1rem;
color: var(--color-text-high);
white-space: nowrap;
cursor: pointer;
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}

View File

@@ -118,8 +118,13 @@
border-radius: var(--radius-field);
color: var(--color-text-high);
cursor: pointer;
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}

View File

@@ -71,6 +71,7 @@
}
.noticeableLink {
text-decoration: none;
display: flex;
width: 100%;
align-items: center;
@@ -174,11 +175,12 @@
}
.statCardPopoverTrigger {
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
display: inline;
height: 1rem;
padding: 0;
border: none;
background-color: transparent;
color: var(--color-accent);
font-size: var(--font-md);
font-weight: var(--weight-bold);

View File

@@ -24,9 +24,12 @@
height: 100%;
min-width: var(--card-width);
max-width: var(--card-width);
text-decoration: none;
transition: background-color 0.15s;
&:hover .avatarImg {
outline: 6px solid var(--color-bg-higher);
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
}

View File

@@ -34,6 +34,7 @@
all: unset;
background-color: var(--color-bg-higher);
border: var(--border-style);
transition: background-color 0.15s;
display: flex;
align-items: center;
gap: var(--s-2);
@@ -47,11 +48,25 @@
outline: var(--focus-ring);
}
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
&:not(.navigateArrowButton) {
justify-content: center;
flex-basis: 100%;
background-color: var(--color-bg);
min-height: 30px;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
& svg {

View File

@@ -154,8 +154,8 @@
position: absolute;
font-size: var(--font-2xs);
font-weight: var(--weight-bold);
--button-bg: var(--color-bg-higher);
border-radius: var(--radius-field);
background-color: var(--color-bg-higher);
border: none;
color: var(--color-text);
bottom: 60px;

View File

@@ -20,9 +20,15 @@
color: var(--color-text);
width: 100%;
text-align: left;
transition: background-color 0.15s;
&:hover {
background: var(--color-bg-high);
&:hover,
&:focus-visible {
background: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}
@@ -105,9 +111,14 @@
border: 1px solid transparent;
border-radius: var(--radius-selector);
cursor: pointer;
transition:
background-color 0.15s,
color 0.15s;
&:hover {
text-decoration: line-through;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}
}
@@ -190,10 +201,15 @@
font-size: var(--font-xs);
color: var(--color-text);
cursor: pointer;
transition: background-color 0.15s ease;
transition: background-color 0.15s;
&:hover:not(:disabled) {
background: var(--color-bg-high);
&:hover:not(:disabled),
&:focus-visible {
background: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
&:disabled {
@@ -222,10 +238,15 @@
font-size: var(--font-xs);
color: var(--color-text-high);
cursor: pointer;
transition: background-color 0.15s ease;
transition: background-color 0.15s;
&:hover {
background: var(--color-bg-high);
&:hover,
&:focus-visible {
background: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}

View File

@@ -20,9 +20,15 @@
color: var(--color-text);
width: 100%;
text-align: left;
transition: background-color 0.15s;
&:hover {
background: var(--color-bg-high);
&:hover,
&:focus-visible {
background: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}

View File

@@ -99,9 +99,15 @@
line-height: 1;
color: var(--color-text-high);
flex-shrink: 0;
border-radius: var(--radius-field);
transition:
background-color 0.15s,
color 0.15s;
&:hover {
color: var(--color-error);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}
}

View File

@@ -82,19 +82,20 @@
border: 2px solid transparent;
border-radius: var(--radius-box);
cursor: pointer;
transition: border-color 0.1s;
transition: background-color 0.15s;
&:hover {
border-color: var(--color-text-accent);
&:hover:not(:disabled),
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
&:hover {
border-color: transparent;
}
}
}

View File

@@ -12,11 +12,12 @@
}
.popoverTrigger {
--button-bg: transparent;
--button-hover-bg: var(--color-bg-high);
display: inline;
height: 1rem;
padding: 0;
border: none;
background-color: transparent;
color: var(--color-text-accent);
font-size: var(--font-md);
font-weight: var(--weight-bold);

View File

@@ -50,9 +50,15 @@
font-size: var(--font-xs);
font-weight: var(--weight-semi);
vertical-align: middle;
transition: background-color 0.15s ease-out;
text-decoration: none;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-high);
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}

View File

@@ -101,6 +101,7 @@
}
.editButton {
text-decoration: none;
font-size: var(--font-2xs);
font-weight: var(--weight-semi);
border-radius: var(--radius-selector);

View File

@@ -48,8 +48,10 @@
border-radius: 0 0 var(--radius-selector) var(--radius-selector);
background-color: var(--color-bg);
cursor: pointer;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
@@ -123,8 +125,10 @@
border-radius: 0 var(--radius-selector) var(--radius-selector) 0;
background-color: var(--color-bg);
cursor: pointer;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
@@ -177,8 +181,10 @@
background: transparent;
cursor: grab;
touch-action: none;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -24,9 +24,13 @@
column-gap: var(--s-2);
padding-block: var(--s-3);
color: var(--color-text);
border-radius: var(--radius-field);
text-decoration: none;
transition: background-color 0.15s;
&:hover .imageContainer {
outline: 3px solid var(--color-bg-higher);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-within .imageContainer {

View File

@@ -71,6 +71,12 @@
border-radius: var(--radius-field);
width: var(--field-size);
height: var(--field-size);
transition: background-color 0.15s;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {
outline: var(--focus-ring);

View File

@@ -36,9 +36,14 @@
.gearLink {
display: inline-flex;
align-items: center;
border-radius: var(--radius-rounded);
padding: var(--s-0-5);
margin: calc(-1 * var(--s-0-5));
border-radius: var(--radius-field);
text-decoration: none;
transition: background-color 0.15s;
&:hover {
filter: brightness(1.2);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -51,10 +51,6 @@
text-align: left;
& tbody {
& tr:hover {
background-color: var(--color-bg-high);
}
& td {
padding: var(--s-2) var(--s-3);
border-bottom: 1px solid var(--color-border);
@@ -125,6 +121,7 @@
.expandableRow .paramName {
cursor: pointer;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-high);

View File

@@ -204,6 +204,11 @@ button.cardToggle {
cursor: pointer;
font-size: var(--font-2xs);
color: var(--color-text-high);
transition: color 0.15s;
&:hover {
color: var(--color-text);
}
}
.json {

View File

@@ -1,14 +1,17 @@
/* an unstyled button so the image itself is the target */
button.thumbButton {
height: auto;
padding: 0;
border: none;
background: none;
margin-inline-start: auto;
margin-block: -2px;
padding: 2px;
border-radius: var(--radius-field);
transition: background-color 0.15s;
&:hover {
filter: brightness(1.2);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -12,6 +12,7 @@
background-repeat: no-repeat;
color: var(--color-text);
cursor: pointer;
transition: background-color 0.15s;
font-family: inherit;
font-size: var(--font-xs);
height: var(--field-size-sm);
@@ -31,6 +32,11 @@
cursor: not-allowed;
opacity: 0.5;
}
&:hover:not(:disabled),
&:focus-visible {
background-color: var(--color-bg-high);
}
}
.preview {

View File

@@ -268,14 +268,18 @@ button.expand {
background: color-mix(in oklab, var(--color-bg) 55%, transparent);
backdrop-filter: blur(8px);
color: var(--color-text-high);
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
transition:
transform 0.25s cubic-bezier(0.16, 1, 0.3, 1),
background-color 0.15s,
color 0.15s;
& svg {
width: var(--field-size-icon);
height: var(--field-size-icon);
}
&:hover {
&:hover,
&:focus-visible {
color: var(--color-text);
background: color-mix(in oklab, var(--color-bg) 78%, transparent);
}
@@ -338,12 +342,7 @@ button.expand {
& a {
color: inherit;
text-decoration: underline;
text-underline-offset: 2px;
&:hover {
color: var(--color-text-high);
}
}
}

View File

@@ -69,8 +69,13 @@ from sendou.ink's app/styles/vars.css.
text-decoration: none;
padding: var(--s-1) var(--s-2-5);
border-radius: var(--radius-field);
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}

View File

@@ -6,14 +6,10 @@ button.iconMenu {
height: var(--field-size-sm);
border-radius: var(--radius-field);
padding: 0;
--button-bg: var(--color-bg-higher);
border: var(--border-style);
background: var(--color-bg-higher);
color: var(--color-text);
&:hover {
color: var(--color-text-accent);
}
& > svg {
width: var(--field-size-icon);
height: var(--field-size-icon);

View File

@@ -61,8 +61,8 @@
button.vodDelete {
width: var(--field-size-sm);
padding: 0;
--button-bg: var(--color-error);
border-color: var(--color-error);
background: var(--color-error);
outline-color: var(--color-error);
}
@@ -73,6 +73,11 @@ button.vodDelete {
& summary {
cursor: pointer;
transition: color 0.15s;
&:hover {
color: var(--color-text);
}
}
& table {

View File

@@ -10,10 +10,6 @@
border-radius: 0;
font-size: var(--font-2xs);
font-weight: var(--weight-semi);
&:hover {
background-color: var(--color-bg-high);
}
}
.stripeTeam {

View File

@@ -108,10 +108,10 @@
font-weight: var(--weight-semi);
padding: 0;
text-align: left;
text-decoration: underline;
&:hover {
opacity: 0.8;
&:hover,
&:focus-visible {
text-decoration: underline;
}
}

View File

@@ -82,8 +82,8 @@
}
.extraInfoButton {
--button-bg: var(--color-bg);
font-size: var(--font-xs);
background-color: var(--color-bg);
border-radius: var(--radius-box);
padding: var(--s-0-5) var(--s-1-5);
width: max-content;
@@ -126,7 +126,8 @@
}
.popoverButton {
background-color: transparent;
--button-bg: transparent;
--button-hover-bg: var(--color-bg-higher);
color: var(--color-text-high);
font-size: var(--font-xs);
padding: 0;

View File

@@ -31,9 +31,11 @@
display: flex;
align-items: center;
gap: var(--s-3);
transition: background-color 0.2s;
text-decoration: none;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
}

View File

@@ -123,6 +123,7 @@
border: var(--border-style);
border-radius: var(--radius-full);
background-color: transparent;
transition: background-color 0.15s;
& img {
filter: grayscale(100%);
@@ -132,8 +133,9 @@
opacity 0.2s;
}
&:hover img {
opacity: 0.8;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {

View File

@@ -10,11 +10,16 @@
align-items: center;
gap: var(--s-1);
cursor: pointer;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-higher);
}
}
.emoji {
filter: grayscale(100%);
transition: all 0.2s;
transition: filter 0.2s;
}
.checked {
@@ -29,7 +34,3 @@
.focusVisible {
outline: var(--focus-ring);
}
.radio:hover .emoji {
scale: 1.1;
}

View File

@@ -7,6 +7,7 @@
}
.results {
text-decoration: none;
background-color: var(--color-bg-higher);
max-width: 32rem;
margin: 0 auto;

View File

@@ -43,6 +43,7 @@
}
.bskyLink {
text-decoration: none;
padding: var(--s-1);
border: 1px solid;
border-radius: 50%;

View File

@@ -7,14 +7,17 @@
.clickableItem {
min-height: 50px;
padding: 0;
padding: var(--s-0-5);
margin: calc(-1 * var(--s-0-5));
border: none;
border-radius: var(--radius-field);
background: transparent;
cursor: pointer;
transition: transform 0.1s;
transition: background-color 0.15s;
&:hover:not(:disabled) {
transform: scale(1.1);
&:hover:not(:disabled),
&:focus-visible {
background-color: var(--color-bg-high);
}
&:disabled {

View File

@@ -17,11 +17,17 @@
color: var(--color-text);
border-radius: var(--radius-field);
cursor: pointer;
transition: opacity 0.2s;
background-color: var(--tier-color);
transition: background-color 0.15s;
border: none;
&:hover {
opacity: 0.9;
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--tier-color) 85%,
var(--color-text)
);
}
}
@@ -57,7 +63,7 @@
border-radius: var(--radius-field) 0 0 var(--radius-field);
align-items: center;
align-content: center;
transition: background 0.2s;
transition: background-color 0.15s;
}
.targetZoneOver {
@@ -109,10 +115,11 @@
background: var(--color-bg-high);
border: none;
cursor: pointer;
transition: opacity 0.2s;
transition: background-color 0.15s;
&:hover:not(:disabled) {
opacity: 0.8;
&:hover:not(:disabled),
&:focus-visible {
background: var(--color-bg-higher);
}
&:disabled {
@@ -147,11 +154,11 @@
border-radius: 50%;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.2s;
transition: border-color 0.15s;
padding: 0;
&:hover {
transform: scale(1.1);
&:hover,
&:focus-visible {
border-color: var(--color-text-high);
}
}

View File

@@ -5,7 +5,7 @@ import {
} from "@dnd-kit/sortable";
import clsx from "clsx";
import { ChevronDown, ChevronUp, Plus, Trash } from "lucide-react";
import type { KeyboardEvent } from "react";
import type { CSSProperties, KeyboardEvent } from "react";
import { useLayoutEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { SendouButton } from "~/components/elements/Button";
@@ -89,9 +89,7 @@ export function TierRow({ tier }: TierRowProps) {
<button
type="button"
className={styles.tierLabel}
style={{
backgroundColor: tier.color,
}}
style={{ "--tier-color": tier.color } as CSSProperties}
>
<span
className={styles.tierName}

View File

@@ -86,11 +86,17 @@
font-size: var(--font-lg);
color: var(--color-text-high);
padding: var(--s-1);
border-radius: var(--radius-field);
touch-action: none;
user-select: none;
-webkit-user-select: none;
transition:
background-color 0.15s,
color 0.15s;
&:hover {
&:hover:not(:disabled),
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}

View File

@@ -87,12 +87,13 @@
gap: var(--s-1);
color: var(--color-text);
justify-content: center;
transition: background-color 0.2s;
text-decoration: none;
transition: background-color 0.15s;
}
a.match:hover {
background-color: var(--color-bg-high);
border-radius: var(--radius-field);
a.match:hover,
a.match:focus-visible {
background-color: var(--color-bg-higher);
}
.matchSeparator {

View File

@@ -35,9 +35,10 @@
font-size: var(--font-sm);
font-weight: var(--weight-semi);
cursor: pointer;
transition: background-color 0.2s ease;
transition: background-color 0.15s;
&:hover:not(:disabled):not(.roundButtonActive) {
&:hover:not(:disabled):not(.roundButtonActive),
&:focus-visible:not(.roundButtonActive) {
background-color: var(--color-bg-higher);
}

View File

@@ -161,10 +161,11 @@
align-items: center;
flex-shrink: 0;
border-radius: var(--radius-full);
transition: background-color 0.15s;
&:hover {
color: var(--color-error);
background-color: color-mix(in srgb, var(--color-error) 10%, transparent);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -5,6 +5,7 @@
}
.link {
text-decoration: none;
background-color: var(--color-bg-high);
padding: var(--s-2) var(--s-4);
border-radius: var(--radius-box);

View File

@@ -25,10 +25,10 @@
font-size: var(--font-2xs);
padding: 0;
text-align: left;
text-decoration: underline;
&:hover {
opacity: 0.8;
&:hover,
&:focus-visible {
text-decoration: underline;
}
}

View File

@@ -24,6 +24,7 @@
}
.eventInfo {
text-decoration: none;
display: flex;
align-items: center;
gap: var(--s-2);

View File

@@ -91,15 +91,17 @@
text-decoration: none;
cursor: pointer;
min-width: max-content;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
.linkActive {
color: var(--color-text-accent);
background-color: var(--color-bg-high);
background-color: var(--color-bg-higher);
}
.icon {
@@ -146,8 +148,10 @@
font-size: var(--font-sm);
font-weight: var(--weight-semi);
text-decoration: none;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -1,4 +1,5 @@
.standingsMatchResultSquare {
text-decoration: none;
width: 28px;
height: 28px;
display: grid;

View File

@@ -111,7 +111,7 @@ function ResultsTable({ standings }: { standings: ResultsStanding[] }) {
let rowDarkerBg = false;
return (
<Table noRowHover>
<Table>
<thead>
<tr>
<th>{t("tournament:results.column.standing")}</th>

View File

@@ -4,8 +4,11 @@
gap: var(--s-2);
padding: var(--s-1-5);
border-radius: var(--radius-field);
text-decoration: none;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -37,5 +37,6 @@
}
.friendLink {
text-decoration: none;
padding: var(--s-0-5) var(--s-1);
}

View File

@@ -30,14 +30,16 @@
background-color: var(--color-bg);
border: 2px solid var(--color-bg-higher);
color: var(--color-text);
transition: all 0.2s;
text-decoration: none;
transition: background-color 0.15s;
& svg {
min-width: 30px;
}
&:hover {
background-color: var(--color-bg-higher);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}

View File

@@ -5,6 +5,7 @@
}
.iconNavItem {
text-decoration: none;
display: flex;
align-items: center;
gap: var(--s-2);
@@ -17,11 +18,12 @@
color: var(--color-text);
font-size: var(--font-xs);
font-weight: var(--weight-semi);
transition: all 0.2s;
transition: background-color 0.15s;
cursor: pointer;
&:hover {
background-color: var(--color-bg-higher);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
&:focus-visible {

View File

@@ -46,13 +46,20 @@
}
.membership {
text-decoration: none;
display: flex;
align-items: center;
gap: var(--s-3);
color: var(--color-text);
margin-block-end: var(--s-1);
padding: var(--s-1) var(--s-1-5);
margin-block-start: calc(-1 * var(--s-1));
border-radius: var(--radius-field);
transition: background-color 0.2s;
transition: background-color 0.15s;
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
}
}
.membershipInfo {
@@ -183,10 +190,12 @@
font-size: var(--font-sm);
border-radius: var(--radius-field);
padding: var(--s-2);
transition: background-color 0.2s;
text-decoration: none;
transition: background-color 0.15s;
background-color: var(--color-bg-high);
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
}
@@ -280,6 +289,7 @@
}
.socialLinkIconContainer {
text-decoration: none;
background-color: var(--color-bg-higher);
display: grid;
place-items: center;
@@ -343,8 +353,11 @@
.friendLink {
padding: var(--s-0-5) var(--s-1);
border-radius: var(--radius-field);
text-decoration: none;
transition: background-color 0.15s;
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
}

View File

@@ -3,12 +3,14 @@
border-radius: var(--radius-box);
padding: var(--s-2) var(--s-3);
color: var(--color-text);
transition: ease-in 0.2s background-color;
text-decoration: none;
transition: background-color 0.15s;
display: flex;
flex-direction: column;
gap: var(--s-4);
&:hover {
&:hover,
&:focus-visible {
background-color: var(--color-bg-higher);
}
}

View File

@@ -79,6 +79,10 @@
text-decoration: none;
border-radius: var(--radius-field);
&:hover {
text-decoration: underline;
}
&:focus-visible {
outline: var(--focus-ring);
outline-offset: 1px;

View File

@@ -12,6 +12,7 @@
}
.changeLogIconButton {
text-decoration: none;
display: flex;
flex-direction: row;
gap: var(--s-1-5);
@@ -19,11 +20,18 @@
align-items: center;
font-weight: var(--weight-bold);
font-size: var(--font-xs);
border-radius: 100%;
padding: var(--s-0-5) var(--s-1-5);
margin: calc(-1 * var(--s-0-5)) calc(-1 * var(--s-1-5));
border-radius: var(--radius-field);
color: var(--color-text-high);
transition:
background-color 0.15s,
color 0.15s;
&:hover {
color: var(--color-text-accent);
&:hover,
&:focus-visible {
background-color: var(--color-bg-high);
color: var(--color-text);
}
}
@@ -54,8 +62,9 @@
position: relative;
color: var(--color-text);
border: var(--border-style-high);
transition: --l 0.2s ease-out;
transition: --l 0.15s;
margin-block-start: var(--s-6);
text-decoration: none;
&:hover {
--l: 75%;
@@ -93,11 +102,6 @@
& svg {
width: 24px;
transition: all 0.2s ease-out;
}
&:hover svg {
translate: 2px;
}
}
@@ -153,12 +157,18 @@
font-weight: var(--weight-bold);
text-align: center;
color: var(--color-text);
transition: background-color 0.2s ease-out;
text-decoration: none;
transition: background-color 0.15s;
min-width: 90px;
max-width: 90px;
&:hover {
background-color: var(--color-bg-high);
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}
@@ -222,7 +232,8 @@
position: relative;
color: var(--color-text);
overflow: hidden;
transition: --l 0.2s ease-out;
text-decoration: none;
transition: --l 0.15s;
&:hover {
--l: 75%;
@@ -307,9 +318,16 @@
flex-wrap: wrap;
font-size: var(--font-sm);
font-weight: var(--weight-semi);
text-decoration: none;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-high);
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
& svg {
@@ -337,16 +355,22 @@
}
.weaponPill {
text-decoration: none;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--color-bg-higher);
border-radius: var(--radius-full);
padding: var(--s-1);
transition: background-color 0.15s ease-out;
transition: background-color 0.15s;
&:hover {
background-color: var(--color-bg-high);
&:hover,
&:focus-visible {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}
@@ -370,6 +394,7 @@
background-color: var(--color-bg-higher);
display: grid;
place-items: center;
transition: background-color 0.15s;
}
.discoverGridItem {
@@ -383,7 +408,12 @@
font-weight: var(--weight-semi);
text-align: center;
&:hover .discoverGridItemImage {
background-color: var(--color-bg-high);
&:hover .discoverGridItemImage,
&:focus-visible .discoverGridItemImage {
background-color: color-mix(
in oklch,
var(--color-bg-higher) 85%,
var(--color-text)
);
}
}

View File

@@ -0,0 +1,8 @@
---
type: feature
---
Consistent hover feedback across the site
- Every button, link, tab, menu item and list row now highlights the same way when hovered or focused
- Buttons no longer scale, fade or blur on hover
- Plain text links underline on hover

19
docs/dev/styling.md Normal file
View File

@@ -0,0 +1,19 @@
# Styling
## Hover
- Every interactive element has hover feedback. Non-interactive elements have none.
- Hover feedback is a background change one step up the bg scale from the surface the element sits on: on `--color-bg`/`--color-bg-nav` use `--color-bg-high`, on `--color-bg-high` use `--color-bg-higher`.
- Transparent elements (nav links, icon buttons, list rows, menu items, outlined and minimal buttons) get that background on hover, clipped by their own `border-radius`.
- Filled elements (accent, success, error buttons and badges) keep their fill and mix 15% of `--color-text` into it: `color-mix(in oklch, var(--color-text-accent) 85%, var(--color-text))`. This moves the same direction as the bg scale in both themes.
- Muted text (`--color-text-high`) lifts to `--color-text` on hover. Text already at `--color-text` does not change color.
- Plain inline text links underline on hover; nothing else changes. Hover feedback is one or the other, never a background *and* an underline: the underline comes from a global `a:hover` rule, so every link class with a hover background declares `text-decoration: none`.
- Transition `background-color 0.15s` (add `color 0.15s` when the text lifts). No `all`, no other durations.
- `:focus-visible` gets the same background as hover plus `outline: var(--focus-ring)`.
- The selected/current state (`aria-current="page"`, `aria-selected`) is `--color-bg-higher` and bold, so it stays distinct from hover.
- Disabled and pending elements have no hover styles (`:hover:not(:disabled)`); their cursor is `not-allowed`.
- No `transform`, `scale`, `opacity`, `filter` or `box-shadow` on hover. `:active` may use `translateY(1px)`.
- Elements whose own fill is already `--color-bg-higher` (chips, pills, bg-higher cards) have no next step on the scale, so they use the same 15% text mix: `color-mix(in oklch, var(--color-bg-higher) 85%, var(--color-text))`.
- Tabs are the exception to the background step: hovering an unselected tab colours its indicator border `--color-border-high` and lifts the text, the selected tab keeps the accent indicator.
- Shared components (`SendouButton`, menus, tabs, selects) own their hover styles in their own module; feature CSS never adds or overrides hover on them.
- `SendouButton` derives its hover from its fill. A feature class that changes a button's fill sets `--button-bg` instead of `background`, so the hover follows (`--button-bg: var(--color-bg-higher)`); the transparent variants (`minimal`, `outlined`) already hover to `--color-bg-high` (`minimal` carries `--s-1` of horizontal padding so the background has room around the text), override with `--button-hover-bg` only when the button sits on a `--color-bg-high` surface. A `background` declaration in feature CSS wins over the shared hover through the cascade layers and leaves the button with no hover at all.