moved all of the css to global because why not

This commit is contained in:
2026-05-28 16:54:35 +01:00
parent cce45fc57e
commit 99a29cc92b
4 changed files with 751 additions and 338 deletions

View File

@@ -26,7 +26,6 @@
eventEndpoint = new EventSource('/api/registeredEvents'); eventEndpoint = new EventSource('/api/registeredEvents');
eventEndpoint.onmessage = (e) => { eventEndpoint.onmessage = (e) => {
eventTable = JSON.parse(e.data); eventTable = JSON.parse(e.data);
console.log(eventTable);
}; };
}); });
@@ -172,6 +171,10 @@
<div class="bracket-sep" aria-hidden="true"></div> <div class="bracket-sep" aria-hidden="true"></div>
{/if} {/if}
<div class="bracket-row"> <div class="bracket-row">
<div class="brackets-name flex items-center">
<span class="brackets-name-text align-text-middle">{bracket.name}</span>
<div class="bracket-vertical-sep"></div>
</div>
{#each bracket.items as player} {#each bracket.items as player}
<div class="player-box" style="--c:{player.teamColor}"> <div class="player-box" style="--c:{player.teamColor}">
<div class="player-ghost" aria-hidden="true"> <div class="player-ghost" aria-hidden="true">
@@ -209,337 +212,354 @@
</section> </section>
</div> </div>
<style> <!-- <style> -->
@import url('https://fonts.googleapis.com/css2?family=Black+Ops+One&display=swap'); <!-- @import url('https://fonts.googleapis.com/css2?family=Black+Ops+One&display=swap'); -->
<!---->
:global(html), <!-- :global(html), -->
:global(body) { <!-- :global(body) { -->
min-height: 100vh; <!-- min-height: 100vh; -->
} <!-- } -->
<!---->
:global(body > div), /* SvelteKit's root wrapper */ <!-- :global(body > div), /* SvelteKit's root wrapper */ -->
:global(#svelte) { <!-- :global(#svelte) { -->
min-height: 100vh; <!-- min-height: 100vh; -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- flex-direction: column; -->
} <!-- } -->
<!---->
.page { <!-- .page { -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- flex-direction: column; -->
max-height: 150vh; <!-- max-height: 150vh; -->
max-width: 1000px; <!-- max-width: 1000px; -->
margin: 0 auto; <!-- margin: 0 auto; -->
width: 100%; <!-- width: 100%; -->
} <!-- } -->
.goldman { <!-- .goldman { -->
font-family: 'Black Ops One', system-ui; <!-- font-family: 'Black Ops One', system-ui; -->
font-weight: 400; <!-- font-weight: 400; -->
} <!-- } -->
<!---->
/* ── Leaderboard ── */ <!-- /* ── Leaderboard ── */ -->
.leaderboard { <!-- .leaderboard { -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- flex-direction: column; -->
gap: 10px; <!-- gap: 10px; -->
padding: 14px 14px 6px; <!-- padding: 14px 14px 6px; -->
} <!-- } -->
<!---->
.score-box { <!-- .score-box { -->
position: relative; <!-- position: relative; -->
overflow: hidden; <!-- overflow: hidden; -->
border-radius: 14px; <!-- border-radius: 14px; -->
border: 2px solid var(--c); <!-- border: 2px solid var(--c); -->
color: var(--c); <!-- color: var(--c); -->
background: color-mix(in srgb, var(--c) 10%, transparent); <!-- background: color-mix(in srgb, var(--c) 10%, transparent); -->
/* Grid stacking: ghost + fg share the same cell */ <!-- /* Grid stacking: ghost + fg share the same cell */ -->
display: grid; <!-- display: grid; -->
grid-template-columns: 1fr; <!-- grid-template-columns: 1fr; -->
grid-template-rows: 1fr; <!-- grid-template-rows: 1fr; -->
text-decoration: none; <!-- text-decoration: none; -->
transition: filter 0.15s ease; <!-- transition: filter 0.15s ease; -->
} <!-- } -->
.score-box:hover { <!-- .score-box:hover { -->
filter: brightness(1.15); <!-- filter: brightness(1.15); -->
} <!-- } -->
.score-box > * { <!-- .score-box > * { -->
grid-column: 1; <!-- grid-column: 1; -->
grid-row: 1; <!-- grid-row: 1; -->
} <!-- } -->
<!---->
.winner { <!-- .winner { -->
aspect-ratio: 2 / 1; <!-- aspect-ratio: 2 / 1; -->
border-width: 3px; <!-- border-width: 3px; -->
min-height: 80px; <!-- min-height: 80px; -->
} <!-- } -->
.runner { <!-- .runner { -->
aspect-ratio: 4 / 1; <!-- aspect-ratio: 4 / 1; -->
min-height: 56px; <!-- min-height: 56px; -->
} <!-- } -->
<!---->
/* Ghost SVG: fill the cell edge-to-edge, text flush to bottom */ <!-- /* Ghost SVG: fill the cell edge-to-edge, text flush to bottom */ -->
.score-ghost { <!-- .score-ghost { -->
width: 100%; <!-- width: 100%; -->
height: 100%; <!-- height: 100%; -->
opacity: 0.18; <!-- opacity: 0.18; -->
fill: currentColor; <!-- fill: currentColor; -->
} <!-- } -->
.ghost-svg { <!-- .ghost-svg { -->
width: 100%; <!-- width: 100%; -->
height: 100%; <!-- height: 100%; -->
display: block; <!-- display: block; -->
} <!-- } -->
<!---->
/* Foreground */ <!-- /* Foreground */ -->
.score-fg { <!-- .score-fg { -->
position: relative; <!-- position: relative; -->
z-index: 1; <!-- z-index: 1; -->
display: flex; <!-- display: flex; -->
align-items: center; <!-- align-items: center; -->
justify-content: space-between; <!-- justify-content: space-between; -->
padding: 0 14px; <!-- padding: 0 14px; -->
gap: 8px; <!-- gap: 8px; -->
} <!-- } -->
.score-meta { <!-- .score-meta { -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- flex-direction: column; -->
min-width: 0; <!-- min-width: 0; -->
flex: 1; <!-- flex: 1; -->
} <!-- } -->
.score-rank { <!-- .score-rank { -->
font-size: 10px; <!-- font-size: 10px; -->
letter-spacing: 1.5px; <!-- letter-spacing: 1.5px; -->
text-transform: uppercase; <!-- text-transform: uppercase; -->
opacity: 0.5; <!-- opacity: 0.5; -->
line-height: 1; <!-- line-height: 1; -->
margin-bottom: 3px; <!-- margin-bottom: 3px; -->
} <!-- } -->
.score-name { <!-- .score-name { -->
font-size: clamp(11px, 3vw, 20px); <!-- font-size: clamp(11px, 3vw, 20px); -->
white-space: nowrap; <!-- white-space: nowrap; -->
overflow: hidden; <!-- overflow: hidden; -->
text-overflow: ellipsis; <!-- text-overflow: ellipsis; -->
} <!-- } -->
.score-pts { <!-- .score-pts { -->
font-size: clamp(20px, 5.5vw, 40px); <!-- font-size: clamp(20px, 5.5vw, 40px); -->
letter-spacing: 2px; <!-- letter-spacing: 2px; -->
flex-shrink: 0; <!-- flex-shrink: 0; -->
} <!-- } -->
.winner .score-name { <!-- .winner .score-name { -->
font-size: clamp(16px, 5vw, 32px); <!-- font-size: clamp(16px, 5vw, 32px); -->
} <!-- } -->
.winner .score-pts { <!-- .winner .score-pts { -->
font-size: clamp(26px, 7.5vw, 52px); <!-- font-size: clamp(26px, 7.5vw, 52px); -->
} <!-- } -->
<!---->
/* <!-- /* -->
* Runners-up grid: <!-- * Runners-up grid: -->
* - 1 column on small screens (<480px) <!-- * - 1 column on small screens (<480px) -->
* - 2 columns on medium (480699px) <!-- * - 2 columns on medium (480699px) -->
* - 4 columns on large (≥700px), max 5 <!-- * - 4 columns on large (≥700px), max 5 -->
* --runner-count drives the actual column count on large screens <!-- * --runner-count drives the actual column count on large screens -->
* so fewer than 5 teams still fill the whole row. <!-- * so fewer than 5 teams still fill the whole row. -->
*/ <!-- */ -->
.runners-grid { <!-- .runners-grid { -->
display: grid; <!-- display: grid; -->
gap: 10px; <!-- gap: 10px; -->
grid-template-columns: 1fr; <!-- grid-template-columns: 1fr; -->
} <!-- } -->
@media (min-width: 480px) { <!-- @media (min-width: 480px) { -->
.runners-grid { <!-- .runners-grid { -->
grid-template-columns: repeat(2, 1fr); <!-- grid-template-columns: repeat(2, 1fr); -->
} <!-- } -->
<!---->
.winner { <!-- .winner { -->
aspect-ratio: 2 / 1; <!-- aspect-ratio: 2 / 1; -->
} <!-- } -->
<!---->
.runner { <!-- .runner { -->
aspect-ratio: 2 / 1; <!-- aspect-ratio: 2 / 1; -->
} <!-- } -->
} <!-- } -->
@media (min-width: 700px) { <!-- @media (min-width: 700px) { -->
.runners-grid { <!-- .runners-grid { -->
/* clamp actual count to 4 on large, but use --runner-count <!-- /* clamp actual count to 4 on large, but use --runner-count -->
so e.g. 2 teams still fill 2 equal columns not 2 of 4 */ <!-- so e.g. 2 teams still fill 2 equal columns not 2 of 4 */ -->
grid-template-columns: repeat(min(var(--runner-count), 4), 1fr); <!-- grid-template-columns: repeat(min(var(--runner-count), 4), 1fr); -->
} <!-- } -->
.winner { <!-- .winner { -->
aspect-ratio: 3 / 1; <!-- aspect-ratio: 3 / 1; -->
} <!-- } -->
.runner { <!-- .runner { -->
aspect-ratio: 3 / 2; <!-- aspect-ratio: 3 / 2; -->
} <!-- } -->
} <!-- } -->
<!---->
/* ── Section label ── */ <!-- /* ── Section label ── */ -->
.section-label { <!-- .section-label { -->
font-size: 10px; <!-- font-size: 10px; -->
letter-spacing: 2.5px; <!-- letter-spacing: 2.5px; -->
text-transform: uppercase; <!-- text-transform: uppercase; -->
opacity: 0.4; <!-- opacity: 0.4; -->
padding: 12px 16px 4px; <!-- padding: 12px 16px 4px; -->
margin: 0; <!-- margin: 0; -->
} <!-- } -->
<!---->
/* ── Events scrollable container ── */ <!-- /* ── Events scrollable container ── */ -->
.events-scroll { <!-- .events-scroll { -->
flex: 1; <!-- flex: 1; -->
overflow-y: auto; <!-- overflow-y: auto; -->
/* max-height: 900px; */ <!-- /* max-height: 900px; */ -->
min-height: 0; <!-- min-height: 0; -->
padding: 0 14px 24px; <!-- padding: 0 14px 24px; -->
/* Thin custom scrollbar */ <!-- /* Thin custom scrollbar */ -->
scrollbar-width: thin; <!-- scrollbar-width: thin; -->
scrollbar-color: color-mix(in srgb, currentColor 30%, transparent) transparent; <!-- scrollbar-color: color-mix(in srgb, currentColor 30%, transparent) transparent; -->
} <!-- } -->
.events { <!-- .events { -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- flex-direction: column; -->
gap: 10px; <!-- gap: 10px; -->
} <!-- } -->
<!---->
/* ── Event card ── */ <!-- /* ── Event card ── */ -->
.event-card { <!-- .event-card { -->
border-radius: 12px; <!-- border-radius: 12px; -->
border: 1px solid color-mix(in srgb, currentColor 18%, transparent); <!-- border: 1px solid color-mix(in srgb, currentColor 18%, transparent); -->
overflow: hidden; <!-- overflow: hidden; -->
transition: box-shadow 0.3s ease; <!-- transition: box-shadow 0.3s ease; -->
} <!-- } -->
/* Focus highlight pulse — added/removed by $effect */ <!-- /* Focus highlight pulse — added/removed by $effect */ -->
.event-card.highlight-pulse { <!-- .event-card.highlight-pulse { -->
animation: card-pulse 1.2s ease-out forwards; <!-- animation: card-pulse 1.2s ease-out forwards; -->
} <!-- } -->
@keyframes card-pulse { <!-- @keyframes card-pulse { -->
0% { <!-- 0% { -->
box-shadow: 0 0 0 3px currentColor; <!-- box-shadow: 0 0 0 3px currentColor; -->
} <!-- } -->
100% { <!-- 100% { -->
box-shadow: 0 0 0 0px currentColor; <!-- box-shadow: 0 0 0 0px currentColor; -->
} <!-- } -->
} <!-- } -->
<!---->
.event-header { <!-- .event-header { -->
display: flex; <!-- display: flex; -->
align-items: baseline; <!-- align-items: baseline; -->
gap: 10px; <!-- gap: 10px; -->
padding: 9px 13px 7px; <!-- padding: 9px 13px 7px; -->
border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent); <!-- border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent); -->
flex-wrap: wrap; <!-- flex-wrap: wrap; -->
} <!-- } -->
.event-name { <!-- .event-name { -->
font-size: 15px; <!-- font-size: 15px; -->
text-decoration: none; <!-- text-decoration: none; -->
color: inherit; <!-- color: inherit; -->
} <!-- } -->
.event-name:hover { <!-- .event-name:hover { -->
text-decoration: underline; <!-- text-decoration: underline; -->
} <!-- } -->
.event-division { <!-- .event-division { -->
font-size: 10px; <!-- font-size: 10px; -->
letter-spacing: 1.2px; <!-- letter-spacing: 1.2px; -->
text-transform: uppercase; <!-- text-transform: uppercase; -->
opacity: 0.4; <!-- opacity: 0.4; -->
} <!-- } -->
<!---->
/* ── Brackets ── */ <!-- /* ── Brackets ── */ -->
.brackets { <!-- .brackets { -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- flex-direction: column; -->
} <!-- } -->
.bracket-sep { <!-- .brackets-name { -->
height: 1px; <!-- font-size: 20px; -->
background: color-mix(in srgb, currentColor 10%, transparent); <!-- letter-spacing: 1.2px; -->
margin: 0 10px; <!-- text-transform: uppercase; -->
} <!-- opacity: 0.4; -->
.bracket-row { <!-- margin-left: 1px; -->
display: flex; <!-- } -->
gap: 6px; <!-- .brackets-name-text { -->
padding: 7px 9px; <!-- display: table-cell; -->
flex-wrap: wrap; <!-- vertical-align: middle; -->
} <!-- } -->
<!-- .bracket-vertical-sep { -->
/* ── Player boxes ── */ <!-- width: 1px; -->
.player-box { <!-- height: 100%; -->
flex: 1 1 0; /* equal widths, no min-content bias */ <!-- background: var(--ctp-mocha-surface2); -->
max-width: 160px; <!-- margin: 10px 5px; -->
position: relative; <!-- } -->
overflow: hidden; <!-- .bracket-sep { -->
border-radius: 8px; <!-- height: 1px; -->
border: 1.5px solid var(--c); <!-- background: color-mix(in srgb, currentColor 10%, transparent); -->
color: var(--c); <!-- margin: 0 10px; -->
background: color-mix(in srgb, var(--c) 10%, transparent); <!-- } -->
padding: 5px 7px 5px; <!-- .bracket-row { -->
display: flex; <!-- display: flex; -->
flex-direction: column; <!-- gap: 6px; -->
min-height: 52px; <!-- padding: 7px 9px; -->
} <!-- flex-wrap: wrap; -->
<!-- } -->
/* 1 col on small screens, 4 across on large */ <!---->
@media (max-width: 479px) { <!-- /* ── Player boxes ── */ -->
.bracket-row { <!-- .player-box { -->
flex-direction: column; <!-- flex: 1 1 0; /* equal widths, no min-content bias */ -->
} <!-- max-width: 160px; -->
.player-box { <!-- position: relative; -->
max-width: 100%; <!-- overflow: hidden; -->
} <!-- border-radius: 8px; -->
} <!-- border: 1.5px solid var(--c); -->
@media (min-width: 700px) { <!-- color: var(--c); -->
.player-box { <!-- background: color-mix(in srgb, var(--c) 10%, transparent); -->
max-width: calc(25% - 6px); <!-- padding: 5px 7px 5px; -->
} /* 4 per row */ <!-- display: flex; -->
} <!-- flex-direction: column; -->
<!-- min-height: 52px; -->
.player-ghost { <!-- } -->
position: absolute; <!---->
inset: 0; <!-- /* 1 col on small screens, 4 across on large */ -->
opacity: 0.15; <!-- @media (max-width: 479px) { -->
fill: currentColor; <!-- .bracket-row { -->
pointer-events: none; <!-- flex-direction: column; -->
} <!-- } -->
.ghost-svg { <!-- .player-box { -->
width: 100%; <!-- max-width: 100%; -->
height: 100%; <!-- } -->
display: block; <!-- } -->
} <!-- @media (min-width: 700px) { -->
<!-- .player-box { -->
.player-name-wrap { <!-- max-width: calc(25% - 6px); -->
position: relative; <!-- } /* 4 per row */ -->
z-index: 1; <!-- } -->
overflow: hidden; <!---->
white-space: nowrap; <!-- .player-ghost { -->
} <!-- position: absolute; -->
.marquee-inner { <!-- inset: 0; -->
display: inline-block; <!-- opacity: 0.15; -->
font-size: 11px; <!-- fill: currentColor; -->
font-weight: 600; <!-- pointer-events: none; -->
white-space: nowrap; <!-- } -->
} <!-- .ghost-svg { -->
.marquee-inner.scrolling { <!-- width: 100%; -->
animation: marquee-scroll 7s ease-in-out infinite; <!-- height: 100%; -->
} <!-- display: block; -->
@keyframes marquee-scroll { <!-- } -->
0%, <!---->
20% { <!-- .player-name-wrap { -->
transform: translateX(0); <!-- position: relative; -->
} <!-- z-index: 1; -->
70%, <!-- overflow: hidden; -->
90% { <!-- white-space: nowrap; -->
transform: translateX(var(--scroll-dist, 0px)); <!-- } -->
} <!-- .marquee-inner { -->
100% { <!-- display: inline-block; -->
transform: translateX(0); <!-- font-size: 11px; -->
} <!-- font-weight: 600; -->
} <!-- white-space: nowrap; -->
<!-- } -->
.player-placement { <!-- .marquee-inner.scrolling { -->
position: relative; <!-- animation: marquee-scroll 7s ease-in-out infinite; -->
z-index: 1; <!-- } -->
font-size: 17px; <!-- @keyframes marquee-scroll { -->
line-height: 1.1; <!-- 0%, -->
margin-top: 2px; <!-- 20% { -->
} <!-- transform: translateX(0); -->
.player-placement-gap { <!-- } -->
height: 20px; <!-- 70%, -->
} <!-- 90% { -->
</style> <!-- transform: translateX(var(--scroll-dist, 0px)); -->
<!-- } -->
<!-- 100% { -->
<!-- transform: translateX(0); -->
<!-- } -->
<!-- } -->
<!---->
<!-- .player-placement { -->
<!-- position: relative; -->
<!-- z-index: 1; -->
<!-- font-size: 17px; -->
<!-- line-height: 1.1; -->
<!-- margin-top: 2px; -->
<!-- } -->
<!-- .player-placement-gap { -->
<!-- height: 20px; -->
<!-- } -->
<!-- </style> -->

