/* ═══════════════════════════════════════════════════════════════════════════
   PESBUL — shared shell layer
   ---------------------------------------------------------------------------
   Everything here used to live inside homepage.css, which loads on the homepage
   and nowhere else. That is why every other page had different scrollbars,
   different heading fonts and differently drawn avatars: these rules simply
   never reached them.

   This file loads on EVERY page, straight after buttons.css and before any
   page stylesheet. It owns the things that must look identical site-wide:
   page container, heading and label typography, avatars, icons, scrollbars.

   A page stylesheet may set size and colour on top of this; it must not
   redefine the family, the casing or the avatar geometry.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Page container ─────────────────────────────────────────────────────────
   One width and one gutter for every route. Page stylesheets used to set
   their own (1180px on the league, 1640px on the ELO hub, 1600px everywhere
   else), so switching pages visibly shifted the content edges. */
/* The gutter scales with the viewport: 16px is right on a phone and far too
   tight beside a 1600px column, where content ends up hugging the edges. */
.pb-content {
    width: min(100%, var(--pb-max));
    margin-inline: auto;
    padding: 18px clamp(16px, 2.4vw, 40px) 28px;
}
/* A page stylesheet may add vertical padding; it must not reset the gutter. */
.pb-content[class] { padding-inline: clamp(16px, 2.4vw, 40px); }

/* Vertical rhythm between the major blocks of any page. */
.pb-content > section,
.pb-content > article { margin-bottom: 14px; }
.pb-content > section:last-child,
.pb-content > article:last-child { margin-bottom: 0; }

/* ── Typography ─────────────────────────────────────────────────────────────
   Three roles, three families, applied by structure so a new page inherits
   the house style without restating it.

   display   — page titles and numbers you are meant to read at a glance
   condensed — small uppercase labels: panel titles, table heads, KPI captions
   body      — everything else (set on <body> in base.css) */
.pb-content h1,
.pb-content h2,
.pb-content h3 {
    font-family: var(--pb-font-display);
    font-weight: 800;
    letter-spacing: 0.01em;
}
.pb-content h1 {
    letter-spacing: -0.015em;
    text-transform: uppercase;
}

/* The panel title. Every card header on every page resolves to this rule, so
   a section heading reads the same on the homepage, the ELO hub, the league,
   the dashboard and a public profile. */
.pb-card > header h2,
.pb-card > header h3,
.pb-feed > header h3,
.pb-data-panel > header h2,
.pb-dashboard-card__header h2,
.pb-elo3-card__head h2,
.pb-sl-card__head h2,
.pb-gm-mode__head h2,
.pb-pf-card__head h2 {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font: 500 13px/1 var(--pb-font-condensed);
    letter-spacing: 0.13em;
    text-transform: uppercase;
}

/* Small uppercase caption above or below a value. */
.pb-eyebrow,
.pb-kpi span:first-of-type,
.pb-quick-links strong,
.pb-elo3-kpi__label,
.pb-elo3-hero__kicker,
.pb-elo3-card__head .pb-elo3-pill,
.pb-pf-official h2 {
    font-family: var(--pb-font-condensed);
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.pb-eyebrow { font-size: 12px; line-height: 1; letter-spacing: 0.26em; }

/* Table heads, everywhere there is a table. */
.pb-room-feed thead th,
.pb-elo2-table th,
.pb-sl-table th,
.pb-pf-table th {
    font: 500 11px/1 var(--pb-font-condensed);
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

/* Numbers are read, not spelled: display face, tabular figures so columns of
   digits line up down a table. */
.pb-kpi strong,
.pb-data-panel li b,
.pb-record-rank,
.pb-result-score,
.pb-elo3-kpi strong,
.pb-elo3-lb__elo b,
.pb-elo3-lb__rank,
.pb-elo3-rating__value b,
.pb-elo3-hero__stats b,
.pb-elo3-podium__elo {
    font-family: var(--pb-font-display);
    font-variant-numeric: tabular-nums;
}

/* ── Scrollbars ─────────────────────────────────────────────────────────────
   A slim themed bar instead of the operating system's. Anything that scrolls
   anywhere on the site gets this — that is the point of it being global. */
* {
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 201, 255, 0.32) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    border: 2px solid transparent;
    border-radius: 99px;
    background: rgba(0, 201, 255, 0.30);
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 201, 255, 0.55);
    background-clip: content-box;
}

