/* Golorum — app chassis (topbar, drawer, bottom nav) and shared screen styles.
   Ported from the validated mockups:
   .superpowers/brainstorm/3061279-1784974935/content/03-hamburguesa.html
   .superpowers/brainstorm/3061279-1784974935/content/04-inicio-clasificacion.html

   ══ RESPONSIVE SYSTEM ═══════════════════════════════════════════════════════

   Three tiers, and only TWO width thresholds. Everything else is fluid: the
   shell, the gutters and the card grids all resize between the thresholds
   instead of jumping at them.

     PHONE     (base, mobile-first — no media query)
               One column capped at --shell. Sections live in the bottom bar.

     TABLET+   @media (min-width: 700px)
               The sections move up into the topbar and the bottom bar goes
               away: a thumb bar is a phone pattern, and from here on there is
               a pointer and a wide window. The shell widens and card lists
               become auto-fill grids, so a tablet in portrait already gets two
               columns instead of a stretched phone.

     DESKTOP   @media (min-width: 1100px)
               Same chrome as tablet, more room: a wider shell, bigger gutters
               and a third column where the cards are narrow enough to earn it.

   700 and 1100 are the ONLY size thresholds in the app. Two more queries exist
   and are NOT tiers — they are spacing tweaks inside the phone tier, labelled
   as such where they appear:
     max-width: 380px   very narrow phones (tighter fixture rows)
     max-width: 559px   hide your own name in the topbar so the league fits
   Adding a third tier is almost always the wrong answer: widen a minmax() or
   reach for clamp() instead.

   RULES OF THE ROAD
   · No fixed pixel widths on containers. Widths come from --shell, --gutter
     and --read, or from min()/clamp().
   · Reading text never exceeds --read (~68 characters). Wide screens get more
     COLUMNS, never longer lines.
   · Anything that cannot shrink (tables, the newspaper) scrolls inside its own
     box; the page itself must never scroll sideways at any width.        */

:root {
    --green: #0a1410;
    --lime: #c6f24e;
    --card: #12241c;
    --line: #1d3a2c;
    --ink: #e8ede9;
    --muted: #9db0a4;
    --neg: #e0703a;
    --gold: #f5d76e;
    --shadow: 0 8px 30px rgba(0, 0, 0, .5);

    /* Layout tokens. Redefined once per tier, so a screen only ever has to say
       "as wide as the shell" and never a number of its own. */
    --shell: 34rem;     /* the content column, phone tier */
    --gutter: .8rem;    /* space between the content and the shell edge */
    --read: 68ch;       /* longest comfortable line of prose */
    --pitch: clamp(1.75rem, 7vw, 3.25rem);  /* width of one pitch stripe */
}

* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }

body {
    background: repeating-linear-gradient(90deg,
        var(--green) 0, var(--green) var(--pitch),
        #0f2115 var(--pitch), #0f2115 calc(var(--pitch) * 2));
    color: var(--ink);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    line-height: 1.5;
    padding-bottom: 0; /* the .app grid reserves the bottom bar itself */
}

img, svg, video { max-width: 100%; }

/* ===== Anonymous pages (login / registro / confirmar) — unchanged .wrap branch ===== */

/* A login form does not want a wide screen, so .wrap stays a form column and
   only gains air above it as the window grows. The legal pages are the one
   exception and widen in the TABLET+ block: they are documents, not forms. */
.wrap { width: 100%; max-width: 26.25rem; margin: 0 auto;
    padding: clamp(1.25rem, 6vh, 4rem) 1.25rem 2.5rem; position: relative; z-index: 1; }
.wrap h1 { color: var(--lime); font-size: 1.6rem; margin: 0 0 .3rem; }
.wrap .sub { color: var(--muted); margin: 0 0 1.8rem; font-size: .95rem; }
.wrap form { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 1.4rem; }
.wrap label { display: block; font-size: .85rem; color: var(--muted); margin: .9rem 0 .3rem; }
.wrap input {
    width: 100%; padding: .6rem .75rem; border-radius: 8px; border: 1px solid var(--line);
    background: var(--green); color: var(--ink); font-size: 1rem;
}
.wrap button {
    width: 100%; margin-top: 1.3rem; padding: .7rem; border: none; border-radius: 8px;
    background: var(--lime); color: var(--green); font-weight: 700; font-size: 1rem; cursor: pointer;
}
.wrap .error {
    background: rgba(232, 121, 91, .12); border: 1px solid rgba(232, 121, 91, .4); color: #e8795b;
    border-radius: 8px; padding: .6rem .8rem; font-size: .88rem; margin-bottom: 1rem;
}
.wrap .alt { text-align: center; margin-top: 1.3rem; font-size: .9rem; color: var(--muted); }
.wrap .alt a { color: var(--lime); }

/* ===== App chassis (session pages) ===== */

.app {
    position: relative;
    display: grid;
    grid-template-rows: auto 1fr;
    /* Grid children default to min-width:auto, so a table wider than the screen
       would stretch this column and take the whole page sideways with it. */
    grid-template-columns: minmax(0, 1fr);
    min-height: 100dvh;
    width: 100%;
    max-width: var(--shell);
    margin: 0 auto;
    background-image: repeating-linear-gradient(90deg,
        #0a1410 0, #0a1410 var(--pitch),
        #0d1a13 var(--pitch), #0d1a13 calc(var(--pitch) * 2));
}

/*
 * The bottom bar is pinned to the viewport instead of being a grid row: on
 * mobile the browser chrome collapses on scroll, which changes what 100dvh
 * resolves to, and a chassis-height row would slide below the fold until the
 * user scrolled back up. .app-scroll reserves its height as padding so the
 * last item is never hidden behind it.
 */
.app-foot {
    position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
    z-index: 15; width: 100%; max-width: var(--shell);
}

.app-scroll {
    position: relative; z-index: 2;
    min-width: 0;
    padding: .9rem var(--gutter) calc(var(--foot-h, 4.5rem) + 1rem);
}

/* ---- Layout helpers, used by every screen instead of per-page one-offs ---- */

/* A stack of cards that becomes columns once there is room. Cards are as wide
   as they need to be and no wider, which is also what keeps their text short. */
.card-cols { display: grid; gap: 0; }

/* A list of fixtures. One per row on a phone, a grid of them from tablet up.
   The day headings inside it always span the full row — see the tablet tier. */
.match-grid { display: block; }

.overlay { position: fixed; inset: 0; z-index: 20; background: rgba(0, 0, 0, .55); display: none; }
.overlay.show { display: block; }

/* ---- Topbar ---- */

/* z-index above .overlay (20): the league dropdown lives inside the topbar, and
   sticky + z-index makes this a stacking context, so the dropdown's own z-index
   is only relative to its siblings here. At 5 the overlay covered it and
   swallowed every click on "Crear una liga" / "Unirme con un código". */
.topbar {
    position: sticky; top: 0; z-index: 25;
    padding: .8rem .8rem;
    border-bottom: 1px solid var(--line);
    background: #0c1712ee;
    backdrop-filter: blur(6px);
}
/* The burger and league switch always share one row; .top-nav (desktop only)
   sits below them. */
.topbar-main { display: flex; align-items: center; gap: .55rem; }

/* Your name and photo, always on screen instead of behind the burger, and a
   shortcut to Mi perfil — which is where the photo gets changed. */
/* Scoped to the topbar on purpose. A bare .me also matches the ranking's
   "this row is you" class, and turning that <tr> into a flex container drops
   it out of the table layout — which misaligns exactly one row, yours. */
/* min-width/min-height 44px: on a phone the name is hidden and only the 34px
   photo is left, which is under the size a thumb hits reliably. The box grows
   around the photo instead of the photo growing — justify-content keeps it
   pinned to the right edge, so nothing moves. */
.topbar .me { margin-left: auto; flex: none; display: inline-flex; align-items: center;
    justify-content: flex-end; gap: .5rem; min-width: 44px; min-height: 44px;
    text-decoration: none; color: var(--ink); }
.topbar .me .me-name { font-size: .82rem; font-weight: 700; max-width: 9rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar .me .av { width: 34px; height: 34px; flex: none; border-radius: 50%;
    background: linear-gradient(135deg, #2d6a45, #173626); border: 1px solid var(--line);
    display: grid; place-items: center; font-size: .7rem; font-weight: 800; color: var(--lime); }
/* PHONE TWEAK (not a tier): on a narrow phone the league name needs the width
   more than your own name does — the photo alone still says whose account
   this is. */
@media (max-width: 559px) {
    .topbar .me .me-name { display: none; }
}

.burger {
    width: 40px; height: 40px; border-radius: 11px; border: 1px solid var(--line);
    background: var(--card); display: grid; place-items: center; cursor: pointer; flex: none;
}
.burger svg { width: 21px; height: 21px; color: var(--ink); }

/* ---- League switch ---- */

.league-switch {
    display: flex; align-items: center; gap: .5rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 11px;
    padding: .42rem .6rem; cursor: pointer; flex: 1; min-width: 0;
}
.league-switch .crest {
    width: 26px; height: 26px; border-radius: 7px;
    background: linear-gradient(135deg, var(--lime), #7fae2e);
    color: var(--green); font-weight: 800; font-size: .8rem;
    display: grid; place-items: center; flex: none;
}
.league-switch .nm { font-weight: 700; font-size: .88rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.league-switch .sb { font-size: .68rem; color: var(--muted); }
.league-switch .chev { margin-left: auto; color: var(--muted); font-size: .7rem; }

/* ---- League dropdown (quick switch) ---- */

.dropdown {
    /* Viewport-pinned like the drawer, so it tracks the sticky topbar.
       Anchored under the league switch: that sits one burger-width in from the
       left edge of the shell, and the shell is centred. */
    position: fixed; top: 3.9rem;
    left: max(3.75rem, calc(50% - var(--shell) / 2 + 3.75rem));
    width: 18.125rem; max-width: 80%; z-index: 30;
    background: var(--card); border: 1px solid var(--line); border-radius: 14px;
    box-shadow: var(--shadow); display: none; overflow: hidden;
}
.dropdown.show { display: block; animation: pop .16s ease; }
@keyframes pop { from { transform: translateY(-6px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

.dd-cap { font-size: .62rem; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); padding: .7rem .8rem .3rem; }
.dd-item {
    display: flex; align-items: center; gap: .6rem; padding: .6rem .8rem; font-size: .86rem;
    cursor: pointer; text-decoration: none; color: var(--ink);
}
.dd-item:hover { background: #1a3527; }
.dd-item .crest {
    width: 24px; height: 24px; border-radius: 6px; font-weight: 800; font-size: .75rem;
    background: linear-gradient(135deg, var(--lime), #7fae2e);
    color: var(--green); display: grid; place-items: center; flex: none;
}
.dd-item.active { background: #1a3527; }
.dd-item.active .nm { color: var(--lime); font-weight: 700; }
.dd-item .ic { width: 22px; text-align: center; color: var(--muted); }
.dd-sep { height: 1px; background: var(--line); margin: .3rem 0; }

/* ---- Drawer ---- */

.drawer {
    /* Pinned to the viewport, not to .app: the chassis now grows with its
       content, so an absolute drawer would stretch to the whole page height. */
    position: fixed; z-index: 30; top: 0; bottom: 0;
    /* Anchored to the viewport edge: translateX(-100%) only parks it fully
       off-screen when left is 0, otherwise a strip stays visible when closed. */
    left: 0;
    width: min(87%, 19.375rem);
    background: #0b1611; border-right: 1px solid var(--line); box-shadow: var(--shadow);
    transform: translateX(-100%);
    transition: transform .24s cubic-bezier(.4, 0, .2, 1);
    display: flex; flex-direction: column;
}
.drawer.show { transform: translateX(0); }

.dr-top {
    padding: 1.1rem .95rem; border-bottom: 1px solid var(--line);
    display: flex; align-items: center; gap: .75rem;
    background: linear-gradient(135deg, #12281d, #0b1611);
}
.dr-top .av {
    width: 48px; height: 48px; border-radius: 50%;
    background: linear-gradient(135deg, #2d6a45, #173626);
    color: var(--lime); font-weight: 800; display: grid; place-items: center; font-size: 1.15rem; flex: none;
}
.dr-top .nm { font-weight: 700; font-size: 1rem; }

.dr-scroll { flex: 1; overflow-y: auto; padding: .4rem 0; }

.cap { font-size: .6rem; text-transform: uppercase; letter-spacing: .13em; color: var(--muted); padding: .75rem .95rem .3rem; }

.di {
    display: flex; align-items: center; gap: .75rem; padding: .66rem .95rem; cursor: pointer;
    font-size: .92rem; text-decoration: none; color: var(--ink);
    width: 100%; text-align: left; background: none; border: none; font-family: inherit;
}
.di:hover { background: #16302463; }
.di svg { width: 20px; height: 20px; color: var(--muted); flex: none; }
.di.admin { color: var(--lime); }
.di.admin svg { color: var(--lime); }
.di .crest {
    width: 22px; height: 22px; border-radius: 6px; font-weight: 800; font-size: .68rem;
    background: linear-gradient(135deg, var(--lime), #7fae2e);
    color: var(--green); display: grid; place-items: center; flex: none;
}
.di .arrow { margin-left: auto; color: var(--muted); font-size: .8rem; }

.dr-sep { height: 1px; background: var(--line); margin: .35rem .6rem; }
.dr-foot { border-top: 1px solid var(--line); padding: .5rem 0; }
.dr-foot form { background: none; border: none; padding: 0; }
.di.logout { color: var(--neg); }
.di.logout svg { color: var(--neg); }

/* ---- Bottom nav ---- */

.bottom-nav {
    position: relative; z-index: 5;
    display: flex; justify-content: space-around;
    padding: .5rem 0 calc(.5rem + env(safe-area-inset-bottom));
    border-top: 1px solid var(--line);
    background: #0c1712f2;
    backdrop-filter: blur(6px);
}
.nav-item {
    display: flex; flex-direction: column; align-items: center; gap: .18rem;
    color: var(--muted); font-size: .66rem; flex: 1; text-decoration: none;
}
.nav-item svg { width: 22px; height: 22px; }
.nav-item.on { color: var(--lime); }

/* ---- A goal, arriving on its own ----
   The number changes without anybody touching the page, so it needs a moment
   of attention and no more: brighten and settle, in place. No movement, no
   size change — the score sits between two team names and anything that
   resized it would shove them sideways mid-read. */

.live-bump {
    animation: livebump .9s ease-out;
    border-radius: 4px;
}

@keyframes livebump {
    0%   { color: var(--lime); background: rgba(198, 242, 78, .28); }
    100% { color: inherit;     background: transparent; }
}

/* ---- prefers-reduced-motion: kill the drawer/dropdown movement ---- */

@media (prefers-reduced-motion: reduce) {
    .dropdown.show,
    .drawer {
        animation: none !important;
        transition: none !important;
    }

    /* The new score is still there — it just arrives without the flash. */
    .live-bump {
        animation: none !important;
    }
}

/* ---- Shared content: page header, cards, tabs, matches, ranking rows ---- */

.page-h { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: .5rem; }
.page-h h2 { font-size: 1.15rem; color: var(--lime); margin: 0; }
h1 { font-size: 1.15rem; color: var(--lime); margin: 0 0 .2rem; }
.sub { color: var(--muted); font-size: .82rem; margin: 0 0 .8rem; }

.card { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 1.2rem; margin-bottom: 1rem; }
.card.empty { text-align: center; padding: 2rem; }
/* Plain links inside cards are lime; buttons keep their own colours. */
.card a:not(.btn):not(.btn-primary):not(.btn-secondary):not(.btn-wa) { color: var(--lime); }
.card h2 { font-size: 1rem; color: var(--lime); margin: 0 0 .9rem; }

.subtabs { display: flex; gap: .35rem; margin-bottom: .8rem; }
.subtab, .js-tab {
    flex: 1; text-align: center; font-size: .78rem; padding: .5rem .25rem; border-radius: 9px;
    border: 1px solid var(--line); background: var(--card); color: var(--muted); cursor: pointer;
    text-decoration: none;
    /* "Clasificación final" is two words and the active tab is bold, so on a
       phone it wraps and drags the other tabs out of line with it. */
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.subtab.on, .js-tab.on { background: var(--lime); color: var(--green); border-color: var(--lime); font-weight: 700; }

/* ---- 404 / 403 / 400 ---- */

/* A dead end still gets the palette, the shell and a way out. Deliberately
   plain: it is read once, in irritation, and the only thing on it that matters
   is the button. */
.errpage { text-align: center; max-width: 30rem; margin-inline: auto; padding: 2rem 1.2rem; }
.err-code { font-size: 3rem; font-weight: 900; line-height: 1; color: var(--lime); letter-spacing: -.02em; }
.err-h { font-size: 1.15rem; margin: .6rem 0 .4rem; }
.err-b { font-size: .9rem; color: var(--muted); line-height: 1.55; margin-bottom: 1.2rem; }
.errpage .btn-primary { display: inline-block; width: auto; min-width: 12rem; }

/* An <a> wrapping the whole row: inherit the text colour so it never picks up
   the lime link colour, and keep it a block so the card layout is unchanged.

   The horizontal padding and the two gaps below are as tight as they are on
   purpose: every pixel spent here comes straight out of the team names, which
   are the only part of the row that truncates. Together they buy ~11px per
   row, which is what "Rayo Vallecano" (101px, the longest short name) was
   missing on a phone. */
.match { display: block; color: inherit; text-decoration: none;
    background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: .7rem .65rem; margin-bottom: .55rem; }
.match.finished { opacity: .85; }
.match .teams { display: flex; align-items: center; gap: .3rem; }
/* Team names must stay on ONE line: a wrapped name makes rows uneven and the
   fixture list ragged. min-width:0 lets the flex item shrink below its content
   so the ellipsis can kick in instead of forcing a second line.
   flex:1 (equal halves), not flex:1 1 auto: the middle block has to sit in the
   same place on every row or the column of scores zigzags down the list. */
.match .team {
    flex: 1; min-width: 0;
    display: flex; align-items: center; gap: .35rem;
    font-size: .86rem; font-weight: 600;
    white-space: nowrap;
}
/* The name itself is what truncates, so the crest is never clipped. */
.match .team .tname { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* PHONE TWEAK (not a tier): slightly tighter spacing on the narrowest phones.
   The display names are now short enough ("Barcelona", "Athletic") that the
   type size can stay put. */
@media (max-width: 380px) {
    .match .teams { gap: .25rem; }
    .match { padding-left: .55rem; padding-right: .55rem; }
}
.match .team.away { flex-direction: row-reverse; text-align: right; }
.match .dot { width: 20px; height: 20px; border-radius: 5px; flex: none; background: #26493788; }
.match .crestimg { width: 20px; height: 20px; object-fit: contain; flex: none; border-radius: 5px; }
.match .score { font-weight: 800; font-size: 1rem; color: var(--lime); min-width: 3.2rem; text-align: center; }
.match .score.live { color: var(--neg); font-size: .85rem; }
.match .vs { color: var(--muted); font-size: .8rem; min-width: 3.2rem; text-align: center; }
.match .kickoff, .match .kick { font-size: .7rem; color: var(--muted); text-align: center; margin-top: .35rem; }
.match .pred-row { display: flex; align-items: center; justify-content: center; gap: .5rem; font-size: .85rem;
    color: var(--muted); border-top: 1px solid var(--line); padding-top: .6rem; margin-top: .5rem; }
.match .pred-value { color: var(--ink); font-weight: 600; }
.match .pred-value.muted { color: var(--muted); font-weight: 400; font-style: italic; }
.match .pred-points { color: var(--lime); font-weight: 700; }

/* flex:none so the score block never grows into the space the team names need.
   No gap: the dash already has air around it, and 2×2.4px here is 2.4px off
   each team name — which is the difference between "Rayo Vallecano" and
   "Rayo Vallecan…" on a phone. */
.score-in { display: flex; align-items: center; gap: 0; flex: none; }
.score-in .goal-input {
    /* 34px wide, not 44: the width of this block is subtracted from the two
       team names either side of it. The touch target grows downwards instead
       (min-height below), where the room is free. */
    width: 34px; min-height: 44px; text-align: center; border-radius: 8px; border: 1px solid var(--line);
    background: var(--green); color: var(--ink); font-size: 1rem; font-weight: 700;
    padding: 0; /* Chrome's default input padding was stealing name width */
    /* type=number reserves room for the spinner arrows, which pushes the digit
       off-centre. Hiding them lets text-align:center actually centre it. */
    -moz-appearance: textfield;
    appearance: textfield;
}
.score-in .goal-input::-webkit-outer-spin-button,
.score-in .goal-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.score-in .dash { color: var(--muted); }

/* Touch targets, all three of them: 44px is the smallest square a thumb hits
   reliably, and this row is centred with room to spare on either side, so the
   arrows can take it in both directions without moving anything. */
.jornada-select { display: flex; align-items: center; justify-content: center; gap: .4rem; margin-bottom: 1rem; }
.jornada-select select { padding: .4rem .6rem; min-height: 44px; border-radius: 8px; border: 1px solid var(--line);
    background: var(--card); color: var(--ink); }
.jornada-nav { color: var(--lime); font-size: 1.3rem; text-decoration: none;
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; }

.rk-row { display: flex; align-items: center; gap: .6rem; padding: .6rem .55rem; border-radius: 9px;
    margin-bottom: .3rem; background: var(--card); border: 1px solid transparent; }
.rk-row.me { border-color: var(--lime); background: #16302463; }
.rk-row .pos { width: 22px; text-align: center; font-weight: 800; color: var(--muted); }
.rk-row .pos.p1 { color: var(--gold); }
.rk-row .pos.p2 { color: #cfd8dc; }
.rk-row .pos.p3 { color: #e0a06a; }
.rk-row .av { width: 28px; height: 28px; border-radius: 50%; background: linear-gradient(135deg, #2d6a45, #173626);
    color: var(--lime); font-weight: 700; font-size: .7rem; display: grid; place-items: center; flex: none; }
.rk-row .nm { font-size: .88rem; font-weight: 600; flex: 1; }
.rk-row.me .nm { color: var(--lime); }
.rk-row .p { font-weight: 800; font-size: .95rem; }
.rk-row .ppts { font-weight: 600; font-size: .78rem; color: var(--muted); margin-right: .2rem; }

.rank-header { display: flex; padding: 0 .55rem .4rem; font-size: .72rem; color: var(--muted); text-transform: uppercase; }
.rank-header .col-pos { width: 22px; text-align: center; }
.rank-header .col-name { flex: 1; padding-left: 2.3rem; }
.rank-header .col-pts { font-weight: 700; }

/* ---- Predictions: by-date grouping, autosave feedback, copy dialog ---- */

.daysep { display: flex; align-items: center; gap: .5rem; margin: .9rem 0 .5rem; }
.daysep span { font-size: .68rem; text-transform: uppercase; letter-spacing: .1em;
    color: var(--muted); font-weight: 800; white-space: nowrap; }
.daysep i { flex: 1; height: 1px; background: var(--line); }

.match .mtop { display: flex; align-items: center; justify-content: space-between;
    gap: .5rem; font-size: .66rem; color: var(--muted); margin-bottom: .45rem; }
/* Under "Por jornada" this carries the whole date, not just the hour, so it
   needs room to shrink before it collides with the badge. */
.match .mtop > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jbadge { flex: none; border: 1px solid var(--line); border-radius: 999px; padding: .05rem .45rem; font-weight: 700; }
/* A match played out of its own matchday: the case the by-date view exists for. */
.match.late { border-color: #5a4a1e; background: #1a1710; }
.jbadge.late { border-color: var(--gold); color: var(--gold); }

/* The gold "you are missing predictions" card: the one thing on Inicio that
   asks the user to act, so it is the only block allowed to shout. */
.missing-card { border-color: #5a4a1e; background: #1a1710; }
.missing-h { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em;
    color: var(--gold); font-weight: 800; margin-bottom: .35rem; }
.missing-b { font-size: .86rem; line-height: 1.5; margin-bottom: .8rem; }
.daysep .live-h { color: var(--neg); }
.dash-cta { display: block; text-align: center; margin-top: .7rem; }

/* Shown when a background save comes back 401. Pinned above the footer so it
   is seen without scrolling, whichever row the save failed on. */
.session-gone {
    position: fixed; left: 50%; transform: translateX(-50%);
    bottom: calc(var(--foot-h, 4rem) + .8rem); z-index: 40;
    width: min(560px, calc(100vw - 1.6rem));
    display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
    background: #2a1618; border: 1px solid #7a2f36; color: #ffd9dc;
    border-radius: 12px; padding: .75rem .9rem; font-size: .82rem;
    box-shadow: 0 12px 34px rgba(0, 0, 0, .5);
}
.session-gone span { flex: 1; min-width: 0; }
.session-gone .btn { flex: none; }

.save-state { font-size: .68rem; margin-top: .35rem; min-height: .9rem; }
.save-state.saving { color: var(--muted); }
.save-state.ok { color: var(--lime); }
.save-state.err { color: var(--neg); }

/* Tabs on the left, Sincronizar on the right — one row, so the control is
   visible from the top of the page in both views. */
/* Tabs and Sincronizar stack by default and only share a row when there is
   genuinely space. Three tabs — "Clasificación final" is the long one — plus a
   button leaves each tab about 60px on a phone, which is not enough for their
   labels, so they wrap and the row falls apart. */
.subtabs-row { display: flex; flex-direction: column; align-items: stretch;
    gap: .5rem; margin-bottom: .8rem; }
.subtabs-row .subtabs { margin-bottom: 0; min-width: 0; }
.btn-sync { display: inline-flex; align-items: center; justify-content: center;
    gap: .35rem; padding: .5rem .8rem; font-size: .78rem; white-space: nowrap; }
.btn-sync svg { flex: none; }

/* From the tablet tier up they share a row again — see the TABLET+ block. */

.sync-dialog { width: 25rem; }
.sync-dirs { display: grid; gap: .4rem; margin-bottom: .8rem; }
.sync-dir { display: flex; align-items: flex-start; gap: .55rem; padding: .55rem .6rem;
    border: 1px solid var(--line); border-radius: 10px; cursor: pointer; }
.sync-dir:has(input:checked) { border-color: var(--lime); background: #16281f; }
.sync-dir input { width: 17px; height: 17px; flex: none; margin-top: .1rem; accent-color: var(--lime); }
.sync-dir strong { display: block; font-size: .86rem; }
.sync-dir em { display: block; font-style: normal; font-size: .74rem; color: var(--muted); margin-top: .1rem; }
.sync-leagues { border-top: 1px solid var(--line); padding-top: .6rem; }
.sync-leagues .cd-item input { width: 17px; height: 17px; flex: none; accent-color: var(--lime); }

/* A profile picture fills whichever avatar circle it lands in — the drawer,
   the ranking table and the ranking cards each size .av differently, so the
   image takes the shape rather than carrying one of its own. */
.av { overflow: hidden; }
.av img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }

/* The one notice that should feel like an alarm rather than an update: the
   deadline moving is what a league owner would use to reopen their own final
   table quietly. Gold, above everything, and impossible to scroll past. */
.dl-change { border-color: var(--gold); background: #1a1710; margin-bottom: .8rem; }
.dlc-h { color: var(--gold); font-weight: 800; font-size: .92rem; margin: 0 0 .4rem; }
.dlc-b { font-size: .86rem; line-height: 1.6; margin: 0 0 .5rem; color: var(--ink); }
.dlc-b strong { color: var(--gold); }
.dlc-f { font-size: .78rem; color: var(--muted); margin: 0; }
.dlc-f a { color: var(--lime); white-space: nowrap; }

/* ---- Inicio: position and the two deadlines ---- */

.hero-card { padding-bottom: .8rem; }
.hero-position { font-size: .95rem; color: var(--muted); margin: 0 0 .1rem; }
.hero-position strong { color: var(--lime); font-size: 1.5rem; font-weight: 800; }
.hero-points { font-size: .82rem; color: var(--muted); margin: 0; }

/* Both deadlines are one-way doors, so they get a permanent place rather than
   a warning that only shows up once it is nearly too late. */
.hero-deadlines { display: grid; gap: .5rem; margin-top: .9rem;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.hd { display: block; padding: .55rem .65rem; border-radius: 10px;
    border: 1px solid var(--line); background: var(--green); text-decoration: none; }
.hd .hd-l { display: block; font-size: .68rem; text-transform: uppercase;
    letter-spacing: .06em; color: var(--muted); }
.hd .hd-v { display: block; font-size: .95rem; font-weight: 800; color: var(--ink); margin: .1rem 0; }
.hd .hd-d { display: block; font-size: .7rem; color: var(--muted); }
.hd.urge { border-color: var(--gold); background: #1a1710; }
.hd.urge .hd-v { color: var(--gold); }
.hd.closed { opacity: .72; }

/* ---- Predicted final table ---- */

.ft-note { font-size: .8rem; color: var(--muted); line-height: 1.55;
    background: var(--card); border: 1px solid var(--line); border-radius: 10px;
    padding: .7rem .8rem; margin-bottom: .8rem; }
.ft-note strong { color: var(--ink); }
.ft-note.locked { border-color: #5a4a1e; background: #1a1710; color: #e8d9a8; }
.ft-note a { color: var(--lime); white-space: nowrap; }

.ft-list { list-style: none; margin: 0 0 .8rem; padding: 0;
    border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
/* .25rem of vertical padding, not .5: the ▲/▼ buttons now stand 44px tall
   (see .ft-moves) and set the row height on their own. Keeping the old padding
   would have added 20 rows × 14px of slack to a list you reorder by eye. */
.ft-row { display: flex; align-items: center; gap: .5rem; padding: .25rem .7rem;
    background: var(--card); border-bottom: 1px solid rgba(29, 58, 44, .5);
    /* The zone stripe: a left border that changes as the row moves. */
    border-left: 3px solid transparent; }
.ft-row:last-child { border-bottom: none; }
.ft-list:not(.locked) .ft-row { cursor: grab; }
.ft-row.dragging { opacity: .4; }
.ft-pos { flex: none; width: 1.4rem; text-align: right; font-weight: 800;
    font-size: .8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.ft-row .crestimg { width: 22px; height: 22px; object-fit: contain; flex: none; }
.ft-name { flex: 1; min-width: 0; font-weight: 600; font-size: .88rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ft-grip { flex: none; color: var(--muted); font-size: 1rem; cursor: grab; }
.ft-moves { flex: none; display: flex; gap: .2rem; }
/* 44×44: this is the accessible way to reorder the table on a phone — the
   alternative is a drag, which is exactly what someone who cannot drag needs
   an alternative to. Too small to hit, it is not an alternative at all. */
.ft-moves button { width: 44px; height: 44px; border-radius: 7px; cursor: pointer;
    border: 1px solid #2f5943; background: #16281f; color: var(--ink); font-size: .62rem; }
.ft-moves button:active { background: #1c3327; }

/* Zones. Colour carries the meaning, so the legend below names each one. */
.ft-row.z-ch  { border-left-color: var(--lime); }
.ft-row.z-ue  { border-left-color: #4a9fd8; }
.ft-row.z-cf  { border-left-color: #4ad8a0; }
.ft-row.z-rel { border-left-color: #d8564a; }

.ft-state { font-size: .76rem; color: var(--muted); }
.ft-state.ok { color: var(--lime); }
.ft-state.err { color: #ffb4ba; }
.ft-state.dirty { color: var(--gold); }

.ft-legend { display: flex; flex-wrap: wrap; gap: .8rem; font-size: .72rem;
    color: var(--muted); margin-bottom: .5rem; }
.ft-legend span { display: inline-flex; align-items: center; gap: .35rem; }
.ft-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.ft-legend i.z-ch  { background: var(--lime); }
.ft-legend i.z-ue  { background: #4a9fd8; }
.ft-legend i.z-cf  { background: #4ad8a0; }
.ft-legend i.z-rel { background: #d8564a; }
.ft-foot { font-size: .72rem; color: var(--muted); line-height: 1.5; }

/* The predicted table is capped in the TABLET+ block and kept to ONE column on
   purpose: splitting twenty rows into two would put 11th at the top of the
   right-hand column, so dragging a team "down" past 10th would mean dragging
   it up and across. */

.sync-conf-h { font-size: .8rem; margin: .2rem 0 .5rem; }
/* Sits above the rows it governs and reads as a header, not another fixture. */
.sync-all { display: flex; align-items: center; gap: .55rem; padding: .4rem 0 .5rem;
    font-size: .78rem; font-weight: 700; color: var(--muted);
    border-bottom: 1px solid var(--line); cursor: pointer; }
.sync-all input { width: 17px; height: 17px; flex: none; accent-color: var(--lime); }
.sync-conf { display: flex; align-items: center; gap: .55rem; padding: .45rem 0;
    border-bottom: 1px solid rgba(29, 58, 44, .5); font-size: .82rem; cursor: pointer; }
.sync-conf input { width: 17px; height: 17px; flex: none; accent-color: var(--lime); }
.sc-teams { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-scores { flex: none; display: inline-flex; align-items: center; gap: .3rem;
    font-variant-numeric: tabular-nums; color: var(--muted); }
.sc-scores b { color: var(--ink); }
.sc-scores i { font-style: normal; color: var(--lime); }
.sync-done { color: var(--lime); font-size: .88rem; }

/* A <dialog> is centred by its own `margin: auto`, which a global margin reset
   silently overrides — that is how this ended up pinned to the top-left. Fixed
   positioning states the intent outright instead of relying on that default. */
.copy-dialog {
    position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
    margin: 0; border: 1px solid var(--line); background: var(--card); color: var(--ink);
    border-radius: 14px; padding: 0; width: 21.25rem; max-width: calc(100vw - 2rem);
    max-height: calc(100dvh - 3rem); overflow: auto;
    box-shadow: 0 18px 50px rgba(0, 0, 0, .55);
}
.copy-dialog::backdrop { background: rgba(0, 0, 0, .6); }
.cd-head { padding: .8rem; border-bottom: 1px solid var(--line); font-weight: 800; font-size: .92rem; }
.cd-body { padding: .8rem; }
.cd-note { font-size: .76rem; color: var(--muted); margin-bottom: .6rem; line-height: 1.5; }
.cd-note strong { color: var(--ink); }
.cd-item { display: flex; align-items: center; gap: .5rem; padding: .4rem 0; font-size: .86rem; cursor: pointer; }
/* Without this the boxes render in the OS blue, which fights the whole palette. */
.cd-item input { width: 18px; height: 18px; flex: none; accent-color: var(--lime); }
.cd-foot { padding: .7rem .8rem; border-top: 1px solid var(--line); display: flex; gap: .5rem; justify-content: flex-end; }

/* ---- General ranking table ---- */

/* Scrolls sideways on a phone: position, player, the two season point columns
   and the running jornada fit — which is what people open this screen for. The
   rest (quinielas, plenos, goals) is a swipe away.

   And it SAYS so. Four background layers, the classic scroll-shadow trick:
   two "shadow" layers pinned to the edges (attachment: scroll) and two
   opaque "cover" layers that ride with the content (attachment: local). At
   scroll position 0 the left cover hides the left shadow; scroll to the end
   and the right cover hides the right one. So the fade is visible exactly
   when there is something hidden — no JS, and it turns itself off from the
   tablet tier up, where the table stops overflowing. The cover colour has to
   be the page background, not transparent, or it hides nothing. */
.rk-scroll {
    max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; margin: 0 -.15rem;
    background-image:
        linear-gradient(to right,  #0b1712 55%, rgba(11, 23, 18, 0)),
        linear-gradient(to left,   #0b1712 55%, rgba(11, 23, 18, 0)),
        linear-gradient(to right,  rgba(198, 242, 78, .16), rgba(198, 242, 78, 0)),
        linear-gradient(to left,   rgba(198, 242, 78, .16), rgba(198, 242, 78, 0));
    background-position: left center, right center, left center, right center;
    background-repeat: no-repeat;
    background-size: 20px 100%, 20px 100%, 18px 100%, 18px 100%;
    background-attachment: local, local, scroll, scroll;
}
/* Ten short columns, one of them the running jornada. Full width on a phone,
   where the table is wider than the screen and .rk-scroll handles the rest;
   from the tablet tier up it shrink-to-fits instead (see the TABLET+ block),
   because a table told to be 44rem wide just moves the emptiness inside it. */
.rk-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
.rk-table th, .rk-table td { padding: .55rem .4rem; white-space: nowrap; }
.rk-table thead th {
    font-size: .68rem; font-weight: 700; letter-spacing: .04em; color: var(--muted);
    border-bottom: 1px solid var(--line); text-align: right;
}
.rk-table thead th.c-pos, .rk-table thead th.c-name { text-align: left; }
.rk-table tbody tr { border-bottom: 1px solid rgba(29, 58, 44, .5); }
.rk-table tbody tr:last-child { border-bottom: none; }
.rk-table tbody tr.me { background: #16302463; }
.rk-table tbody tr.me .nm { color: var(--lime); font-weight: 700; }

.rk-table .c-pos { width: 1.6rem; text-align: center; font-weight: 800; color: var(--muted); }
.rk-table .c-pos.p1 { color: var(--gold); }
.rk-table .c-pos.p2 { color: #cfd8dc; }
.rk-table .c-pos.p3 { color: #e0a06a; }
/* The cell stays a table cell. Making it a flex container takes it out of the
   table layout, so its column stops sharing a width with the header and every
   row lines up differently — the layout falls apart the moment there are two
   players. The avatar and name are laid out by an inner wrapper instead. */
.rk-table .c-name { font-weight: 600; width: 100%; }
/* Names link to the player's card. Inherit the row's colour rather than the
   lime link colour, so a whole table of names does not read as a list of links. */
.rk-table .c-name .who { display: flex; align-items: center; gap: .45rem; min-width: 0;
    text-decoration: none; color: inherit; }
a.rk-row { text-decoration: none; color: inherit; }
.rk-table .c-name .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rk-table .c-name .av {
    width: 26px; height: 26px; border-radius: 50%; flex: none;
    background: linear-gradient(135deg, #2d6a45, #173626);
    display: grid; place-items: center; font-size: .64rem; font-weight: 800;
}
.rk-table .c-num { text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); }
/* The league's official points column is the one that decides the order. */
.rk-table .c-official { color: var(--ink); font-weight: 800; font-size: .95rem; }
.rk-table thead th.c-official { color: var(--lime); }

/* Points banked so far in the jornada being played. Brighter than the season
   stats it sits among, never brighter than the official column that decides
   the order. */
.rk-table .c-md { color: var(--ink); }
.rk-table thead th.c-md { color: var(--ink); }

/* ---- Clasificación en vivo -----------------------------------------------
   Only ever on screen while a match is being played. It borrows the ficha de
   partido's vocabulary on purpose — the same orange pulsing dot for "right
   now" and the same lime for points won — because the two screens are showing
   the same thing at two zoom levels, and inventing a second colour code for
   it would make them look like different features. */

/* The line that says the table below is a projection, not a result. Sits
   between the subtitle and the table, quiet enough not to compete with it. */
.rk-live-note {
    display: flex; flex-wrap: wrap; align-items: center; gap: .35rem;
    font-size: .76rem; color: var(--muted); line-height: 1.5;
    margin: -.3rem 0 .7rem;
}
.rk-live-note strong { color: var(--ink); font-weight: 700; }
.rk-live-badge {
    display: inline-flex; align-items: center; gap: .3rem;
    font-size: .62rem; font-weight: 800; letter-spacing: .08em; color: var(--neg);
    background: rgba(224, 112, 58, .14); border: 1px solid rgba(224, 112, 58, .45);
    border-radius: 999px; padding: .14rem .45rem; white-space: nowrap;
}

/* Movement since the live matches kicked off. Rides inside the position cell
   rather than taking a column of its own: on a 390px phone the table is
   already wider than the screen, and an eleventh column would push the points
   further out of sight to say something that belongs next to the number it
   modifies. Its own colour, so the gold/silver/bronze of the top three does
   not paint it. */
.rk-arrow { font-size: .62rem; font-weight: 800; margin-left: .12rem;
    vertical-align: .06em; letter-spacing: -.02em; }
.rk-arrow.up   { color: var(--lime); }
.rk-arrow.down { color: var(--neg); }

/* Points still in play, inside the total that already counts them. Lime is
   "points you have earned" everywhere in the app (see .md-rival-pts.scored);
   lighter and smaller than the total, because it is a part of it, not a
   second figure to add. */
.rk-prov { font-size: .68rem; font-weight: 700; color: var(--lime); margin-left: .18rem; }

/* Available to a screen reader, invisible to everyone else. The arrows are the
   first thing on this screen whose whole meaning is a glyph and a colour, and
   neither reaches someone listening to the page. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* A definition list in disguise, so it is laid out like one: a two-column grid
   with the key in the first column and the description in the second.
   display:contents dissolves each <p> so its <strong> and its text become the
   two grid cells of that row.

   The old shape — inline-block strong with a min-width — only ever indented
   the FIRST line. "En J3" is the entry that wraps on a phone, and its second
   line ("los partidos") landed back on the left margin, under the key instead
   of under its own text. A grid track cannot do that, and it also sizes itself
   to the longest key instead of to a magic number. */
.rk-legend { margin-top: .9rem; font-size: .75rem; color: var(--muted); line-height: 1.6;
    display: grid; grid-template-columns: auto 1fr; column-gap: .5rem; }
.rk-legend p { margin: 0; display: contents; }
.rk-legend strong { color: var(--ink); white-space: nowrap; }
/* A sentence, not a key: it spans both tracks and keeps a normal left edge. */
.rk-legend .rk-tiebreak { display: block; grid-column: 1 / -1;
    margin-top: .5rem; padding-top: .5rem; border-top: 1px solid var(--line); }

/* Foot of the Clasificación screen: one jornada on its own, and where the real
   league table lives. Deliberately quiet — this screen is the pool ranking and
   nothing should compete with it, but a signpost costs one line. */
.rk-foot { margin-top: 1rem; padding-top: .7rem; border-top: 1px solid var(--line);
    font-size: .78rem; color: var(--muted); line-height: 1.6; }
.rk-foot p { margin: 0; }
.rk-foot a { color: var(--lime); }

/* ---- Diario: a sports-paper front page ---- */

.paper {
    background: #f4f1e8; color: #16130d; border-radius: 12px;
    padding: 1.1rem 1rem 1.3rem; margin-bottom: 1rem;
    font-family: Georgia, 'Times New Roman', serif;
}
.paper-head { text-align: center; border-bottom: 3px double #16130d; padding-bottom: .7rem; margin-bottom: 1rem; }
/* The masthead scales with the page instead of stepping at a breakpoint: a
   newspaper name is the one thing that should look set for the sheet it is on. */
.paper-name {
    font-size: clamp(1.75rem, 4.4vw, 3.2rem); line-height: 1.05; margin: .1rem 0 .3rem;
    letter-spacing: -.02em; font-weight: 900; color: #16130d; text-transform: uppercase;
    overflow-wrap: break-word;
}
.paper-date { font-size: .7rem; color: #5c5647; letter-spacing: .06em; text-transform: uppercase; margin: 0; }
.paper-kicker {
    font-family: system-ui, sans-serif; font-size: .62rem; font-weight: 800;
    letter-spacing: .14em; text-transform: uppercase; color: #9a3412; margin: 0 0 .25rem;
}

.paper-lead { border-bottom: 1px solid #cfc8b6; padding-bottom: 1rem; margin-bottom: 1rem; }
.paper-headline { font-size: clamp(1.35rem, 2.6vw, 2.2rem); line-height: 1.15; margin: 0 0 .5rem; font-weight: 900; letter-spacing: -.01em; }
.paper-subhead { font-size: 1.02rem; line-height: 1.2; margin: 0 0 .35rem; font-weight: 800; }
.paper-body { font-size: .92rem; line-height: 1.55; margin: 0; color: #2b2618; }
.paper-lead .paper-body::first-letter {
    float: left; font-size: 2.8rem; line-height: .82; padding: .1rem .35rem 0 0; font-weight: 900;
}

.paper-story { border-bottom: 1px solid #ddd6c4; padding-bottom: .85rem; margin-bottom: .85rem; }
.paper-story:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }

.paper-empty { text-align: center; padding: 1rem 0; }
.paper-empty h2 { font-size: 1.25rem; margin: 0 0 .5rem; font-weight: 900; }
.paper-empty p { font-size: .9rem; line-height: 1.55; color: #2b2618; margin: 0; }

/* ---- Real competition table (Resultados) ---- */

/* A league table is 10 short columns. Left to fill a wide window it turns into
   a scatter of digits with a void between the crest and PJ. The 40rem cap only
   moved that void inside the name column (measured: 640px table, 281px name
   cell, ~200px of nothing), so from the tablet tier up the table shrink-to-fits
   instead — see the TABLET+ block. Here it stays full width, for the phone. */
.rt-table { width: 100%; max-width: 40rem;
    border-collapse: collapse; font-size: .82rem; }
.rt-table th, .rt-table td { padding: .45rem .35rem; white-space: nowrap; }
.rt-table thead th {
    font-size: .64rem; font-weight: 700; letter-spacing: .04em; color: var(--muted);
    border-bottom: 1px solid var(--line); text-align: right;
}
.rt-table thead th.c-pos, .rt-table thead th.c-name { text-align: left; }
.rt-table tbody tr { border-bottom: 1px solid rgba(29, 58, 44, .5); }
.rt-table tbody tr:last-child { border-bottom: none; }
.rt-table .c-pos { width: 1.5rem; text-align: center; color: var(--muted); font-weight: 700; }
/* Numeric columns only need room for two digits, so cap them and let the name
   take the slack — otherwise the table spreads its width evenly and leaves a
   gulf between the crest and PJ on a wide screen. */
.rt-table .c-num { width: 2.6rem; }
/* Same reasoning as .rk-table .c-name: a flex td leaves the table layout. */
.rt-table .c-name { font-weight: 600; }
.rt-table .c-name .who { display: flex; align-items: center; gap: .4rem; min-width: 0; }
.rt-table .c-name .tname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rt-table .c-name .crestimg { width: 18px; height: 18px; object-fit: contain; flex: none; }
.rt-table .c-num { text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); }
.rt-table .c-pts { color: var(--lime); font-weight: 800; }

.badge-open { text-align: center; font-size: .78rem; color: var(--muted); background: var(--card);
    border: 1px solid var(--line); border-radius: 999px; padding: .25rem .8rem; display: inline-block;
    margin: 0 auto .8rem; width: fit-content; }

.form-card label { display: block; font-size: .85rem; color: var(--muted); margin: .9rem 0 .3rem; }
.form-card label:first-child { margin-top: 0; }
.form-card input[type="text"] {
    width: 100%; padding: .6rem .75rem; border-radius: 8px; border: 1px solid var(--line);
    background: var(--green); color: var(--ink); font-size: 1rem;
}
.form-card button[type="submit"] {
    width: 100%; margin-top: 1rem; padding: .7rem; border: none; border-radius: 8px;
    background: var(--lime); color: var(--green); font-weight: 700; font-size: 1rem; cursor: pointer;
}
.error {
    background: rgba(232, 121, 91, .12); border: 1px solid rgba(232, 121, 91, .4); color: #e8795b;
    border-radius: 8px; padding: .6rem .8rem; font-size: .88rem; margin-bottom: 1rem;
}
.success {
    background: rgba(198, 242, 78, .12); border: 1px solid rgba(198, 242, 78, .4); color: var(--lime);
    border-radius: 8px; padding: .6rem .8rem; font-size: .88rem; margin-bottom: 1rem;
}
.alt { text-align: center; margin-top: 1.3rem; font-size: .9rem; color: var(--muted); }
.alt a { color: var(--lime); }
.legal-consent { text-align: center; margin-top: .9rem; font-size: .76rem;
    color: var(--muted); line-height: 1.5; }
.legal-consent a { color: var(--lime); }
.nav-links { margin-top: 1.2rem; text-align: center; }
.nav-links a { color: var(--lime); font-size: .9rem; }

.btn, .btn-secondary, .btn-primary {
    display: inline-block; padding: .6rem 1rem; border-radius: 8px;
    font-weight: 700; font-size: .9rem; text-decoration: none; text-align: center; border: none; cursor: pointer;
}
.btn, .btn-primary { background: var(--lime); color: var(--green); }
/* Transparent with a hairline border read as decoration — people could not
   tell "Avisarme cuando me falten pronósticos" was a button at all. Solid
   fill and a lit border make it obviously pressable while staying clearly
   below the lime primary. */
.btn-secondary {
    background: #1e3a2c; border: 1px solid #4a7c5d; color: #dff5c8;
    transition: background .15s ease, border-color .15s ease;
}
.btn-secondary:hover, .btn-secondary:focus-visible { background: #26493a; border-color: var(--lime); }
.btn-secondary:active { background: #182f24; }
.btn-wa { display: inline-flex; align-items: center; gap: .4rem; background: #25d366; color: #fff;
    padding: .5rem 1rem; border-radius: 8px; font-weight: 700; font-size: .9rem; text-decoration: none; }
.btn-wa svg { flex: none; }

/* ---- Match detail ---- */

.md-hero { padding: 1rem .8rem .85rem; }
.md-teams { display: flex; align-items: flex-start; gap: .5rem; }
.md-side { flex: 1; display: flex; flex-direction: column; align-items: center; gap: .4rem; text-align: center; }
.md-crest { width: 46px; height: 46px; object-fit: contain; }
.md-team { font-size: .82rem; font-weight: 700; line-height: 1.2; }
.md-score-box { display: flex; flex-direction: column; align-items: center; gap: .3rem; min-width: 6.2rem; }
.md-score { font-size: 2.1rem; font-weight: 800; color: var(--lime); letter-spacing: -.02em; line-height: 1; }
.md-score.md-vs { font-size: 1.1rem; color: var(--muted); font-weight: 700; }
.md-dash { color: var(--muted); margin: 0 .25rem; font-weight: 400; }
.md-live {
    display: inline-flex; align-items: center; gap: .3rem;
    font-size: .64rem; font-weight: 800; letter-spacing: .08em; color: var(--neg);
    background: rgba(224, 112, 58, .14); border: 1px solid rgba(224, 112, 58, .45);
    border-radius: 999px; padding: .16rem .5rem; white-space: nowrap;
}
.md-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--neg); animation: mdpulse 1.4s ease-in-out infinite; }
@keyframes mdpulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .md-dot { animation: none; } }
/* Half time is "in play" for the score but nothing is happening on the pitch,
   so the badge stops shouting: muted colour and a dot that does not beat. */
.md-live.md-paused { color: var(--muted); background: rgba(157, 176, 164, .12); border-color: rgba(157, 176, 164, .35); }
.md-live.md-paused .md-dot { background: var(--muted); animation: none; }
.md-state { font-size: .72rem; color: var(--muted); white-space: nowrap; }
.md-meta { margin-top: .8rem; padding-top: .7rem; border-top: 1px solid var(--line);
    font-size: .72rem; color: var(--muted); text-align: center; }

.md-timeline { padding: .35rem .5rem; }
.md-ev { display: flex; align-items: baseline; gap: .5rem; padding: .5rem .3rem;
    border-bottom: 1px solid rgba(29, 58, 44, .55); }
.md-ev:last-child { border-bottom: none; }
.md-ev.away { flex-direction: row-reverse; text-align: right; }
.md-ev-min { font-size: .74rem; font-weight: 800; color: var(--lime); min-width: 2.3rem; flex: none; }
.md-ev.away .md-ev-min { text-align: right; }
.md-ev-icon { font-size: .82rem; flex: none; }
.md-ev-body { flex: 1; display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem; }
.md-ev.away .md-ev-body { justify-content: flex-end; }
.md-ev-player { font-size: .84rem; font-weight: 600; }
.md-ev-note { font-size: .72rem; color: var(--muted); }
.md-ev-score { font-size: .72rem; font-weight: 800; color: var(--lime);
    background: rgba(198, 242, 78, .1); border-radius: 4px; padding: .05rem .3rem; }

/* ---- Match detail: how the league stands on this match ---- */

.md-tabs { margin-top: .9rem; }
.md-league-pick { display: flex; align-items: center; gap: .4rem; margin-bottom: .6rem; font-size: .72rem; color: var(--muted); }
.md-league-pick select { flex: 1; background: var(--card); color: var(--ink);
    border: 1px solid var(--line); border-radius: 9px; padding: .4rem .5rem; font-size: .82rem; }

.md-rivals { padding: .5rem .6rem; }
.md-rivals-h { display: flex; justify-content: space-between; font-size: .66rem;
    color: var(--muted); text-transform: uppercase; letter-spacing: .06em; margin-bottom: .35rem; }
.md-rival { display: flex; align-items: center; gap: .5rem; padding: .45rem 0;
    border-bottom: 1px solid rgba(29, 58, 44, .5); font-size: .86rem; }
.md-rival:last-child { border-bottom: none; }
.md-rival.me .md-rival-nm { color: var(--lime); font-weight: 700; }
.md-rival-pos { width: 1.2rem; color: var(--muted); font-weight: 800; }
.md-rival-nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.md-rival-pred { color: var(--muted); font-size: .8rem; font-variant-numeric: tabular-nums; }
.md-rival-pts { font-weight: 800; font-size: .8rem; color: var(--muted); min-width: 2.2rem; text-align: right; }
.md-rival-pts.scored { color: var(--lime); }
.md-live-note { font-size: .72rem; color: var(--neg); margin-top: .5rem; }

/* ---- Match detail: la general, the porra while the match is being played ----

   Rendered only mid-match, and it is not a new table: it is the Clasificación
   screen's own .rk-table — same medals, same ▲▼, same "(+n)" — with the season
   columns dropped, so nothing has to be kept in step by hand.

   No card around it, unlike the rivals list next door. Twice tried and twice
   wrong: .rk-scroll paints its scroll hints in the PAGE colour, so a card
   background shows through them as two dark bands; and ".card a:not(.btn)"
   turns every plain link lime, which on a column of names lights up the whole
   league as if every row were you. On the page background both problems are
   simply not there, and it reads as what it is — the same table, borrowed. */
.md-gen-foot { font-size: .78rem; margin-top: .8rem; }
.md-gen-foot a { color: var(--lime); }

/* FOUR tabs, which only ever happens while a match is on. The strip divides
   evenly, so at 390px each tab gets an 86px box, and "Alineaciones" is the
   label that decides everything. Measured, at .78rem: 81px unselected — five
   pixels of room — and 87px once it is the selected tab, because the selected
   tab is bold. So it clips exactly when you are reading it, and on a 360px
   phone it clips either way.

   Scrolling the strip was the alternative and it is worse: a tab you have to
   discover by dragging is a tab nobody opens, and the one off the edge would
   be the new one. So the type and the side padding shrink instead — 74px into
   an 80px box in the worst case measured (360px, selected) — and only in the
   phone tier: from 700px up the tabs size to their own labels and this is
   undone. */
   Competiciones carries the same problem and the same answer, with a worse
   worst case ("Clasificación", one character longer than "Alineaciones"), so
   it shares the rule rather than growing a second copy of it that could drift.
   The two class names are kept apart because the strips are: one belongs to
   the match detail, the other to a screen with no match on it. */
.md-tabs-4, .subtabs-4 { gap: .25rem; }
.md-tabs-4 .subtab,
.subtabs-4 .subtab { font-size: .68rem; padding-left: .15rem; padding-right: .15rem; }

.md-xi { padding: .85rem .8rem; }
.md-xi-head { display: flex; align-items: center; gap: .5rem; margin-bottom: .2rem; }
.md-xi-team { font-size: .88rem; font-weight: 800; color: var(--lime); }
.md-xi-formation { margin-left: auto; font-size: .7rem; font-weight: 700; color: var(--muted);
    border: 1px solid var(--line); border-radius: 999px; padding: .1rem .45rem; }
.md-xi-coach { font-size: .72rem; color: var(--muted); margin-bottom: .6rem; }
.md-player { display: flex; align-items: center; gap: .55rem; padding: .3rem 0; font-size: .82rem; }
.md-num { min-width: 1.4rem; font-size: .72rem; font-weight: 800; color: var(--muted); text-align: right; flex: none; }
.md-pname { flex: 1; }
.md-pos { font-size: .68rem; color: var(--muted); }
.md-bench-h { margin-top: .7rem; padding-top: .6rem; border-top: 1px solid var(--line);
    font-size: .68rem; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); font-weight: 700; }
.md-bench { font-size: .76rem; color: var(--muted); line-height: 1.5; margin-top: .25rem; }

/* The topbar nav belongs to the tablet tier and up; on a phone the bottom bar
   owns it. Hidden here rather than shown there so the phone is the default. */
.top-nav { display: none; }

.push-btn { display: block; width: 100%; margin-top: .8rem; }

/* ---- Competiciones (informational screens) ----
   The widget's own styling lives in widget.css, which only these screens load.
   What is here is the Golorum furniture around it: the header, the line that
   explains which day the widget was opened on, and the drawer entries. */

/* The area (España / Europa) sits opposite the name in the page header, where
   .page-h already puts a second item on the baseline. */
.comp-area { font-size: .68rem; text-transform: uppercase; letter-spacing: .09em;
    color: var(--muted); border: 1px solid var(--line); border-radius: 999px; padding: .1rem .5rem; }

/* Why the screen opened where it did. Without it, a calendar that opens on
   last Sunday looks like a bug rather than a decision. */
.comp-focus { font-size: .78rem; color: var(--muted); line-height: 1.5;
    margin: 0 0 .7rem; padding-left: .6rem; border-left: 2px solid var(--lime); }
.comp-focus b { color: var(--ink); font-weight: 700; }

/* A caveat under a widget, in the app's own voice rather than the library's. */
.comp-note { font-size: .72rem; color: var(--muted); line-height: 1.5; margin: .6rem 0 0; }

/* A closing line under a list: "los 20 primeros", the way back from a match. */
.comp-foot { font-size: .78rem; color: var(--muted); margin: .8rem 0 0; }

/* ---- What a competition fixture has and a pool fixture does not ----------
   The rows themselves are the shared .match component (see
   templates/partials/comp_match.php for why). These three rules are the whole
   difference: a live marker, a place for the badges, and an arrow that has
   nowhere to go. */

/* "EN VIVO" where a scheduled row shows its kickoff time. Bold and in the
   warning colour because it is the one thing on the screen worth interrupting
   a scan for — the same --neg the live score already uses, so the row reads as
   one state and not two. */
.live-chip {
    font-size: .6rem; font-weight: 800; letter-spacing: .06em;
    color: var(--neg); border: 1px solid var(--neg); border-radius: 999px;
    padding: .05rem .4rem;
}

/* Ida/vuelta and the round name, right-aligned opposite the time. flex-end
   keeps them together against the edge when there is only one; the gap stops
   two badges touching. */
.mtop-tags { display: flex; align-items: center; justify-content: flex-end; gap: .3rem; flex: none; }

/* The first matchday has no previous and the last has no next. The arrow stays
   in the layout rather than vanishing, so the jump menu between them does not
   jump sideways as you page through the season. */
.jornada-nav.off { opacity: .25; cursor: default; }

/* The heading of an empty state, so "Todavía sin sorteo" reads as a title and
   the sentence under it as the explanation. */
.card.empty .empty-h { color: var(--lime); font-weight: 700; margin-bottom: .45rem; }
.card.empty p + p { margin-top: .6rem; }

/* Drawer: a competition entry. The square badge is the competition CODE, so it
   has to fit four characters ("SESF") — it sizes to its text instead of being
   the fixed 22px circle a league crest gets. Muted rather than lime on
   purpose: the lime crest means "a league you play in", and these are not. */
.di .comp-tag {
    min-width: 26px; height: 20px; padding: 0 .32rem; border-radius: 6px;
    font-weight: 800; font-size: .6rem; letter-spacing: .02em;
    background: rgba(198, 242, 78, .12); color: var(--lime);
    border: 1px solid var(--line); display: grid; place-items: center; flex: none;
}
/* Long names ("Supercopa de España") must not push the badge off the edge. */
.di-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.di-state { margin-left: auto; flex: none; font-size: .58rem; text-transform: uppercase;
    letter-spacing: .06em; color: var(--muted); border: 1px solid var(--line);
    border-radius: 999px; padding: .08rem .4rem; }
.di.on { background: #16302463; color: var(--lime); }

/* =========================================================================
   TABLET AND UP — 700px. Stop being a stretched phone.

   This is where the chrome changes: the sections move out of the thumb bar and
   into the topbar, exactly as the brief asked, and the threshold is low enough
   that a tablet in portrait (768) already gets it — landscape (1024+) never
   had a reason to keep a bottom bar.

   The content changes with it: one fluid column becomes auto-fill grids of
   cards. Nothing gets WIDER text, only more columns of it.
   ========================================================================= */

@media (min-width: 700px) {
    :root { --shell: 62rem; --gutter: 1.25rem; }

    /* The shell stays a shell. Its own pitch stripes are kept so the content
       column reads as the pitch and the brighter body stripes only show in the
       gutters; hairlines mark where it ends once it stops filling the window. */
    .app { border-inline: 1px solid var(--line); }

    .topbar { padding: .7rem var(--gutter) 0; }
    /* The drawer holds profile, help and log out — the league dropdown does
       not — so the trigger has to stay reachable. It moves to the right, where
       an account menu is expected on the web. */
    .topbar-main .burger { order: 3; margin-left: .55rem; }
    /* Your name sits just left of the burger, and carries the push to the right
       so the pair ends up together instead of the name floating mid-bar. */
    .topbar-main .me { order: 2; margin-left: auto; }
    /* 9rem is a phone budget. Up here the bar is 726px and more, and the league
       switch shrinks before the name does, so "Juanfe Sanahuja Muñoz" (149px)
       has no business ending in an ellipsis — it did, at 1280. */
    .topbar .me .me-name { max-width: 14rem; }
    .topbar-main .league-switch { flex: 0 1 auto; min-width: 0; }

    .top-nav {
        display: flex; gap: .35rem; margin-top: .7rem;
        border-top: 1px solid var(--line);
        /* Five sections at 700px is a tight fit in some languages. Let them
           slide rather than wrap the topbar into three rows. */
        overflow-x: auto; scrollbar-width: none;
    }
    .top-nav::-webkit-scrollbar { display: none; }
    .top-nav-item {
        display: flex; align-items: center; gap: .45rem;
        padding: .7rem clamp(.5rem, 1.6vw, 1rem); margin-bottom: -1px;
        color: var(--muted); font-size: .84rem; font-weight: 600;
        text-decoration: none; border-bottom: 2px solid transparent; white-space: nowrap;
    }
    /* The first tab sits flush with the content column below it, so the label
       of the section you are on lines up with the page heading. */
    .top-nav-item:first-child { padding-left: 0; }
    .top-nav-item svg { width: 17px; height: 17px; flex: none; }
    .top-nav-item:hover { color: var(--ink); }
    .top-nav-item.on { color: var(--lime); border-bottom-color: var(--lime); }

    /* The bottom bar is a phone pattern: from here up the sections live in the
       topbar, so the footer has nothing left to hold. Hidden rather than left
       empty and pinned — app.js then measures --foot-h as 0. */
    .app-foot { display: none; }

    .app-scroll { padding: 1.25rem var(--gutter) 2.5rem; }

    /* Under the league switch, which starts one burger-width in from the
       shell's padding. */
    .dropdown { top: 4.1rem; left: max(4.4rem, calc(50% - var(--shell) / 2 + 4.4rem)); }

    /* ---- The drawer becomes a panel hanging off its own button -------------
       On a phone this is a slide-over from the left edge, which is right: the
       burger is at that edge and the panel covers the screen it came from.

       Up here it was still pinned to the VIEWPORT's right edge while the burger
       sits at the right edge of the CONTENT COLUMN, and the two are not the
       same place: at 1920px the shell is 62rem, so the button ended up about
       330px away from the menu it opens. That reads as an unrelated panel that
       happened to appear.

       So it is anchored to the burger instead — same arithmetic as .dropdown
       above, plus --gutter because the topbar's padding insets the button from
       the shell edge — and it hangs below the topbar rather than covering it,
       so the button you just pressed stays visible under the panel it opened.

       SHOWN, NOT SLID. translateX(100%) moves a box by its own width, which
       parks it off-screen only when it is already flush against the edge. Held
       ~330px in, the same transform would leave most of the panel on screen.
       It uses the league dropdown's display + pop instead, which is also what
       makes the two account menus behave alike. */
    .drawer {
        left: auto;
        right: max(0px, calc(50% - var(--shell) / 2 + var(--gutter)));
        top: 4.1rem; bottom: auto;
        max-height: calc(100dvh - 5.5rem);
        border: 1px solid var(--line); border-radius: 14px;
        box-shadow: var(--shadow);
        overflow-y: auto; overscroll-behavior: contain;
        display: none;
    }
    .drawer.show { display: flex; animation: pop .16s ease; }
    /* The rounded top corners would otherwise be squared off by the profile
       block, which paints its own gradient right up to them. */
    .drawer .dr-top { border-radius: 14px 14px 0 0; }

    /* ---- Cards in columns ------------------------------------------------
       One definition, used by Mi perfil, Ajustes de la liga, Administración
       and the welcome screen. auto-fit means the same rule gives two columns
       on a tablet and three on a desktop with no second breakpoint. */
    .card-cols {
        grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
        gap: 1rem; align-items: start;
    }
    .card-cols > .card { margin-bottom: 0; }
    /* A full-width member of the grid: a submit button that governs every card. */
    .card-cols > .cols-full { grid-column: 1 / -1; }
    /* For cards that are paragraphs rather than fields: fewer, wider columns,
       so the measure stays near --read instead of dropping to 45 characters.
       The per-card cap matters at the width where this is still ONE column —
       without it a tablet gets a single 45em line. */
    .card-cols.cols-wide { grid-template-columns: repeat(auto-fit, minmax(26rem, 1fr)); }
    .card-cols.cols-wide > .card { max-width: 34rem; }

    /* ---- Fixtures in a grid ----------------------------------------------
       A fixture row is two team names either side of a fixed middle block, so
       the width a column needs is: 2 × (longest name + crest) + that block +
       the gaps. The longest short name in play is "Rayo Vallecano" at 101px,
       and the middle block is not the same on every screen — hence two
       thresholds rather than one, both measured rather than guessed.

       Read/played rows carry "2 – 1" (a 51px .score/.vs): 22rem is enough.
       Editable rows carry two 34px inputs and a dash (77px), which needs
       ~22.5rem — so 23rem, and the second column waits for it. Better one
       honest column than two clipped ones. */
    .match-grid, .results-list {
        display: grid; grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
        gap: .7rem; align-items: start;
    }
    .matchday-list {
        display: grid; grid-template-columns: repeat(auto-fill, minmax(23rem, 1fr));
        gap: .7rem; align-items: start;
    }
    .match-grid > .match, .matchday-list > .match, .results-list > .match { margin-bottom: 0; }

    /* A day heading must span the whole row and start a new one, or the grid
       drops it into whatever cell comes next and the matches under "SÁB 15
       AGO" end up in a different column from the heading itself. */
    .match-grid > .daysep, .matchday-list > .daysep, .results-list > .daysep {
        grid-column: 1 / -1;
        margin: 1.1rem 0 .2rem;
    }
    /* Only for the two long single lists, where the first heading opens the
       list and there is nothing above it to be separated from. Inicio is NOT
       here on purpose: it wraps every block ("En juego", "Últimos resultados",
       "Próximos partidos") in its own .match-grid, so every one of its
       headings is a :first-child and the reset welded each title to the block
       above it — measured gapAbove 0px at 768 and 1280. */
    .matchday-list > .daysep:first-child,
    .results-list > .daysep:first-child { margin-top: 0; }

    /* ---- Reading width ---------------------------------------------------
       These are the blocks that are pure prose. They stop growing at --read
       (~68 characters); the card around them may be wider, the sentence is not. */
    .sub, .hero-points, .missing-b, .ft-foot, .rk-legend, .rk-live-note, .rk-foot,
    .fc-note, .adm-preview, .dlc-b, .dlc-f, .welcome-lead, .welcome-steps,
    .paper-empty p, .md-live-note {
        max-width: var(--read);
    }
    /* Cards that are nothing but prose: the BOX tracks the text, so there is
       no half-empty card with a short measure floating inside it. */
    .card.empty, .adm-flash, .adm-search { max-width: 46rem; }

    /* Privacidad and Borrar mi cuenta are read logged out, inside .wrap. They
       are documents rather than forms, so they get a document's width and
       their cards fall into columns like everywhere else. */
    .wrap:has(.legal) { max-width: 62rem; }

    /* ---- Inicio ---------------------------------------------------------- */
    .hero-card { max-width: 46rem; }
    .missing-card { max-width: 34rem; }
    .push-btn, .dash-cta { display: inline-block; width: auto; min-width: 16rem; }
    .dash-cta { margin-top: 1rem; }

    /* ---- Clasificación ---------------------------------------------------
       Capping the table was not enough and the old comment here claimed it
       was. A cap only stops the table at 44rem; inside it, .c-name (width:100%
       on the phone tier, so short leagues fill the row) still swallowed every
       spare pixel — 704px of table with a 453px name column, ~340px of nothing
       between "Maricarmen" and her points. Measured, at both 768 and 1280.

       So from here up the tables stop being told how wide to be and take the
       width of what is in them: width:auto shrink-to-fits, max-width:100% is
       the only limit left. Phones keep width:100% — there the table is wider
       than the screen anyway and .rk-scroll does the work. */
    .rk-table, .rt-table { width: auto; max-width: 100%; }
    .rk-table .c-name { width: auto; }
    .rank-header, .rk-row { max-width: 34rem; }
    .rk-row { padding: .7rem .85rem; }

    /* ---- Pronósticos: la clasificación final ----------------------------- */
    .ft-note, .ft-list, .ft-legend { max-width: 34rem; }

    /* ---- Ficha de partido ------------------------------------------------
       Panels keep a readable width; the line-ups get the room they need to sit
       side by side, which is the one thing here that earns the extra pixels. */
    .md-hero, .md-tabs, .md-panel, .md-league-pick { max-width: 46rem; }
    .md-panel:has(> .md-lineups) { max-width: 62rem; }
    .md-lineups { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; align-items: start; }
    .md-lineups .card { margin-bottom: 0; }

    /* ---- Diario: real newspaper columns once there is width for them ------ */
    .paper { padding: 2rem 2.5rem 2.2rem; }
    .paper-lead { column-count: 2; column-gap: 2rem; }
    .paper-lead .paper-headline { column-span: all; }
    .paper-lead .paper-kicker { column-span: all; }
    .paper-cols { column-count: 2; column-gap: 2rem; }
    .paper-story { break-inside: avoid; }

    /* ---- Controls at their natural size ---------------------------------- */
    /* Tabs and the sync button share a row again, instead of stacking. */
    .subtabs-row { flex-direction: row; align-items: center; }
    .subtabs-row .subtabs { flex: 1; }
    .btn-sync { flex: none; }

    /* Tabs sit at their natural width instead of stretching into oversized
       banners. */
    .subtabs { justify-content: flex-start; }
    .subtab, .js-tab { flex: 0 0 auto; padding-left: 1.4rem; padding-right: 1.4rem; }
    /* ...which is also what undoes the four-tab squeeze: from here up a tab is
       as wide as its label, so there is nothing left to squeeze. */
    .md-tabs-4, .subtabs-4 { gap: .35rem; }
    .md-tabs-4 .subtab,
    .subtabs-4 .subtab { font-size: .78rem; padding-left: 1.4rem; padding-right: 1.4rem; }

    /* La general keeps the phone tier's full-width table, against the rule
       above that has .rk-table shrink-to-fit from here up. That rule exists
       because the Clasificación table has ten columns and a cap only moves the
       emptiness inside it; this one has three, so shrink-to-fit would leave a
       table the width of a tweet. Full width inside a narrow block instead,
       with the name column taking the slack and the figures on the right edge
       — the shape of the rivals list two panels away. */
    .md-gen { max-width: 34rem; }
    .md-gen .rk-table, .md-gen .rk-table .c-name { width: 100%; }

    /* Everything on the page hangs off the left edge of the content column, so
       the odds and ends that centre themselves on a phone stop doing it here —
       a lone centred link under a left-aligned card reads as a mistake. */
    .jornada-select, .badge-open, .alt, .nav-links {
        justify-content: flex-start; text-align: left; margin-inline: 0;
    }

    /* A form is a column, not a banner: inputs and their submit stop at a
       width a name or a password actually needs. */
    .form-card { max-width: 30rem; }
    .del-link, .adm-save { max-width: 22rem; }

    /* Wider, calmer type for the page headings. */
    .page-h h2 { font-size: 1.4rem; }
    h1 { font-size: 1.4rem; }
}

/* =========================================================================
   DESKTOP — 1100px. Same chrome, more room.

   Almost nothing changes: the shell and the gutters grow, the newspaper takes
   its third column, and the match hero scales up. Everything else was already
   an auto-fit grid, so it gains a column on its own without another rule —
   which is the point of keeping the tokens in one place.

   NOTE on the drawer: it deliberately stays a slide-over here instead of
   becoming a fixed rail. It holds Mi perfil, Cómo se puntúa, Privacidad and
   your leagues — an account menu, not navigation. The navigation is already on
   screen in the topbar, so pinning the drawer open would spend ~19rem of every
   page on links nobody needs in view, and duplicate the league switcher that
   is two clicks away in the topbar.
   ========================================================================= */

@media (min-width: 1100px) {
    :root { --shell: 75rem; --gutter: 2rem; }

    .paper-cols { column-count: 3; }
    .md-score { font-size: 2.6rem; }
    .md-crest { width: 3.875rem; height: 3.875rem; }
}

/* ── Admin tables (users, leagues) ──────────────────────────────────────────
   Shared by /admin/usuarios and /admin/ligas. Both are dense, scannable lists
   read on a phone as often as on a desktop, so the table scrolls sideways
   inside .rk-scroll rather than squeezing columns until they are unreadable. */

.adm-search {
    display: flex; gap: .4rem; margin-bottom: .8rem; flex-wrap: wrap;
}
.adm-search input[type="search"] {
    flex: 1 1 12rem; min-width: 0;
    padding: .55rem .7rem; border-radius: 8px;
    border: 1px solid var(--line); background: var(--card); color: var(--ink);
}

.adm-flash {
    border-left: 3px solid var(--lime);
    font-size: .85rem; margin-bottom: .8rem;
}

/* Six columns of text, not ten of digits: this one wants every pixel it can
   get, so it opts out of .rt-table's reading cap and scrolls in .rk-scroll. */
.adm-table { width: 100%; max-width: none; border-collapse: collapse; font-size: .82rem; }
.adm-table th {
    text-align: left; font-size: .7rem; text-transform: uppercase;
    letter-spacing: .04em; color: var(--muted);
    padding: .4rem .5rem; border-bottom: 1px solid var(--line); white-space: nowrap;
}
.adm-table td {
    padding: .55rem .5rem; border-bottom: 1px solid var(--line); vertical-align: top;
}
.adm-table tr:last-child td { border-bottom: none; }
.adm-table .c-num { text-align: right; font-variant-numeric: tabular-nums; }

/* Secondary information: email under the name, IP, timestamps. Present but
   never competing with the name for attention. */
.adm-dim { color: var(--muted); font-size: .76rem; }

.adm-badge {
    display: inline-block; font-size: .62rem; text-transform: uppercase;
    letter-spacing: .04em; padding: .1rem .35rem; border-radius: 5px;
    border: 1px solid var(--line); color: var(--muted); vertical-align: middle;
}
/* Gold, matching how the leagues screen already flags "someone still owes a
   final table" — the same meaning: needs a human to look at it. */
.adm-pending { color: var(--gold); border-color: var(--gold); }

.adm-actions { white-space: nowrap; }
.adm-inline  { display: inline-block; margin: 0 .15rem .15rem 0; }

.btn-sm { padding: .35rem .6rem; font-size: .74rem; }

/* Destructive actions read as destructive. --neg is the palette's warning
   orange, already used elsewhere for negative numbers. */
.btn-danger {
    display: inline-block; padding: .6rem 1rem; border-radius: 8px;
    border: 1px solid var(--neg); background: transparent; color: var(--neg);
    cursor: pointer; text-decoration: none; font: inherit;
}
.btn-danger:hover { background: var(--neg); color: var(--green); }

/* ---- Mis equipos (favoritos) --------------------------------------------
   El canal cromático de "esto es mío" es PROPIO y no reutiliza ninguno de los
   que ya significan otra cosa: --lime es marca y acierto, --gold es urgencia y
   aplazado, --neg es en vivo, y el borde completo ya lo gasta .match.late. Un
   morado no aparece en ninguna otra parte de la hoja, así que el canal estaba
   libre y no colisiona con nada. */
:root { --fav: #a78bfa; --fav-soft: rgba(167, 139, 250, .13); }

/* Los elegidos, arriba y aparte: con cinco repartidos entre tres bloques de
   veinte, saber cuáles tienes exigiría recorrerlos todos. */
.fav-h { font-size: .68rem; text-transform: uppercase; letter-spacing: .1em;
    color: var(--muted); font-weight: 700; margin: 0 0 .6rem; }
.fav-chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.fav-chip-f { margin: 0; }
.fav-chip {
    display: inline-flex; align-items: center; gap: .4rem;
    background: var(--fav-soft); border: 1px solid var(--fav); color: var(--ink);
    border-radius: 999px; padding: .3rem .65rem .3rem .4rem;
    font: inherit; font-size: .8rem; font-weight: 600; cursor: pointer;
    /* 44px de alto real sin engordar la píldora: el relleno vertical es
       pequeño para que quepan cinco en dos filas, y el área táctil la da
       min-height, que no cambia el dibujo. */
    min-height: 38px;
}
/* El principal lleva el color macizo. No es decoración: es el único equipo del
   que los avisos llegan siempre, así que tiene que distinguirse de un vistazo. */
.fav-chip.main { background: var(--fav); color: #16121f; border-color: var(--fav); }
.fav-chip .crestimg { width: 20px; height: 20px; object-fit: contain; flex: none; }
.fav-chip i { font-style: normal; opacity: .55; font-size: 1rem; line-height: 1; }
.fav-chip:hover i { opacity: 1; }
.fav-note { font-size: .76rem; color: var(--muted); margin: .7rem 0 0; line-height: 1.5; }
.fav-note b { color: var(--ink); }

/* ---- La rejilla de avisos ------------------------------------------------
   Equipos en filas, tipos de aviso en columnas. Se lee por columnas, que es la
   pregunta de quien entra aquí: "¿de cuántos equipos recibo goles?". */
.fav-prefs { display: block; }
/* Si con cuatro columnas y un nombre largo no cabe, que se arrastre la TABLA y
   no la página: la regla de la casa es que nada mueva el documento de lado. */
.fav-grid-wrap { overflow-x: auto; margin-bottom: .9rem; }
.fav-matrix { width: 100%; border-collapse: collapse; }
.fav-matrix th, .fav-matrix td { padding: .5rem .25rem; text-align: center; }
.fav-matrix thead th {
    font-size: .58rem; text-transform: uppercase; letter-spacing: .05em;
    color: var(--muted); font-weight: 700; padding-bottom: .45rem;
}
.fav-matrix thead th:first-child, .fav-matrix tbody th { text-align: left; }
.fav-matrix tbody th { font-weight: 700; }
.fav-matrix tbody tr { border-top: 1px solid var(--line); }
.fav-team { display: flex; align-items: center; gap: .45rem; min-width: 0; font-size: .8rem; }
/* El nombre se recorta antes que empujar las columnas de casillas: perder la
   última letra de "Valencia CF Femenino" cuesta menos que perder una columna. */
.fav-team span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fav-team .crestimg { width: 20px; height: 20px; object-fit: contain; flex: none; }

/* La etiqueta envuelve la casilla para que la celda entera sea zona de toque:
   44px de alto real, en vez de los 21 del cuadradito. */
.fav-box { display: grid; place-items: center; min-height: 44px; cursor: pointer; }
.fav-box input { position: absolute; opacity: 0; width: 0; height: 0; }
.fav-box > span[aria-hidden] {
    width: 22px; height: 22px; border-radius: 6px;
    border: 1px solid var(--line); background: var(--card);
    display: grid; place-items: center;
}
.fav-box input:checked + span[aria-hidden] { background: var(--fav); border-color: var(--fav); }
/* La marca se dibuja con dos bordes girados: una tipografía puede no traer el
   carácter, y un cuadro que a veces se ve vacío estando marcado es peor que
   ninguno. */
.fav-box input:checked + span[aria-hidden]::after {
    content: ""; width: 5px; height: 9px; margin-top: -2px;
    border: solid #16121f; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
/* El foco tiene que verse: la casilla real está oculta, así que sin esto no
   hay ninguna señal al navegar con teclado. */
.fav-box input:focus-visible + span[aria-hidden] { outline: 2px solid var(--fav); outline-offset: 2px; }

/* Rejilla de clubes. auto-fill con un mínimo generoso: en un móvil salen dos
   columnas, en un escritorio cuatro o cinco, y nunca una sola tan ancha que el
   nombre quede perdido en medio de la fila. */
.fav-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
    gap: .45rem; margin-bottom: .4rem; }
.fav-cell-f { margin: 0; }
.fav-cell {
    width: 100%; min-height: 44px;
    display: flex; align-items: center; gap: .45rem;
    background: var(--card); border: 1px solid var(--line); color: var(--ink);
    border-radius: 10px; padding: .45rem .55rem; cursor: pointer;
    font: inherit; font-size: .8rem; text-align: left;
}
.fav-cell .crestimg { width: 22px; height: 22px; object-fit: contain; flex: none; }
.fav-cell .dot { width: 22px; height: 22px; border-radius: 6px; background: #26493788; flex: none; }
.fav-cell .fav-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; font-weight: 600; }
.fav-cell .fav-star { flex: none; color: var(--muted); font-size: .9rem; }
.fav-cell.on { border-color: var(--fav); background: var(--fav-soft); }
.fav-cell.on .fav-star { color: var(--fav); }
/* Marcado pero ya no elegible: bajó de categoría. Se sigue enseñando porque hay
   que poder quitarlo — si desapareciera, seguiría avisando sin manera de pararlo. */
.fav-cell.gone { border-style: dashed; }
/* Con el cupo lleno, los no marcados dejan de responder. Atenuados y no
   escondidos: esconderlos haría creer que faltan equipos. */
.fav-cell:disabled { opacity: .4; cursor: default; }

/* ---- Un partido de un equipo tuyo, en cualquier lista ---------------------
   Franja izquierda, no borde completo: los dos estados pueden coincidir (un
   partido aplazado de tu equipo) y .match.late ya gasta el borde entero. Así
   se leen los dos a la vez en lugar de pisarse. */
.match.fav { box-shadow: inset 3px 0 0 var(--fav); }
.match.fav .team.mine .tname { color: var(--fav); }

/* ---- Mercado (fichajes) --------------------------------------------------
   La fila responde tres preguntas en este orden: quién, de dónde a dónde, y qué
   clase de operación. El nombre arriba porque es lo que se busca; el movimiento
   debajo, con escudos, porque un escudo se reconoce antes que un nombre. */
.tr { border-bottom: 1px solid var(--line); padding: .75rem .25rem; }
.tr:last-of-type { border-bottom: 0; }
.tr-who { font-size: .92rem; font-weight: 700; margin: 0 0 .45rem;
    display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }

/* Los dos clubes comparten el ancho para que la flecha caiga en el centro de
   la fila y no baile según la longitud de los nombres. */
.tr-move { display: flex; align-items: center; gap: .5rem; }
.tr-club { display: flex; align-items: center; gap: .4rem; min-width: 0; flex: 1;
    font-size: .82rem; color: var(--muted); }
.tr-club span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* El destino en el color del texto y en negrita: de las dos mitades, la que
   importa es a dónde va. */
.tr-club.to { justify-content: flex-end; text-align: right; color: var(--ink); font-weight: 700; }
.tr-club.to span { order: 2; }
.tr-club.to .crestimg { order: 3; }
/* Un club que la API no identifica. En cursiva y atenuado porque "de fuera" no
   es el nombre de nadie: se lee como lo que es, un hueco declarado. */
.tr-club.unknown { font-style: italic; opacity: .65; }
.tr-club .crestimg { width: 22px; height: 22px; object-fit: contain; flex: none; }
.tr-arrow { color: var(--lime); font-size: 1.05rem; flex: none; line-height: 1; }
.tr-fee { font-size: .78rem; color: var(--muted); text-align: right; margin: .35rem 0 0; }
.tr-fee b { color: var(--lime); }

/* La breve escrita a partir de la ficha. Debajo del movimiento, no encima:
   quien recorre la lista busca nombres, y quien se para lee. */
.tr-news { margin-top: .5rem; padding-left: .6rem; border-left: 2px solid var(--line); }
.tr-head { font-size: .84rem; font-weight: 700; margin: 0 0 .2rem; line-height: 1.3; }
.tr-body { font-size: .8rem; color: var(--muted); margin: 0; line-height: 1.5; }

/* Un movimiento de un equipo tuyo. Mismo canal que el resto de favoritos. */
.tr.mine { box-shadow: inset 3px 0 0 var(--fav); padding-left: .6rem;
    background: var(--fav-soft); border-radius: 6px; }

/* Texto solo para lectores de pantalla: la flecha es aria-hidden, así que sin
   esto un lector diría "Levante Real Madrid" sin decir en qué dirección. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ---- Tour de bienvenida (G14) --------------------------------------------
   Señala una zona, la etiqueta, y difumina el resto. Se enseña una sola vez.

   EL RECUADRO NO LLEVA VELO PROPIO: el oscurecido lo hace su box-shadow con un
   radio enorme, que pinta todo MENOS el hueco. Un <div> semitransparente
   encima habría necesitado recortarle un agujero con clip-path o con cuatro
   rectángulos, y ninguna de las dos cosas se mueve suavemente al cambiar de
   paso. */
.tour { position: fixed; inset: 0; z-index: 60; }
.tour[hidden] { display: none; }
body.tour-open { overflow: hidden; }

.tour-spot {
    position: fixed; border-radius: 12px;
    border: 2px solid var(--lime);
    box-shadow: 0 0 0 9999px rgba(4, 10, 7, .74);
    transition: top .22s ease, left .22s ease, width .22s ease, height .22s ease;
    pointer-events: none;
}
/* Los pasos que no señalan nada — el saludo — oscurecen la pantalla entera y
   centran la tarjeta. Sin esto el recuadro se quedaría en la esquina superior
   izquierda con tamaño cero, que se ve como un punto verde suelto. */
.tour-centred .tour-spot { inset: 0; border: 0; border-radius: 0;
    box-shadow: 0 0 0 9999px rgba(4, 10, 7, .74); }
.tour-centred .tour-card { top: 50%; bottom: auto; transform: translateY(-50%); }

.tour-card {
    position: fixed; left: 50%; transform: translateX(-50%);
    width: min(22rem, calc(100vw - 2rem));
    background: var(--lime); color: #0a1410;
    border-radius: 14px; padding: .95rem 1rem;
    box-shadow: 0 14px 34px -10px rgba(0, 0, 0, .65);
}
.tour-centred .tour-card { transform: translate(-50%, -50%); }
.tour-card:focus { outline: 2px solid #0a1410; outline-offset: 3px; }
.tour-card h3 { margin: 0 0 .25rem; font-size: .98rem; letter-spacing: -.01em; }
.tour-card p { margin: 0; font-size: .85rem; line-height: 1.45; }

.tour-dots { display: flex; gap: .28rem; margin-bottom: .55rem; }
.tour-dots i { width: 6px; height: 6px; border-radius: 50%; background: #0a141055; display: block;
    transition: width .2s ease; }
.tour-dots i.on { background: #0a1410; width: 17px; border-radius: 3px; }

.tour-btns { display: flex; align-items: center; justify-content: space-between; margin-top: .9rem; }
.tour-skip, .tour-next { font: inherit; cursor: pointer; border: 0; }
/* 44px de área táctil sin engordar el botón: el relleno lo da min-height. */
.tour-skip { background: none; color: #0a1410aa; font-size: .72rem; font-weight: 700;
    letter-spacing: .04em; padding: .5rem .2rem; min-height: 44px; }
.tour-skip:hover { color: #0a1410; }
.tour-next { background: #0a1410; color: var(--lime); font-size: .76rem; font-weight: 800;
    border-radius: 8px; padding: .6rem .9rem; min-height: 44px; }

@media (prefers-reduced-motion: reduce) {
    .tour-spot { transition: none; }
    .tour-dots i { transition: none; }
}

/* ---- Interruptor de gasto en IA (G15) ------------------------------------
   Arriba del todo en Administración porque es lo único de esa pantalla que se
   apaga SOLO. Un ajuste que nadie ha tocado y que sin embargo ha cambiado tiene
   que verse sin buscarlo. */
.adm-ai { max-width: 46rem; border-left: 3px solid var(--lime); }
/* Apagado en ámbar y no en rojo: no es un error, es una decisión que alguien
   (o la cuota) ha tomado y que hay que ver. El rojo se guarda para lo que está
   roto de verdad. */
.adm-ai.off { border-left-color: var(--gold); }
.adm-ai-state { font-size: .88rem; margin: 0 0 .8rem; line-height: 1.5; }
.adm-ai-state.on b { color: var(--lime); }
.adm-ai-state.off b { color: var(--gold); }
.adm-ai-btn { width: auto; min-width: 12rem; }
.adm-ai-note { font-size: .76rem; color: var(--muted); margin: .7rem 0 0; line-height: 1.5; }

/* ---- Avisos (la bandeja) -------------------------------------------------
   Un push se pierde: se descarta de un gesto y desaparece al reiniciar. Esta
   pantalla es donde vuelve a encontrarse. */
.notif {
    display: flex; align-items: flex-start; gap: .7rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 12px;
    padding: .7rem .75rem; margin-bottom: .5rem;
    color: inherit; text-decoration: none;
}
/* Sin leer: la franja del canal de favoritos, que es de donde vienen casi
   todos. No un punto suelto — una franja se ve al recorrer la lista con el
   pulgar, un punto de 6px hay que buscarlo. */
.notif.unread { box-shadow: inset 3px 0 0 var(--fav); background: var(--fav-soft); }
.notif-ic { font-size: 1.1rem; line-height: 1.3; flex: none; width: 1.5rem; text-align: center; }
.notif-txt { min-width: 0; display: flex; flex-direction: column; gap: .12rem; }
.notif-h { font-size: .87rem; font-weight: 700; line-height: 1.3; }
.notif-b { font-size: .81rem; color: var(--muted); line-height: 1.4; }
.notif-m { font-size: .68rem; color: var(--muted); text-transform: uppercase;
    letter-spacing: .05em; margin-top: .15rem; }

/* El globo del menú. Empuja a la flecha a su sitio sin descolocar el texto. */
.di-badge {
    margin-left: auto; margin-right: .4rem;
    background: var(--fav); color: #16121f;
    font-size: .66rem; font-weight: 800; line-height: 1;
    border-radius: 999px; padding: .18rem .4rem; min-width: 1.15rem; text-align: center;
}

/* El nombre del futbolista, que lleva a su ficha. Subrayado discreto en vez de
   color: la fila ya usa el lima para el importe, y dos verdes distintos en la
   misma tarjeta compiten por la mirada sin decir nada nuevo. */
.tr-player { color: inherit; text-decoration: underline; text-decoration-color: var(--line);
    text-underline-offset: 3px; }
.tr-player:hover { text-decoration-color: var(--lime); }

/* ---- Estado de una clasificación por jornada -----------------------------
   Definitiva o provisional, y las DOS se dicen: antes solo se avisaba cuando
   estaba en curso, así que "definitiva" había que deducirla del silencio.

   Tres canales a la vez — color, forma y palabra — para que se distinga sin
   leer y también sin ver el color: un punto que late frente a un ✓, y el
   adjetivo escrito. El naranja ya significa "esto pasa ahora" en la ficha de
   partido y en la clasificación en vivo; el lima, cerrado y correcto. */
.md-state {
    display: flex; align-items: center; gap: .5rem;
    border-radius: 9px; padding: .5rem .7rem; margin: 0 0 .8rem;
    font-size: .78rem; line-height: 1.4;
}
.md-state b { font-weight: 800; letter-spacing: .03em; }
.md-state.prov { background: rgba(224, 112, 58, .13); border: 1px solid var(--neg); color: #f0b394; }
.md-state.prov b { color: var(--neg); }
.md-state.fin { background: rgba(198, 242, 78, .1); border: 1px solid rgba(198, 242, 78, .5); color: #cfe0a8; }
.md-state.fin b { color: var(--lime); }
.md-state .tick { color: var(--lime); font-weight: 800; flex: none; }
/* .md-dot ya existe: es el punto que late de la ficha de partido, y se
   reutiliza a propósito para que "en juego" se vea igual en toda la app. */

/* El nombre en la tabla de jornada lleva a la ficha del jugador, como en la
   general. Hereda el color en vez de pintarse de lima: en una tabla de nueve
   columnas, una de ellas en color de enlace se lee como un dato distinto. */
.rk-table .c-name a { color: inherit; text-decoration: none; }
.rk-table .c-name a:hover { text-decoration: underline; }

/* ---- Quien no llegó a pronosticar ----------------------------------------
   En NEGATIVO, no resaltado: es un despiste, no un logro. Atenuado para que la
   fila pese menos que las de quien sí jugó, y el guion en el color de aviso
   para que se lea "aquí falta algo" y no "aquí hay un cero".

   No se esconde: una porra de diez que enseña ocho filas no deja saber si
   faltan dos personas o si la pantalla está incompleta. */
.md-rival.missed { opacity: .55; }
.md-rival.missed .md-rival-nm { font-style: italic; }
.md-rival-pred.none { color: var(--neg); font-weight: 700; }

/* Sin eventos y con el partido rodando: la pantalla tiene que seguir viva.
   No es .card.empty — ese gris apagado es el de "aquí no hay nada", y aquí sí
   lo hay: hay un partido en juego. */
.md-nothing-yet { text-align: center; }
.md-nothing-h {
    display: flex; align-items: center; justify-content: center; gap: .6rem;
    flex-wrap: wrap; font-weight: 700; margin: 0 0 .6rem;
}
.md-nothing-p { color: var(--muted); font-size: .86rem; margin: 0 0 .4rem; }
.md-nothing-p:last-child { margin-bottom: 0; }
.md-nothing-p a { color: var(--lime); }

/* ── El once sobre el campo ──────────────────────────────────────────────────
   Sin imagen de fondo y sin SVG: el cesped son dos gradientes y las lineas son
   bordes. Asi escala a cualquier ancho sin pixelarse y sin descargar nada.

   aspect-ratio en vez de alto fijo, que es lo que lo hace mobile-first de
   verdad: el campo se estrecha con el telefono y las posiciones, que van en
   porcentaje, siguen cayendo donde deben. Era justo el problema que no se
   resolvia con el widget, cuyo contenido pide mas de 430 px y se corta. */
.md-pitch {
    position: relative;
    aspect-ratio: 68 / 52;
    margin: .2rem 0 .8rem;
    border: 1px solid var(--line);
    border-radius: 10px;
    overflow: hidden;
    background:
        repeating-linear-gradient(0deg, rgba(255,255,255,.015) 0 8%, transparent 8% 16%),
        linear-gradient(#16301f, #122619);
}
/* Area y semicirculo, colgando de la porteria propia (arriba del dibujo). */
.md-pitch::before {
    content: ""; position: absolute; inset: 5px;
    border: 1px solid rgba(198,242,78,.15); border-radius: 4px;
}
.md-pitch::after {
    content: ""; position: absolute; top: 5px; left: 50%; transform: translateX(-50%);
    width: 52%; height: 22%;
    border: 1px solid rgba(198,242,78,.15); border-top: 0; border-radius: 0 0 3px 3px;
}

.md-spot {
    position: absolute; transform: translate(-50%, -50%);
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    width: 4.6rem;
}
.md-shirt {
    width: 1.35rem; height: 1.35rem; border-radius: 50%;
    display: grid; place-items: center;
    font-size: .58rem; font-weight: 800; font-variant-numeric: tabular-nums;
    color: #0a1410; background: var(--lime);
    box-shadow: 0 1px 4px rgba(0,0,0,.5);
}
.md-pitch.visitante .md-shirt { background: var(--neg); color: #fff; }
.md-spot-name {
    font-size: .55rem; line-height: 1.15; text-align: center; color: var(--ink);
    text-shadow: 0 1px 3px rgba(0,0,0,.9);
    /* Dos lineas como mucho: un nombre largo no puede empujar al de al lado. */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}

/* En pantalla ancha los dos campos van uno al lado del otro; en el telefono,
   uno debajo del otro, que es como .md-lineups ya se comporta. */
@media (min-width: 720px) {
    .md-lineups { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; align-items: start; }
}

/* ── La ficha de partido del widget ──────────────────────────────────────────
   La pestaña que le inyectamos tiene que parecer suya, no un parche: hereda sus
   clases y solo se marca con el acento nuestro cuando está activa. */
.gl-tab-btn.active { color: var(--lime) !important; }
.gl-loading { padding: 1rem; color: var(--muted); font-size: .85rem; text-align: center; }

/* MEDIDO EL 30/8/2026, y el resultado desmiente lo que veníamos repitiendo.
   Metido en una caja de 390 px, el contenido del widget pide EXACTAMENTE 390:
   ningún elemento se pasa. El "pide más de 430 px y se corta" que heredamos del
   spike es falso. El overflow-x se queda de red por si una competición trae
   nombres más largos, pero hoy no hace falta y no se nota. */
.gl-match { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.gl-match api-sports-widget { display: block; min-width: 0; }

/* ── Cuatro pestañas, en el orden de Juanfe (30/8/2026) ──────────────────────

   Suyas van en este orden: events · statistics · lineups · players. Las quiere
   así: eventos · alineaciones · porra · estadísticas, y sin la de jugadores.

   SE REORDENA CON `order`, NO MOVIENDO SU DOM. Su .navtab-header es flex, así
   que basta con numerar. Tocar su DOM sería pelearse con el repintado que hace
   cada quince segundos; esto sobrevive solo.

   SE ESCONDE LA PESTAÑA, NO SE APAGA `data-players`. La bandera alimenta
   también las fichas de jugador de dentro de Alineaciones, así que apagarla se
   llevaría por delante algo que sí queremos. */
/* CUANDO SOLO LES QUEDA UNA PESTAÑA, ESCONDEN LA BARRA ENTERA.
   Le ponen la clase `d-none`, y tiene sentido para ellos: una tira con un solo
   botón no es una tira. Pero con la nuestra dentro ya son dos, así que
   esconderla se lleva por delante «Mi porra» — que es justo la pestaña que hay
   que poder abrir en un partido que aún no ha empezado y con los pronósticos ya
   cerrados. Lo vio Juanfe el 30/8 en un Depor-Valencia a catorce minutos del
   saque: se veía el once y ninguna pestaña.

   Se cancela SOLO si la nuestra está dentro. Si algún día no llegara a
   inyectarse, la barra vuelve a esconderse como ellos quieren, en vez de
   quedarse una tira de un botón. */
.gl-match .navtab-header.d-none:has(.gl-tab-btn) { display: flex !important; }

.gl-match .navtab-header .btn-widget[data-action="players"] { display: none; }

.gl-match .navtab-header .btn-widget[data-action="events"]     { order: 1; }
.gl-match .navtab-header .btn-widget[data-action="lineups"]    { order: 2; }
.gl-match .navtab-header .gl-tab-btn                           { order: 3; }
.gl-match .navtab-header .btn-widget[data-action="statistics"] { order: 4; }

/* ── En el móvil, solo iconos ────────────────────────────────────────────────

   "Estadísticas" y "Alineaciones" no caben cuatro veces en 390 px. Y no hay que
   inventar iconos: sus botones YA traen un <svg> de Lucide dentro, con el
   rótulo como nodo de texto suelto al lado.

   Un nodo de texto suelto no se puede ocultar con un selector, así que se apaga
   por tamaño: `font-size: 0` en el botón se lo lleva, y el SVG sobrevive porque
   se mide por sus atributos width/height y no por la tipografía.

   El nombre sigue estando para quien use lector de pantalla: los suyos lo
   llevan en su aria-label y al nuestro se lo pone widget-porra.js. */
@media (max-width: 560px) {
    .gl-match .navtab-header .btn-widget {
        font-size: 0;
        padding-left: .9rem;
        padding-right: .9rem;
        gap: 0;
    }
    /* CON !important, Y NO ES PEREZA.
       Su hoja lleva `navtab-header .btn-widget svg { display: none }` — los
       iconos están en su HTML y ellos los apagan — y la inyectan en tiempo de
       ejecución, o sea DESPUÉS de la nuestra. Empatando en especificidad gana
       la última, así que subir un selector no basta: hay que pasarle por
       encima. Medido: sin esto el SVG existe y ocupa 0×0. */
    .gl-match .navtab-header .btn-widget svg {
        display: inline-block !important;
        width: 19px !important;
        height: 19px !important;
    }
}

/* La barra propia, para cuando el widget no dibuja ninguna (partido sin
   empezar y sin alineaciones: no tiene secciones que ofrecer). Se parece a la
   suya a propósito — misma altura, mismo redondeo, mismo gris — para que la
   ficha no se parta en dos estilos por un caso de borde. */
.gl-solo { margin-top: .55rem; }
.gl-solo-bar {
    display: flex; border-radius: 3px; overflow: hidden;
    background-color: rgba(133, 133, 133, .15);
}
.gl-solo-btn {
    flex: 1; border: 0; cursor: pointer;
    padding: .5rem; font: inherit; font-size: .78rem; font-weight: 700;
    color: #0a1410; background: var(--lime);
}
.gl-solo-panel { padding-top: .5rem; }

/* ── Avisos al administrador ─────────────────────────────────────────────────
   Llamativo a propósito (pedido de Juanfe, 6/9/2026): esto sale cuando la
   aplicación se ha parado sola y hace falta que una persona actúe. El resto de
   la interfaz es verde y tranquila; esto tiene que romper. */
.adm-alerts { padding: .5rem .75rem 0; display: flex; flex-direction: column; gap: .4rem; }
.adm-alert {
    display: flex; gap: .6rem; align-items: flex-start;
    padding: .6rem .75rem; border-radius: 10px;
    background: rgba(245, 215, 110, .12); border: 1px solid var(--gold);
    font-size: .82rem; line-height: 1.35;
}
.adm-alert.grave { background: rgba(224, 112, 58, .14); border-color: var(--neg); }
.adm-alert-icon { font-size: 1rem; line-height: 1.2; }
.adm-alert-body { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.adm-alert-body strong { color: var(--ink); }
.adm-alert-action { color: var(--gold); font-weight: 600; }
.adm-alert.grave .adm-alert-action { color: var(--neg); }
/* Las palabras del proveedor, en pequeño: son largas y a veces feas, pero son
   las que dicen qué pasa de verdad. Se cortan a tres líneas para que un mensaje
   kilométrico no empuje la pantalla entera hacia abajo. */
.adm-alert-detail {
    color: var(--muted); font-size: .74rem;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.adm-alert-reset { color: var(--ink); font-size: .78rem; }
.adm-alert-reset strong { font-variant-numeric: tabular-nums; }