View File

@@ -9,7 +9,6 @@ export async function GET() {
let eventList = async () => { let eventList = async () => {
// Get eventList with structure from database // Get eventList with structure from database
let newEventList = await getRegisteredEventsWithPlayers(); let newEventList = await getRegisteredEventsWithPlayers();
console.log(newEventList);
// send to client // send to client
enqueue(newEventList); enqueue(newEventList);
}; };

View File

@@ -3,6 +3,30 @@
import type { PageProps } from './$types'; import type { PageProps } from './$types';
let { params }: PageProps = $props(); let { params }: PageProps = $props();
function ordinal(n: number) {
const s = ['th', 'st', 'nd', 'rd'];
const v = n % 100;
return n + (s[(v - 20) % 10] ?? s[v] ?? s[0]);
}
function marquee(node: HTMLElement) {
function measure() {
const inner = node.querySelector<HTMLElement>('.marquee-inner');
if (!inner) return;
const overflow = inner.scrollWidth - node.clientWidth;
if (overflow > 2) {
node.style.setProperty('--scroll-dist', `-${overflow + 6}px`);
inner.classList.add('scrolling');
} else {
inner.classList.remove('scrolling');
}
}
measure();
const ro = new ResizeObserver(measure);
ro.observe(node);
return { destroy: () => ro.disconnect() };
}
let eventId = params.eventId; let eventId = params.eventId;
let eventEndpoint: EventSource; let eventEndpoint: EventSource;
@@ -40,8 +64,45 @@
<div class="w-full flex-col px-[5vw] text-center"> <div class="w-full flex-col px-[5vw] text-center">
{console.log(event)} {console.log(event)}
<div class="align-text-middle h-10 w-full bg-red-500">{event.name} - {event.division}</div> <div class="align-text-middle h-10 w-full bg-red-500">{event.name} - {event.division}</div>
{#each event.registeredPlayers as division} div
<div>{division.name}</div> {#each event.registeredPlayers as bracket, bi}
{#if bi > 0}
<div class="bracket-sep" aria-hidden="true"></div>
{/if}
<div class="bracket-row">
<div class="brackets-name flex items-center">
<span class="brackets-name-text align-text-middle">{bracket.name}</span>
<div class="bracket-vertical-sep"></div>
</div>
{#each bracket.items as player}
<div class="player-box" style="--c:{player.teamColor}">
<div class="player-ghost" aria-hidden="true">
<svg viewBox="0 0.1 100 0.6" preserveAspectRatio="none" class="ghost-svg">
<text
x="0"
y="0.7"
font-size="1"
dominant-baseline="auto"
textLength="100"
lengthAdjust="spacingAndGlyphs"
font-family="'Black Ops One',system-ui">{player.firstName}</text
>
</svg>
</div>
<div class="player-name-wrap" use:marquee>
<span class="marquee-inner">
{player.firstName}
{player.lastName}
</span>
</div>
{#if player.placement !== 0}
<div class="player-placement goldman">{ordinal(player.placement)}</div>
{:else}
<div class="player-placement-gap"></div>
{/if}
</div>
{/each}
</div>
{/each} {/each}
</div> </div>
</div> </div>

View File

@@ -1,5 +1,338 @@
@import url('https://cdn.jsdelivr.net/npm/@catppuccin/palette/css/catppuccin.css'); @import url('https://cdn.jsdelivr.net/npm/@catppuccin/palette/css/catppuccin.css');
@import url('https://fonts.googleapis.com/css2?family=Black+Ops+One&display=swap');
@import 'tailwindcss'; @import 'tailwindcss';
@import '@catppuccin/tailwindcss/mocha.css'; @import '@catppuccin/tailwindcss/mocha.css';
@plugin '@tailwindcss/forms'; @plugin '@tailwindcss/forms';
@plugin '@tailwindcss/typography'; @plugin '@tailwindcss/typography';
:global(html),
:global(body) {
min-height: 100vh;
}
:global(body > div), /* SvelteKit's root wrapper */
:global(#svelte) {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.page {
display: flex;
flex-direction: column;
max-height: 150vh;
max-width: 1000px;
margin: 0 auto;
width: 100%;
}
.goldman {
font-family: 'Black Ops One', system-ui;
font-weight: 400;
}
/* ── Leaderboard ── */
.leaderboard {
display: flex;
flex-direction: column;
gap: 10px;
padding: 14px 14px 6px;
}
.score-box {
position: relative;
overflow: hidden;
border-radius: 14px;
border: 2px solid var(--c);
color: var(--c);
background: color-mix(in srgb, var(--c) 10%, transparent);
/* Grid stacking: ghost + fg share the same cell */
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
text-decoration: none;
transition: filter 0.15s ease;
}
.score-box:hover {
filter: brightness(1.15);
}
.score-box > * {
grid-column: 1;
grid-row: 1;
}
.winner {
aspect-ratio: 2 / 1;
border-width: 3px;
min-height: 80px;
}
.runner {
aspect-ratio: 4 / 1;
min-height: 56px;
}
/* Ghost SVG: fill the cell edge-to-edge, text flush to bottom */
.score-ghost {
width: 100%;
height: 100%;
opacity: 0.18;
fill: currentColor;
}
.ghost-svg {
width: 100%;
height: 100%;
display: block;
}
/* Foreground */
.score-fg {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 14px;
gap: 8px;
}
.score-meta {
display: flex;
flex-direction: column;
min-width: 0;
flex: 1;
}
.score-rank {
font-size: 10px;
letter-spacing: 1.5px;
text-transform: uppercase;
opacity: 0.5;
line-height: 1;
margin-bottom: 3px;
}
.score-name {
font-size: clamp(11px, 3vw, 20px);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.score-pts {
font-size: clamp(20px, 5.5vw, 40px);
letter-spacing: 2px;
flex-shrink: 0;
}
.winner .score-name {
font-size: clamp(16px, 5vw, 32px);
}
.winner .score-pts {
font-size: clamp(26px, 7.5vw, 52px);
}
/*
* Runners-up grid:
* - 1 column on small screens (<480px)
* - 2 columns on medium (480699px)
* - 4 columns on large (≥700px), max 5
* --runner-count drives the actual column count on large screens
* so fewer than 5 teams still fill the whole row.
*/
.runners-grid {
display: grid;
gap: 10px;
grid-template-columns: 1fr;
}
@media (min-width: 480px) {
.runners-grid {
grid-template-columns: repeat(2, 1fr);
}
.winner {
aspect-ratio: 2 / 1;
}
.runner {
aspect-ratio: 2 / 1;
}
}
@media (min-width: 700px) {
.runners-grid {
/* clamp actual count to 4 on large, but use --runner-count
so e.g. 2 teams still fill 2 equal columns not 2 of 4 */
grid-template-columns: repeat(min(var(--runner-count), 4), 1fr);
}
.winner {
aspect-ratio: 3 / 1;
}
.runner {
aspect-ratio: 3 / 2;
}
}
/* ── Section label ── */
.section-label {
font-size: 10px;
letter-spacing: 2.5px;
text-transform: uppercase;
opacity: 0.4;
padding: 12px 16px 4px;
margin: 0;
}
/* ── Events scrollable container ── */
.events-scroll {
flex: 1;
overflow-y: auto;
/* max-height: 900px; */
min-height: 0;
padding: 0 14px 24px;
/* Thin custom scrollbar */
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, currentColor 30%, transparent) transparent;
}
.events {
display: flex;
flex-direction: column;
gap: 10px;
}
/* ── Event card ── */
.event-card {
border-radius: 12px;
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
overflow: hidden;
transition: box-shadow 0.3s ease;
}
/* Focus highlight pulse — added/removed by $effect */
.event-card.highlight-pulse {
animation: card-pulse 1.2s ease-out forwards;
}
@keyframes card-pulse {
0% {
box-shadow: 0 0 0 3px currentColor;
}
100% {
box-shadow: 0 0 0 0px currentColor;
}
}
.event-header {
display: flex;
align-items: baseline;
gap: 10px;
padding: 9px 13px 7px;
border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent);
flex-wrap: wrap;
}
.event-name {
font-size: 15px;
text-decoration: none;
color: inherit;
}
.event-name:hover {
text-decoration: underline;
}
.event-division {
font-size: 10px;
letter-spacing: 1.2px;
text-transform: uppercase;
opacity: 0.4;
}
/* ── Brackets ── */
.brackets {
display: flex;
flex-direction: column;
}
.bracket-sep {
height: 1px;
background: color-mix(in srgb, currentColor 10%, transparent);
margin: 0 10px;
}
.bracket-row {
display: flex;
gap: 6px;
padding: 7px 9px;
flex-wrap: wrap;
}
/* ── Player boxes ── */
.player-box {
flex: 1 1 0; /* equal widths, no min-content bias */
max-width: 160px;
position: relative;
overflow: hidden;
border-radius: 8px;
border: 1.5px solid var(--c);
color: var(--c);
background: color-mix(in srgb, var(--c) 10%, transparent);
padding: 5px 7px 5px;
display: flex;
flex-direction: column;
min-height: 52px;
}
/* 1 col on small screens, 4 across on large */
@media (max-width: 479px) {
.bracket-row {
flex-direction: column;
}
.player-box {
max-width: 100%;
}
}
@media (min-width: 700px) {
.player-box {
max-width: calc(25% - 6px);
} /* 4 per row */
}
.player-ghost {
position: absolute;
inset: 0;
opacity: 0.15;
fill: currentColor;
pointer-events: none;
}
.ghost-svg {
width: 100%;
height: 100%;
display: block;
}
.player-name-wrap {
position: relative;
z-index: 1;
overflow: hidden;
white-space: nowrap;
}
.marquee-inner {
display: inline-block;
font-size: 11px;
font-weight: 600;
white-space: nowrap;
}
.marquee-inner.scrolling {
animation: marquee-scroll 7s ease-in-out infinite;
}
@keyframes marquee-scroll {
0%,
20% {
transform: translateX(0);
}
70%,
90% {
transform: translateX(var(--scroll-dist, 0px));
}
100% {
transform: translateX(0);
}
}
.player-placement {
position: relative;
z-index: 1;
font-size: 17px;
line-height: 1.1;
margin-top: 2px;
}
.player-placement-gap {
height: 20px;
}