/* A fixed-height pane with its own scrollbar hides the rows a visitor came to
   read. Panels render their whole list; the page is what scrolls. */
.pb-stable-body,
.pb-live-body,
.pb-panel-body {
    block-size: auto;
    min-block-size: 0;
    max-block-size: none;
    overflow: visible;
    scrollbar-gutter: auto;
}
.pb-table-wrap { overflow: visible; }
@media (max-width: 900px) {
    /* Wide tables may still scroll sideways — the one axis that cannot be
       avoided without dropping columns. */
    .pb-table-wrap,
    .pb-table-scroll { overflow-x: auto; }
}

/* ── Icons ──────────────────────────────────────────────────────────────────
   Inline SVG inheriting currentColor. No icon font, no external request. */
.pb-icon { display: block; flex: 0 0 auto; }

.pb-nav-icon {
    display: grid;
    flex: 0 0 34px;
    place-items: center;
    width: 34px;
    height: 34px;
    border: 1px solid rgba(0, 201, 255, 0.22);
    border-radius: 10px;
    color: #7fd4ef;
    background: linear-gradient(160deg, rgba(0, 201, 255, 0.10), transparent 70%);
    transition: color .18s ease, border-color .18s ease, background .18s ease;
}
.pb-nav-list a:hover .pb-nav-icon,
.pb-nav-list .current-menu-item .pb-nav-icon,
.current-menu-item > a .pb-nav-icon {
    border-color: rgba(0, 201, 255, 0.6);
    color: #b9f0ff;
    background: linear-gradient(160deg, rgba(0, 201, 255, 0.22), transparent 72%);
}

/* ── Avatars ────────────────────────────────────────────────────────────────
   One shape, one ring, one fallback for every face on the site. The initial
   sits underneath and the image fades in over it once it has really decoded
   (shell.js adds .is-loaded), so a slow or missing image degrades to a letter
   rather than to a broken-image glyph.

   `--pb-avatar-size` is the only knob a caller needs. */
.pb-player-avatar,
.pb-crest,
.pb-account-avatar,
.pb-elo3-face {
    --pb-avatar-size: 36px;
    position: relative;
    display: grid;
    flex: 0 0 var(--pb-avatar-size);
    place-items: center;
    width: var(--pb-avatar-size);
    height: var(--pb-avatar-size);
    overflow: hidden;
    border: 1px solid rgba(0, 201, 255, 0.42);
    border-radius: 50%;
    color: var(--pb-cyan);
    background: radial-gradient(circle at 50% 25%, #0d2c40, #061b29);
    font: 700 calc(var(--pb-avatar-size) * 0.42)/1 var(--pb-font-display);
}
.pb-player-avatar img,
.pb-crest img,
.pb-account-avatar img,
.pb-elo3-face img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
    /* Only shown once it has really decoded — see shell.js. */
    opacity: 0;
    transition: opacity .2s ease;
}
.pb-player-avatar img.is-loaded,
.pb-crest img.is-loaded,
.pb-account-avatar img.is-loaded,
.pb-elo3-face img.is-loaded { opacity: 1; }

/* Pages outside the homepage do not run the avatar settle pass, so their
   images must not wait for a class that never arrives. */
.pb-elo3-face img,
.pb-account-avatar img { opacity: 1; }

.pb-avatar-fallback,
.pb-elo3-face__initial {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    color: inherit;
    font: inherit;
}

@media (prefers-reduced-motion: reduce) {
    .pb-player-avatar img,
    .pb-crest img,
    .pb-account-avatar img,
    .pb-elo3-face img { transition: none; }
}

/* Phones: a smaller gutter, still not zero. Kept here rather than in base.css so
   the container has one owner and the cascade cannot fight itself. */
@media (max-width: 767px) {
    .pb-content,
    .pb-content[class] { padding-inline: 12px; }
}

/* ── Native controls ────────────────────────────────────────────────────────
   The open dropdown list is painted by the operating system, not by the page.
   It kept the system's light background while inheriting our light text, so
   the options were white on grey — unreadable. Each `option` needs its own
   colours; inheriting from the `select` is not enough.

   The arrow is drawn as an inline SVG background so the control matches the
   rest of the form instead of showing the platform's default chrome. */
