Files
TSSBOT-web/frontend/src/styles.css
T
FURRO404 a24decbbeb bye
2026-06-21 04:22:09 -07:00

1099 lines
23 KiB
CSS

@import "tailwindcss";
@theme {
--color-cerulean-50: #e5f9ff;
--color-cerulean-100: #ccf3ff;
--color-cerulean-200: #99e7ff;
--color-cerulean-300: #66dbff;
--color-cerulean-400: #33cfff;
--color-cerulean-500: #00c3ff;
--color-cerulean-600: #009ccc;
--color-cerulean-700: #007599;
--color-cerulean-800: #004e66;
--color-cerulean-900: #002733;
--color-cerulean-950: #001b24;
--color-tropical-teal-50: #e5feff;
--color-tropical-teal-100: #ccfcff;
--color-tropical-teal-200: #99faff;
--color-tropical-teal-300: #66f7ff;
--color-tropical-teal-400: #33f5ff;
--color-tropical-teal-500: #00f2ff;
--color-tropical-teal-600: #00c2cc;
--color-tropical-teal-700: #009199;
--color-tropical-teal-800: #006166;
--color-tropical-teal-900: #003033;
--color-tropical-teal-950: #002224;
--color-light-yellow-50: #fefde7;
--color-light-yellow-100: #fcfbcf;
--color-light-yellow-200: #f9f69f;
--color-light-yellow-300: #f7f26e;
--color-light-yellow-400: #f4ee3e;
--color-light-yellow-500: #f1e90e;
--color-light-yellow-600: #c1bb0b;
--color-light-yellow-700: #918c08;
--color-light-yellow-800: #605d06;
--color-light-yellow-900: #302f03;
--color-light-yellow-950: #222102;
--color-soft-apricot-50: #fff2e6;
--color-soft-apricot-100: #fee5cd;
--color-soft-apricot-200: #fdca9b;
--color-soft-apricot-300: #fdb068;
--color-soft-apricot-400: #fc9636;
--color-soft-apricot-500: #fb7b04;
--color-soft-apricot-600: #c96303;
--color-soft-apricot-700: #974a02;
--color-soft-apricot-800: #643102;
--color-soft-apricot-900: #321901;
--color-soft-apricot-950: #231101;
--color-vibrant-coral-50: #fde9e8;
--color-vibrant-coral-100: #fad3d1;
--color-vibrant-coral-200: #f6a8a2;
--color-vibrant-coral-300: #f17c74;
--color-vibrant-coral-400: #ed5145;
--color-vibrant-coral-500: #e82517;
--color-vibrant-coral-600: #ba1e12;
--color-vibrant-coral-700: #8b160e;
--color-vibrant-coral-800: #5d0f09;
--color-vibrant-coral-900: #2e0705;
--color-vibrant-coral-950: #200503;
--color-bg: #fefde7;
--color-surface: #fcfbcf;
--color-surface-alt: #f9f69f;
--color-fury-white: #fefde7;
--color-fury-ice: #fcfbcf;
--color-fury-blue: #f9f69f;
--color-fury-glow: #fdb068;
--color-fury-cyan: #e82517;
--color-fury-aqua: #ed5145;
--color-fury-violet: #fb7b04;
--color-text: #000000;
--color-text-soft: #555555;
--color-text-muted: #888888;
--color-border: #fee5cd;
--color-ring: #ed5145;
--color-shadow: rgba(232, 37, 23, 0.12);
--color-success: #00f2ff;
--color-warning: #f4ee3e;
--color-danger: #e82517;
--color-win: #1a9e4b;
--color-loss: #e82517;
}
:root[data-theme="dark"] {
--color-bg: #130d08;
--color-surface: #24170d;
--color-surface-alt: #34210f;
--color-fury-white: #18100a;
--color-fury-ice: #24170d;
--color-fury-blue: #34210f;
--color-fury-glow: #a86224;
--color-fury-cyan: #ff6a5f;
--color-fury-aqua: #ff8d84;
--color-fury-violet: #ffac4d;
--color-text: #fdb068;
--color-text-soft: #fff2e6;
--color-text-muted: #fee5cd;
--color-border: #68401f;
--color-ring: #ff8d84;
--color-shadow: rgba(255, 106, 95, 0.18);
--color-success: #58f0f5;
--color-warning: #f4ee3e;
--color-danger: #ff6a5f;
--color-win: #46d17e;
--color-loss: #ff6a5f;
color-scheme: dark;
}
:root[data-theme="light"] {
color-scheme: light;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@font-face {
font-family: "skyquakesymbols";
src: url("/fonts/symbols_skyquake.ttf") format("truetype");
font-display: swap;
}
/* War Thunder vehicle names carry country/event glyphs (▀ ▄ ◊ + PUA markers)
that only the skyquake symbol font renders; list it first, then fall back. */
.vehicle-name {
font-family:
"skyquakesymbols", "SF Pro Rounded", "SF Pro Text", -apple-system, BlinkMacSystemFont,
"Segoe UI", Inter, ui-sans-serif, system-ui, sans-serif;
}
.vehicle-dead {
opacity: 0.45;
color: var(--color-danger);
}
/* Chat/battle logs: monospace for column alignment, with skyquake before the
generic keyword so country/event glyphs still resolve per-character. */
.log-mono {
font-family:
ui-monospace, SFMono-Regular, Menlo, Consolas, "skyquakesymbols", monospace;
}
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
background: var(--color-bg);
font-family:
"SF Pro Rounded", "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Inter,
ui-sans-serif, system-ui, sans-serif;
}
h1,
h2,
h3 {
font-family:
"SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Inter,
ui-sans-serif, system-ui, sans-serif;
}
.pixel-mountains {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
}
.pixel-mountains canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
image-rendering: pixelated;
object-fit: cover;
object-position: center bottom;
transition: opacity 420ms ease;
}
.pixel-mountains-previous {
animation: pixelMountainsFadeOut 420ms ease forwards;
z-index: 1;
}
.pixel-mountains-active {
z-index: 0;
}
.pixel-sky {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 2;
}
.pixel-sun,
.pixel-moon-group {
position: absolute;
display: block;
transform: translate(-50%, -50%);
will-change: left, opacity, top, transform;
}
.pixel-sun,
.pixel-moon {
image-rendering: pixelated;
image-rendering: crisp-edges;
}
.pixel-sun {
left: 78%;
top: 18%;
width: 128px;
height: 128px;
color: var(--color-fury-glow);
--sprite-light: var(--color-soft-apricot-200);
--sprite-shine: var(--color-soft-apricot-50);
--sprite-shadow: var(--color-fury-violet);
}
.pixel-moon-group {
left: 78%;
top: 18%;
width: 136px;
height: 136px;
color: var(--color-border);
--sprite-light: var(--color-soft-apricot-50);
--sprite-mid: var(--color-fury-glow);
--sprite-shadow: var(--color-fury-violet);
--sprite-shine: #ffffff;
}
:root[data-theme="dark"] .pixel-moon-group {
color: #1f2749;
--sprite-light: #fff6df;
--sprite-mid: #8fb2d9;
--sprite-shadow: #5f83b1;
--sprite-shine: #ffffff;
}
.pixel-moon {
position: absolute;
left: 0;
top: 0;
width: 136px;
height: 136px;
transform: translate(-50%, -50%);
}
:root[data-theme="dark"] .pixel-sun {
color: var(--color-fury-violet);
--sprite-light: var(--color-fury-glow);
--sprite-shine: var(--color-soft-apricot-100);
--sprite-shadow: var(--color-fury-cyan);
}
.pixel-star {
position: absolute;
display: block;
width: 8px;
height: 8px;
background: var(--color-soft-apricot-100);
box-shadow: 12px 0 0 -4px var(--color-fury-glow), 0 12px 0 -4px var(--color-fury-glow);
}
.pixel-star-a {
right: -68px;
top: -32px;
}
.pixel-star-b {
left: -92px;
top: 22px;
}
.pixel-star-c {
right: -116px;
top: 54px;
}
.pixel-sky-light .pixel-sun,
.pixel-sky-dark .pixel-moon-group {
opacity: 1;
}
.pixel-sky-light .pixel-moon-group,
.pixel-sky-dark .pixel-sun {
opacity: 0;
}
.pixel-sky-light-to-dark .pixel-sun {
animation: celestialPathExit 980ms cubic-bezier(0.55, 0.085, 0.68, 0.53) forwards;
left: 0;
offset-anchor: center;
offset-path: var(--celestial-exit-path);
offset-rotate: 0deg;
top: 0;
transform: none;
}
.pixel-sky-light-to-dark .pixel-moon-group {
animation: celestialPathEnter 980ms cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
left: 0;
offset-anchor: center;
offset-path: var(--celestial-enter-path);
offset-rotate: 0deg;
top: 0;
transform: none;
}
.pixel-sky-dark-to-light .pixel-moon-group {
animation: celestialPathExit 980ms cubic-bezier(0.55, 0.085, 0.68, 0.53) forwards;
left: 0;
offset-anchor: center;
offset-path: var(--celestial-exit-path);
offset-rotate: 0deg;
top: 0;
transform: none;
}
.pixel-sky-dark-to-light .pixel-sun {
animation: celestialPathEnter 980ms cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
left: 0;
offset-anchor: center;
offset-path: var(--celestial-enter-path);
offset-rotate: 0deg;
top: 0;
transform: none;
}
:root[data-theme="dark"] .pixel-mountains {
opacity: 1;
}
.tree {
width: min(100%, 500px);
height: auto;
display: block;
background: var(--color-fury-white);
border: 3px solid var(--color-border);
border-radius: 16px;
padding: 12px;
box-shadow:
0 4px 24px rgba(253, 202, 155, 0.35),
0 1px 3px rgba(50, 25, 1, 0.08);
}
:root[data-theme="dark"] .apricot-button-text {
color: #fff2e6;
}
:root[data-theme="dark"] .tree {
filter: brightness(0.78) sepia(0.18) saturate(0.92);
box-shadow:
0 4px 24px rgba(255, 106, 95, 0.14),
0 1px 3px rgba(0, 0, 0, 0.35);
}
.theme-toggle-mover {
will-change: transform;
}
:root.theme-transition,
:root.theme-transition *,
:root.theme-transition *::before,
:root.theme-transition *::after {
transition-duration: 420ms;
transition-property: background-color, border-color, box-shadow, color, fill, opacity, stroke, text-decoration-color;
transition-timing-function: ease;
}
.falling-leaves {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 2;
}
.location-signal-map .leaflet-pane,
.location-signal-map .leaflet-top,
.location-signal-map .leaflet-bottom {
z-index: 0;
}
.location-signal-map .leaflet-control {
z-index: 1;
}
.replay-card {
overflow: hidden;
}
.replay-status {
display: flex;
min-height: 120px;
align-items: center;
justify-content: center;
border: 1px solid var(--color-border);
border-radius: 8px;
background: var(--color-surface);
color: var(--color-text-soft);
font-size: 0.9rem;
font-weight: 600;
}
.replay-status-error {
color: var(--color-danger);
}
.rc-mode-toggle {
display: none;
gap: 2px;
border: 1px solid var(--color-border);
border-radius: 6px;
background: var(--color-surface);
padding: 2px;
}
.rc-mode-toggle.visible {
display: inline-flex;
}
.rc-mode-btn {
border: 0;
border-radius: 4px;
background: transparent;
color: var(--color-text-soft);
cursor: pointer;
font: inherit;
font-size: 0.78rem;
font-weight: 700;
padding: 4px 14px;
transition: background-color 120ms ease, color 120ms ease;
}
.rc-mode-btn:hover {
color: var(--color-text);
}
.rc-mode-btn.active {
background: var(--color-fury-cyan);
color: var(--color-fury-white);
}
.rc-layout {
display: grid;
grid-template-columns: minmax(160px, 200px) min(720px, 60vh, 92vw) minmax(160px, 200px);
gap: 0.5rem;
align-items: start;
justify-content: center;
margin: 0 auto;
}
@media (max-width: 1120px) {
.rc-layout {
grid-template-columns: 1fr;
}
.rc-panel {
max-height: 200px;
}
}
.rc-panel {
overflow-y: auto;
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 8px;
background: #15100b;
color: #fff2e6;
font-size: 0.78rem;
}
.rc-panel-head {
position: sticky;
z-index: 1;
top: 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(21, 16, 11, 0.95);
padding: 0.5rem 0.6rem 0.4rem;
text-align: center;
}
.rc-panel-label {
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.rc-clan-tag {
font-family: "skyquakesymbols", monospace;
font-size: 0.85rem;
letter-spacing: 0;
text-transform: none;
}
.rc-panel-list {
padding: 0.25rem 0;
}
.rc-row {
display: flex;
align-items: center;
gap: 0.45rem;
border-left: 2px solid transparent;
cursor: pointer;
padding: 0.35rem 0.6rem;
transition: background-color 120ms ease, opacity 300ms ease;
}
.rc-row:hover,
.rc-row.rc-hl {
background: rgba(255, 255, 255, 0.06);
}
.rc-panel-win .rc-row.rc-hl {
border-left-color: rgba(0, 200, 0, 0.5);
}
.rc-panel-lose .rc-row.rc-hl {
border-left-color: rgba(220, 30, 30, 0.5);
}
.rc-row.rc-dead {
opacity: 0.4;
}
.rc-row.rc-gone {
cursor: default;
opacity: 0.2;
}
.rc-row.rc-dead:hover,
.rc-row.rc-gone:hover {
background: transparent;
}
.rc-type-icon {
width: 28px;
height: 22px;
flex-shrink: 0;
object-fit: contain;
opacity: 0.6;
}
.rc-row-info {
display: flex;
min-width: 0;
flex: 1;
flex-direction: column;
}
.rc-row-name {
overflow: hidden;
color: rgba(255, 255, 255, 0.86);
font-size: 0.76rem;
font-weight: 600;
text-overflow: ellipsis;
white-space: nowrap;
}
.rc-row-veh {
overflow: hidden;
color: rgba(255, 255, 255, 0.42);
font-size: 0.65rem;
text-overflow: ellipsis;
white-space: nowrap;
}
.rc-row-status {
width: 16px;
flex-shrink: 0;
color: rgba(255, 255, 255, 0.4);
font-size: 0.7rem;
font-weight: 800;
text-align: center;
}
.rc-center {
display: flex;
min-width: 0;
flex-direction: column;
align-items: center;
}
.rc-canvas {
width: 100%;
height: auto;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 8px;
background: #111;
cursor: crosshair;
}
.rc-tickets {
display: flex;
width: 100%;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
color: rgba(255, 255, 255, 0.8);
font-size: 0.7rem;
}
.rc-tk-val {
min-width: 2.6rem;
font-variant-numeric: tabular-nums;
font-weight: 700;
}
.rc-tk-val-win {
color: #5cdf5c;
text-align: right;
}
.rc-tk-val-lose {
color: #e85555;
text-align: left;
}
.rc-tk-track {
display: flex;
height: 10px;
flex: 1 1 auto;
overflow: hidden;
border-radius: 5px;
background: rgba(255, 255, 255, 0.1);
}
.rc-tk-fill {
height: 100%;
transition: width 100ms linear;
}
.rc-tk-fill-win {
background: #2a8f2a;
}
.rc-tk-fill-lose {
background: #b22020;
}
.rc-game-over .rc-tk-track {
animation: rcTkGlow 1.4s ease-in-out infinite;
}
.rc-game-over .rc-tk-val-win,
.rc-game-over .rc-panel-win .rc-panel-label {
animation: rcTkTextGlow 1.4s ease-in-out infinite;
}
@keyframes rcTkGlow {
0%,
100% {
box-shadow: 0 0 2px 0 rgba(92, 223, 92, 0.25);
}
50% {
box-shadow: 0 0 7px 1px rgba(92, 223, 92, 0.55);
}
}
@keyframes rcTkTextGlow {
0%,
100% {
text-shadow: 0 0 3px rgba(92, 223, 92, 0.35);
}
50% {
text-shadow: 0 0 9px rgba(92, 223, 92, 0.85);
}
}
.rc-controls {
display: flex;
width: 100%;
align-items: center;
gap: 0.4rem;
padding: 0.45rem 0;
}
.rc-btn {
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 4px;
background: rgba(255, 255, 255, 0.08);
color: rgba(255, 255, 255, 0.7);
cursor: pointer;
font: inherit;
font-size: 0.72rem;
font-weight: 700;
padding: 0.25rem 0.45rem;
transition: background-color 120ms ease, color 120ms ease;
}
.rc-btn:hover {
background: rgba(255, 255, 255, 0.14);
color: rgba(255, 255, 255, 0.9);
}
.rc-play {
min-width: 54px;
}
.rc-speeds {
display: flex;
gap: 1px;
}
.rc-sp.active {
border-color: rgba(255, 255, 255, 0.18);
background: rgba(255, 255, 255, 0.16);
color: #fff2e6;
}
.rc-scrub {
box-sizing: content-box;
height: 6px;
flex: 1;
padding: 6px 0;
border-radius: 3px;
appearance: none;
background: linear-gradient(to right, #2a6e2a var(--rc-progress, 0%), rgba(255, 255, 255, 0.14) var(--rc-progress, 0%));
background-clip: content-box;
cursor: pointer;
outline: none;
}
.rc-scrub::-webkit-slider-thumb {
width: 14px;
height: 14px;
border-radius: 50%;
-webkit-appearance: none;
appearance: none;
background: #90ee90;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
cursor: pointer;
}
.rc-scrub::-moz-range-thumb {
width: 14px;
height: 14px;
border: 0;
border-radius: 50%;
background: #90ee90;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
cursor: pointer;
}
.rc-time {
min-width: 65px;
color: rgba(255, 255, 255, 0.48);
font-size: 0.65rem;
font-variant-numeric: tabular-nums;
text-align: right;
white-space: nowrap;
}
.rc-log-wrap {
width: 100%;
margin-top: 0.4rem;
}
.rc-log {
overflow-y: auto;
max-height: 130px;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 8px;
background: rgba(255, 255, 255, 0.05);
padding: 0.6rem 0.8rem;
scrollbar-color: rgba(255, 255, 255, 0.14) transparent;
scrollbar-width: thin;
}
.rc-log:empty::after {
color: rgba(255, 255, 255, 0.22);
content: "Waiting for events...";
font-size: 0.7rem;
font-style: italic;
}
.rc-ev {
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
color: rgba(255, 255, 255, 0.74);
font-size: 0.72rem;
padding: 0.2rem 0;
}
.rc-ev:last-child {
border-bottom: 0;
}
.rc-ev-damage {
opacity: 0.6;
}
.rc-ev-time {
display: inline-block;
width: 32px;
margin-right: 0.4rem;
color: rgba(255, 255, 255, 0.34);
font-size: 0.65rem;
font-variant-numeric: tabular-nums;
}
.rc-ev-win {
color: #5cdf5c;
font-weight: 700;
}
.rc-ev-lose {
color: #e85555;
font-weight: 700;
}
.rc-ev-action {
color: rgba(255, 255, 255, 0.48);
font-size: 0.68rem;
}
.rc-ev-weapon {
margin-left: 0.3rem;
color: rgba(255, 255, 255, 0.34);
font-size: 0.62rem;
}
/* The bracket reads as a campaign map you drag around. The viewport breaks the
page's max-width so there's room to manoeuvre; the surface carries a faint
tactical grid that pans with the bracket (it lives on the scrolling content). */
/* The whole side (heading + canvas) breaks out to 85vw and centres on the
viewport, so the WINNER/LOSER heading aligns with the canvas's left edge. */
.bracket-side {
width: 85vw;
margin-left: calc(50% - 42.5vw);
}
.bracket-caret {
display: inline-block;
font-size: 1.35rem;
line-height: 1;
transition: transform 0.18s ease;
}
.bracket-caret.is-collapsed {
transform: rotate(-90deg);
}
.bracket-viewport {
position: relative;
width: 100%;
max-height: 78vh;
overflow: auto;
overscroll-behavior: contain;
cursor: grab;
border: 1px solid var(--color-border);
border-radius: 0.5rem;
background-color: color-mix(in srgb, var(--color-bg) 86%, #000);
}
.bracket-viewport.is-grabbing {
cursor: grabbing;
user-select: none;
}
/* While panning, don't let the drag turn into a text selection. */
.bracket-viewport.is-grabbing * {
user-select: none;
}
.tournament-bracket-grid {
position: relative;
display: flex;
gap: 2.6rem;
min-width: max-content;
padding: 3rem clamp(1.5rem, 5vw, 5rem);
--grid-line: color-mix(in srgb, var(--color-border) 38%, transparent);
--grid-dot: color-mix(in srgb, var(--color-fury-violet) 16%, transparent);
background-image:
linear-gradient(var(--grid-line) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-line) 1px, transparent 1px),
radial-gradient(var(--grid-dot) 1.5px, transparent 1.6px);
background-size: 116px 116px, 116px 116px, 116px 116px;
background-position: 0 0, 0 0, 58px 58px;
}
/* Connector layer: absolutely sized to the full bracket, drawn behind the cards.
Paths are measured from real node positions in App.jsx, so they stay correct
with hidden byes and irregular loser-bracket round widths. */
.tournament-bracket-lines {
position: absolute;
top: 0;
left: 0;
z-index: 0;
overflow: visible;
pointer-events: none;
}
/* Each connector is two stacked strokes: a steady base rail plus a brighter
dashed tracer that flows toward the winner (left → right, the path's own
direction). */
.tournament-bracket-lines path {
fill: none;
stroke-linecap: round;
}
.bracket-line-base {
stroke: color-mix(in srgb, var(--color-border) 55%, var(--color-fury-violet));
stroke-width: 1.5px;
}
.bracket-line-flow {
stroke: color-mix(in srgb, var(--color-fury-violet) 92%, white);
stroke-width: 1.5px;
stroke-dasharray: 7 17;
opacity: 0.7;
animation: bracketFlow 1.4s linear infinite;
}
@keyframes bracketFlow {
to {
stroke-dashoffset: -24;
}
}
/* Bye stub: a short rail + tag on the incoming side of a match whose feeders
were all byes, so a top-seed match doesn't read as "appearing from nowhere". */
.bracket-bye-stub {
stroke: color-mix(in srgb, var(--color-text-muted) 60%, transparent);
stroke-width: 1.5px;
stroke-dasharray: 3 4;
}
.bracket-bye-hover {
cursor: help;
pointer-events: all;
}
.bracket-bye-hit {
stroke: transparent;
stroke-width: 18px;
}
.bracket-bye-tag {
fill: var(--color-text-muted);
font-size: 9px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
}
.tournament-round-column {
position: relative;
z-index: 1;
display: flex;
width: 200px;
min-width: 200px;
flex-direction: column;
}
/* Matches are positioned absolutely (computeBracketLayout in App.jsx) so each one
sits centred between the matches that feed it. Height is supplied inline from
the computed layout; before that first measurement it falls back to a min. */
.tournament-round-track {
position: relative;
min-height: 120px;
}
.tournament-match-node {
position: absolute;
z-index: 1;
left: 0;
right: 0;
transition: opacity 0.18s ease;
}
/* Hover a team → its whole run lights up; everything else recedes. */
.tournament-bracket-grid.has-trace .tournament-match-node:not(.is-traced):not(.is-traced-loss) {
opacity: 0.32;
}
.tournament-match-node.is-traced > * {
position: relative;
box-shadow: 0 0 0 1.5px var(--color-win), 0 0 18px -2px color-mix(in srgb, var(--color-win) 70%, transparent);
animation: bracketBreathe 1.6s ease-in-out infinite;
}
@keyframes bracketBreathe {
0%, 100% {
box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--color-win) 70%, transparent), 0 0 14px -4px color-mix(in srgb, var(--color-win) 55%, transparent);
}
50% {
box-shadow: 0 0 0 2px var(--color-win), 0 0 26px 0 color-mix(in srgb, var(--color-win) 75%, transparent);
}
}
.bracket-line-base.is-traced {
stroke: var(--color-win);
stroke-width: 2px;
}
.bracket-line-flow.is-traced {
stroke: color-mix(in srgb, var(--color-win) 75%, white);
opacity: 0.95;
}
/* Loser run: same treatment in the loss colour. */
.tournament-match-node.is-traced-loss > * {
position: relative;
animation: bracketBreatheLoss 1.6s ease-in-out infinite;
}
@keyframes bracketBreatheLoss {
0%, 100% {
box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--color-loss) 70%, transparent), 0 0 14px -4px color-mix(in srgb, var(--color-loss) 55%, transparent);
}
50% {
box-shadow: 0 0 0 2px var(--color-loss), 0 0 26px 0 color-mix(in srgb, var(--color-loss) 75%, transparent);
}
}
.bracket-line-base.is-traced-loss {
stroke: var(--color-loss);
stroke-width: 2px;
}
.bracket-line-flow.is-traced-loss {
stroke: color-mix(in srgb, var(--color-loss) 75%, white);
opacity: 0.95;
}
.tournament-bracket-grid.has-trace .tournament-bracket-lines path:not(.is-traced):not(.is-traced-loss) {
opacity: 0.18;
}
@media (prefers-reduced-motion: reduce) {
.bracket-line-flow,
.tournament-match-node.is-traced > *,
.tournament-match-node.is-traced-loss > * {
animation: none;
}
}
@keyframes scrollPulse {
0% {
transform: translateY(-100%);
opacity: 0;
}
35% {
opacity: 1;
}
100% {
transform: translateY(250%);
opacity: 0;
}
}
@keyframes pixelMountainsFadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes celestialPathExit {
0% {
offset-distance: 0%;
opacity: 1;
}
100% {
offset-distance: 100%;
opacity: 0;
}
}
@keyframes celestialPathEnter {
0% {
offset-distance: 0%;
opacity: 0;
}
100% {
offset-distance: 100%;
opacity: 1;
}
}