.pb-content select,
.pb-content option,
.pb-content optgroup {
    color: var(--pb-text-main);
    background-color: var(--pb-bg-card-soft);
}
.pb-content option:checked,
.pb-content option:hover {
    color: #04101c;
    background: var(--pb-cyan);
}
.pb-content select {
    appearance: none;
    padding-right: 34px;
    border: 1px solid var(--pb-border);
    border-radius: 8px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237fd4ef' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 16px 16px;
}
.pb-content select:focus-visible {
    outline: 2px solid var(--pb-cyan);
    outline-offset: 1px;
}

/* Some platforms honour only the colour scheme; declaring it dark makes them
   draw the list in dark chrome of their own accord. */
.pb-content select,
.pb-content input,
.pb-content textarea { color-scheme: dark; }

/* ══ Pitch-side support board ══════════════════════════════════════════════
   A perimeter advertising hoarding, the kind that runs along the touchline in
   every stadium and in the game itself. It is the one ad slot a football
   audience reads without being asked to, and it is not sold — it cycles from
   "nobody is paying for this" through to the ask. Dot-matrix texture, a slow
   refresh sweep across the panel, and messages that flip like real LED boards
   do. All of it decorative: the whole panel is a single link. */
.pb-board {
    position: relative;
    width: min(100%, var(--pb-max));
    /* Tucked under the utility header. The page container below brings its own
       top padding, so the board needs clearance above it and none beneath. */
    margin: clamp(10px, 1.6vw, 18px) auto 0;
    padding-inline: clamp(16px, 2.4vw, 40px);
}

/* The touchline. A hoarding stands on grass, and one green line along its foot
   is the whole difference between a banner on a web page and a board at the
   side of a pitch. It tilts with the panel, because it belongs to it. */
.pb-board__panel::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    pointer-events: none;
    background: linear-gradient(90deg, transparent, rgba(60, 210, 120, 0.5) 18%, rgba(60, 210, 120, 0.5) 82%, transparent);
}

.pb-board__panel {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: clamp(12px, 2vw, 26px);
    overflow: hidden;
    padding: 0.85rem clamp(0.9rem, 2vw, 1.5rem);
    border: 1px solid rgba(120, 220, 255, 0.16);
    border-radius: 12px;
    text-decoration: none;
    color: inherit;
    /* Seen from the stand rather than head-on — a few degrees is all it takes
       to read as a board on the grass instead of a banner on the page. */
    transform: perspective(900px) rotateX(4deg);
    transform-origin: bottom center;
    background-color: #060d14;
    background-image:
        radial-gradient(circle at 50% 50%, rgba(140, 235, 255, 0.055) 0.9px, transparent 1.1px),
        linear-gradient(180deg, rgba(10, 24, 36, 0.95), rgba(4, 8, 13, 0.98));
    background-size: 4px 4px, 100% 100%;
    box-shadow:
        0 14px 30px -18px rgba(0, 0, 0, 0.9),
        inset 0 1px 0 rgba(255, 255, 255, 0.05);
    transition: border-color 0.25s ease, transform 0.25s ease, box-shadow 0.25s ease;
}

/* The refresh sweep: a bright band travelling the length of the board, the way
   a camera catches an LED hoarding mid-scan. */
.pb-board__panel::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(105deg, transparent 38%, rgba(150, 240, 255, 0.11) 48%, rgba(150, 240, 255, 0.02) 56%, transparent 62%);
    background-size: 260% 100%;
    animation: pb-board-sweep 7s linear infinite;
}

@keyframes pb-board-sweep {
    from { background-position: 160% 0; }
    to { background-position: -60% 0; }
}

.pb-board__panel:hover,
.pb-board__panel:focus-visible {
    border-color: rgba(255, 196, 84, 0.55);
    transform: perspective(900px) rotateX(4deg) translateY(-2px);
    box-shadow:
        0 18px 34px -18px rgba(0, 0, 0, 0.95),
        0 0 0 1px rgba(255, 196, 84, 0.12),
        inset 0 1px 0 rgba(255, 255, 255, 0.07);
}

/* The slot number, as printed on a real hoarding. */
.pb-board__slot {
    position: relative;
    z-index: 1;
    font-family: var(--pb-font-condensed);
    font-size: 0.64rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(150, 235, 255, 0.5);
    padding: 0.2rem 0.45rem;
    border: 1px solid rgba(150, 235, 255, 0.22);
    border-radius: 4px;
    white-space: nowrap;
}

/* One line tall: the reel behind it is taller and slides. */
.pb-board__screen {
    position: relative;
    z-index: 1;
    display: block;
    overflow: hidden;
    height: 1.7rem;
}

.pb-board__reel {
    display: block;
    animation: pb-board-reel 13s cubic-bezier(0.7, 0, 0.2, 1) infinite;
}

.pb-board__line {
    display: block;
    height: 1.7rem;
    line-height: 1.7rem;
    font-family: var(--pb-font-condensed);
    font-size: clamp(0.92rem, 1.6vw, 1.14rem);
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #dff4ff;
    text-shadow: 0 0 12px rgba(120, 220, 255, 0.35);
}

/* Hold on each message, then flip. The last line repeats the first, which is
   what makes the loop seamless — so the stop count follows the message count,
   and a two-message board never slides into empty space. */
.pb-board[data-lines="1"] .pb-board__reel { animation: none; }

.pb-board[data-lines="2"] .pb-board__reel {
    animation-name: pb-board-reel-2;
    animation-duration: 9s;
}

@keyframes pb-board-reel-2 {
    0%, 33% { transform: translateY(0); }
    39%, 72% { transform: translateY(-1.7rem); }
    78%, 100% { transform: translateY(-3.4rem); }
}

@keyframes pb-board-reel {
    0%, 22% { transform: translateY(0); }
    25%, 47% { transform: translateY(-1.7rem); }
    50%, 72% { transform: translateY(-3.4rem); }
    75%, 97% { transform: translateY(-5.1rem); }
    100% { transform: translateY(-5.1rem); }
}

.pb-board__cta {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.52rem 1rem;
    border-radius: 999px;
    font-family: var(--pb-font-condensed);
    font-size: 0.9rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    white-space: nowrap;
    color: #1a1204;
    background: linear-gradient(135deg, #ffd66b, #f2a83c);
    box-shadow: 0 6px 18px -8px rgba(255, 176, 60, 0.8);
}

.pb-board__cta .pb-icon { color: #1a1204; }

.pb-board__arrow {
    display: inline-block;
    transition: transform 0.25s ease;
}

.pb-board__panel:hover .pb-board__arrow,
.pb-board__panel:focus-visible .pb-board__arrow { transform: translateX(4px); }

.pb-board__note {
    margin: 0.5rem 0 0;
    text-align: center;
    font-size: 0.72rem;
    color: rgba(198, 216, 232, 0.55);
}

@media (max-width: 640px) {
    /* No room for a slot tag and a pill on one line — the board becomes a
       stacked card and drops the tilt, which only reads well when wide. */
    .pb-board__panel {
        grid-template-columns: minmax(0, 1fr);
        justify-items: center;
        text-align: center;
        gap: 0.6rem;
        transform: none;
    }
    .pb-board__panel:hover,
    .pb-board__panel:focus-visible { transform: translateY(-2px); }
    .pb-board__slot { display: none; }
    .pb-board__screen { width: 100%; }
    .pb-board__line { white-space: normal; text-align: center; }
}

@media (prefers-reduced-motion: reduce) {
    /* No flipping, no sweep — park the reel on the last real message, which is
       the ask, so the board still says the thing it exists to say. */
    /* Park on the ask — the last real message, wherever that falls. */
    .pb-board__reel { animation: none; }
    .pb-board[data-lines="2"] .pb-board__reel { transform: translateY(-1.7rem); }
    .pb-board[data-lines="3"] .pb-board__reel { transform: translateY(-3.4rem); }
    .pb-board__panel::after { animation: none; }
    .pb-board__arrow { transition: none; }
}

/* ══ Match history (/matches/) ═════════════════════════════════════════════ */
.pb-mh__head h1 { margin: 0 0 4px; }
.pb-mh__head p { margin: 0 0 18px; color: var(--pb-text-muted); }
.pb-mh__filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 16px; }
.pb-mh__modes { display: flex; gap: 4px; padding: 3px; border: 1px solid var(--pb-border); border-radius: 999px; }
.pb-mh__mode { padding: 5px 12px; border-radius: 999px; font: 600 11px/1.2 var(--pb-font-condensed); letter-spacing: 0.06em; text-transform: uppercase; color: var(--pb-text-muted); text-decoration: none; }
.pb-mh__mode.is-active { color: #041018; background: linear-gradient(135deg, var(--pb-cyan), #4f7fff); }
.pb-mh__filters input[type="search"] { flex: 1 1 200px; min-width: 0; padding: 7px 12px; border-radius: 8px; }

/* ── Match history cards ─────────────────────────────────────────────────────
   Full width on purpose — the operator wants the row to use the page. The work
   is in the internal alignment, not in narrowing it: context on top, the
   scoreline anchored in the middle, and the goals split down the same centre so
   the eye reads one vertical line the whole way down the card. */
.pb-mh__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }

.pb-mh__row {
    border: 1px solid var(--pb-border);
    border-radius: 14px;
    background: var(--pb-bg-card);
    overflow: hidden;
}

/* Context first. Which competition it counted for tells a friendly apart from a
   cup tie, so it is read before the score rather than found underneath it. */
.pb-mh__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: rgba(4, 16, 28, 0.55);
    border-bottom: 1px solid var(--pb-divider);
    font-size: 0.7rem;
    color: var(--pb-text-muted);
}
.pb-mh__mode-tag,
.pb-mh__room { padding: 2px 7px; border: 1px solid var(--pb-border); border-radius: 5px; }
.pb-mh__room { letter-spacing: 0.04em; }
/* The competition this match counted for — a badge, not a bare link. It is the
   one chip in the strip that says whether the match meant anything. */
.pb-mh__comp {
    padding: 2px 8px;
    border-radius: 5px;
    color: var(--pb-cyan);
    background: rgba(0, 201, 255, 0.1);
    border: 1px solid rgba(0, 201, 255, 0.35);
    text-decoration: none;
    font-weight: 600;
}
.pb-mh__comp:hover { background: rgba(0, 201, 255, 0.18); text-decoration: none; }
/* An abnormal ending is part of the record, so it is marked rather than hidden. */
.pb-mh__abnormal {
    padding: 2px 7px;
    border-radius: 5px;
    color: #ffb4bc;
    background: rgba(255, 84, 112, 0.12);
    border: 1px solid rgba(255, 84, 112, 0.35);
}

/* ONE circle per player. The avatar is the person; the crest belongs to the club
   and sits on the club's own line, where it identifies a team instead of
   competing with the face for the same spot. */
.pb-mh__fixture {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 16px;
    padding: 16px 14px;
}
.pb-mh__side { display: flex; align-items: center; gap: 12px; min-width: 0; }
.pb-mh__side--away { flex-direction: row-reverse; text-align: right; }
.pb-mh__face { flex: 0 0 auto; display: inline-flex; }
.pb-mh__who { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.pb-mh__side--away .pb-mh__who { align-items: flex-end; }
.pb-mh__name {
    font: 700 1rem/1.2 var(--pb-font-display);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pb-mh__club {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    font-size: 0.74rem;
    color: var(--pb-text-muted);
}
.pb-mh__side--away .pb-mh__club { flex-direction: row-reverse; }
.pb-mh__club img { flex: 0 0 16px; width: 16px; height: 16px; object-fit: contain; }
.pb-mh__club span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The scoreline is the anchor the whole card lines up on, so it is boxed rather
   than left floating in the gap between two names. */
.pb-mh__score {
    font: 800 1.55rem/1 var(--pb-font-display);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    padding: 5px 14px;
    border-radius: 10px;
    background: rgba(4, 16, 28, 0.6);
    border: 1px solid var(--pb-border);
}
.pb-mh__score i { margin: 0 6px; font-style: normal; font-weight: 400; color: var(--pb-text-soft); }

/* A linked player reads as a name, not as a hyperlink. */
.pb-mh__side .pb-player-link {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    color: inherit;
    text-decoration: none;
    transition: color 0.15s ease;
}
.pb-mh__side--away .pb-player-link { flex-direction: row-reverse; }
.pb-mh__side .pb-player-link:hover,
.pb-mh__side .pb-player-link:focus-visible { color: var(--pb-cyan); }

/* The part the operator likes best: who scored, who set it up, and when. Split
   down the same centre as the score — left column is the home side, right the
   away — and kept in the order they were scored. */
.pb-mh__goals {
    list-style: none;
    margin: 0;
    padding: 12px 14px;
    border-top: 1px solid var(--pb-divider);
    background: rgba(4, 16, 28, 0.3);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 6px 16px;
}
.pb-mh__goal { grid-column: 1; display: flex; align-items: baseline; gap: 8px; min-width: 0; font-size: 0.82rem; }
.pb-mh__goal--away { grid-column: 2; flex-direction: row-reverse; text-align: right; }
.pb-mh__minute {
    flex: 0 0 auto;
    min-width: 30px;
    font: 700 0.74rem/1 var(--pb-font-condensed);
    color: var(--pb-cyan);
}
.pb-mh__goal--away .pb-mh__minute { text-align: right; }
.pb-mh__goal small { color: var(--pb-text-muted); }

.pb-mh__pager { display: flex; justify-content: center; align-items: center; gap: 16px; margin-top: 18px; font-size: 0.8rem; }
.pb-mh__empty { padding: 30px; text-align: center; color: var(--pb-text-muted); }

/* Narrow: the two sides stack, so nothing is mirrored any more — a right-aligned
   name under a left-aligned one reads as two different lists. */
@media (max-width: 640px) {
    .pb-mh__fixture { grid-template-columns: minmax(0, 1fr) auto; gap: 12px; }
    .pb-mh__side--away { grid-column: 1; flex-direction: row; text-align: left; }
    .pb-mh__side--away .pb-mh__who { align-items: flex-start; }
    .pb-mh__side--away .pb-mh__club { flex-direction: row; }
    .pb-mh__side--away .pb-player-link { flex-direction: row; }
    .pb-mh__score { grid-column: 2; grid-row: 1 / 3; }
    .pb-mh__goals { grid-template-columns: minmax(0, 1fr); }
    .pb-mh__goal--away { grid-column: 1; flex-direction: row; text-align: left; }
}

/* ── The live fixture strip ──────────────────────────────────────────────────
   One card, five states. The colour is the message: grey means the site has not
   found the room yet, red means it has. A player who sees red before kick-off
   knows the result will be recorded; a player who sees grey after kick-off
   knows the room name is wrong while there is still time to fix it. */
.pb-live {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 6px 10px;
    border-radius: 8px;
    border: 1px solid var(--pb-border-soft);
    background: rgba(4, 16, 28, 0.55);
    font-size: 0.72rem;
    line-height: 1.3;
}
.pb-live__dot {
    flex: 0 0 8px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--pb-text-soft);
}
.pb-live__label {
    color: var(--pb-text-muted);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* The scoreline stays hidden until the game reports numbers: an absent score is
   not nil-nil, and printing one would invent a goalless draw. */
.pb-live__score {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: baseline;
    gap: 3px;
    font-weight: 800;
    font-size: 0.95rem;
    font-variant-numeric: tabular-nums;
    color: var(--pb-text-main);
}
.pb-live__score[hidden] { display: none; }
.pb-live__score i { font-style: normal; color: var(--pb-text-soft); }

/* Waiting: the code is armed and nothing has been found. Deliberately quiet. */
.pb-live[data-pb-live-state="armed"] { opacity: 0.75; }

/* Found, before a ball is kicked. This is the confirmation the whole feature
   exists to give, so it is as loud as a live match. */
.pb-live[data-pb-live-state="room"],
.pb-live[data-pb-live-state="live"],
.pb-live[data-pb-live-state="break"],
.pb-live[data-pb-live-state="ended"],
.pb-live[data-pb-live-state="settling"] {
    border-color: rgba(255, 77, 89, 0.55);
    background: rgba(255, 77, 89, 0.09);
}
.pb-live[data-pb-live-state="room"] .pb-live__dot,
.pb-live[data-pb-live-state="live"] .pb-live__dot,
.pb-live[data-pb-live-state="break"] .pb-live__dot,
.pb-live[data-pb-live-state="ended"] .pb-live__dot,
.pb-live[data-pb-live-state="settling"] .pb-live__dot {
    background: var(--pb-red);
    box-shadow: 0 0 0 0 rgba(255, 77, 89, 0.7);
}
.pb-live[data-pb-live-state="room"] .pb-live__label,
.pb-live[data-pb-live-state="live"] .pb-live__label,
.pb-live[data-pb-live-state="break"] .pb-live__label,
.pb-live[data-pb-live-state="ended"] .pb-live__label,
.pb-live[data-pb-live-state="settling"] .pb-live__label {
    color: var(--pb-text-main);
    font-weight: 600;
}

/* Half-time is not play. It keeps the red card — the match is still on — but the
   dot stops pulsing, because nothing is happening on the pitch. */
.pb-live[data-pb-live-state="break"] .pb-live__dot { background: var(--pb-orange); }

/* Played, but the result has not reached the table. Amber, because it is not an
   error the player caused and not a success either — it is work outstanding. */
.pb-live[data-pb-live-state="unbound"] {
    border-color: rgba(255, 181, 71, 0.5);
    background: rgba(255, 181, 71, 0.09);
}
.pb-live[data-pb-live-state="unbound"] .pb-live__dot { background: var(--pb-orange); }
.pb-live[data-pb-live-state="unbound"] .pb-live__label { color: var(--pb-text-main); font-weight: 600; }

/* Recorded: the result is in the table. Green, and permanently still. */
.pb-live[data-pb-live-state="recorded"] {
    border-color: rgba(53, 229, 111, 0.45);
    background: rgba(53, 229, 111, 0.08);
}
.pb-live[data-pb-live-state="recorded"] .pb-live__dot { background: var(--pb-green); }
.pb-live[data-pb-live-state="recorded"] .pb-live__label { color: var(--pb-text-main); }

@media (prefers-reduced-motion: no-preference) {
    .pb-live[data-pb-live-state="room"] .pb-live__dot,
    .pb-live[data-pb-live-state="live"] .pb-live__dot,
    .pb-live[data-pb-live-state="settling"] .pb-live__dot {
        animation: pb-live-pulse 1.6s ease-out infinite;
    }
}
@keyframes pb-live-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(255, 77, 89, 0.65); }
    70%  { box-shadow: 0 0 0 7px rgba(255, 77, 89, 0); }
    100% { box-shadow: 0 0 0 0 rgba(255, 77, 89, 0); }
}

/* ── The footballer viewer ───────────────────────────────────────────────────
   The PES Master page, opened over this site rather than instead of it. */
.pb-fb-modal { position: fixed; inset: 0; z-index: 900; display: grid; place-items: center; padding: clamp(12px, 3vw, 40px); }
.pb-fb-modal[hidden] { display: none; }
.pb-fb-modal__backdrop { position: absolute; inset: 0; background: rgba(2, 9, 20, 0.78); backdrop-filter: blur(3px); }
.pb-fb-modal__panel {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(1000px, 100%);
    height: min(88vh, 900px);
    overflow: hidden;
    border: 1px solid var(--pb-border);
    border-radius: 14px;
    background: var(--pb-bg-card);
    box-shadow: 0 30px 90px rgba(0, 0, 0, 0.6);
}
.pb-fb-modal__head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--pb-divider);
    background: rgba(4, 16, 28, 0.6);
}
.pb-fb-modal__head h2 {
    flex: 1;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    font: 800 1rem/1.2 var(--pb-font-display);
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pb-fb-modal__out { flex: 0 0 auto; font-size: 0.74rem; color: var(--pb-cyan); text-decoration: none; }
.pb-fb-modal__out:hover { text-decoration: underline; }
.pb-fb-modal__close {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--pb-border);
    border-radius: 8px;
    color: var(--pb-text-main);
    background: transparent;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}
.pb-fb-modal__close:hover { border-color: var(--pb-cyan); color: var(--pb-cyan); }
/* The frame fills what is left, and is white because the page inside it is. */
.pb-fb-modal__body { flex: 1; min-height: 0; background: #fff; }
.pb-fb-modal__body iframe { display: block; width: 100%; height: 100%; border: 0; }
/* The page behind must not scroll while the viewer is open. */
body.pb-fb-open { overflow: hidden; }
/* A footballer's name reads as a name, not as a hyperlink — the same rule the
   player links follow. It is the cursor and the hover that say it opens. */
.pb-fb-link { color: inherit; text-decoration: none; cursor: pointer; }
.pb-fb-link:hover strong,
.pb-fb-link:focus-visible strong { color: var(--pb-cyan); text-decoration: underline; }
