/*
  League Winner — design system.

  Source of truth for the 2026 look: paper white, ink black, one yellow.
  Extracted from the approved landing-page design (design/landing-source.html).
  Every page should pull its colour, type and spacing from the tokens here
  rather than hardcoding values, so a change lands everywhere at once.

  Archivo is the only family — variable weight 100-900 and width 62-125%,
  on the SIL Open Font License via Google Fonts. It replaces the old
  Anton + Barlow + Barlow Condensed trio.
*/


/* ══════════════════════════════════════════════════════════════════
   Archivo, self-hosted.

   Until 2026-08-26 this came from fonts.googleapis.com, which cost two
   render-blocking round trips on two third-party origins: the stylesheet
   from googleapis, then the font file it names from gstatic. PageSpeed
   measured the stylesheet alone at 200ms of the 700ms of render-blocking
   requests. Serving the files from here removes the stylesheet entirely
   and puts the font on an origin the browser has already connected to.

   The rules below are Google's own, byte for byte, with the URLs pointed
   at assets/fonts/. The unicode-range values are UNCHANGED and must stay
   that way: they are what stops a page pulling the Vietnamese subset to
   render an English name, and what makes latin-ext arrive for Jokić,
   Porziņģis and Vučević. Fourteen accented characters appear in
   data/players.json, four of them outside latin.

   Archivo is under the SIL Open Font License, which permits this.
   Refreshing it means re-fetching that css2 URL with a modern browser
   User-Agent and re-downloading whatever it names; Google revs the
   version folder (v25 at the time of writing) when the font changes.
   ══════════════════════════════════════════════════════════════ */
@font-face{
  font-family:"Archivo";
  font-style:normal;
  font-weight:400 900;
  font-display:swap;
  src:url("fonts/archivo-vietnamese-normal.woff2") format("woff2");
  unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face{
  font-family:"Archivo";
  font-style:italic;
  font-weight:400 900;
  font-display:swap;
  src:url("fonts/archivo-vietnamese-italic.woff2") format("woff2");
  unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face{
  font-family:"Archivo";
  font-style:normal;
  font-weight:400 900;
  font-display:swap;
  src:url("fonts/archivo-latin-ext-normal.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:"Archivo";
  font-style:italic;
  font-weight:400 900;
  font-display:swap;
  src:url("fonts/archivo-latin-ext-italic.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:"Archivo";
  font-style:normal;
  font-weight:400 900;
  font-display:swap;
  src:url("fonts/archivo-latin-normal.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:"Archivo";
  font-style:italic;
  font-weight:400 900;
  font-display:swap;
  src:url("fonts/archivo-latin-italic.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The fallback the type stack has always named and never had.

   --lw-font lists "Archivo Fallback" between Archivo and system-ui, and
   nothing ever declared it, so the name did nothing. This declares it, with
   overrides measured rather than guessed. At 100px, against the string
   "Nikola Jokic Victor Wembanyama Shai Gilgeous-Alexander 0123456789":

     Archivo   width 3188.42   ascent 88   descent 21
     Arial     width 3203.66   ascent 91   descent 21

   So Arial is scaled to 99.52% to match Archivo's advance widths and its
   ascent is pulled from 91 to 88, which makes the swap under display=swap
   land in the same space it started in.

   THIS IS NOT THE CLS FIX, though it was added as one on 2026-08-26 and
   that was wrong on two counts, both worth recording so nobody re-runs the
   experiment. Lighthouse still measured 0.151 afterwards, and then:

   - Forcing the fallback and measuring moves the first board row by TWO
     pixels and the h1 not at all. The swap was never big enough to explain
     a 0.15 score.
   - Lighthouse's mobile run emulates a Moto G Power, and Android ships
     Roboto with none of the three faces named below. The rule does not
     even apply there, which is precisely where the score was measured.

   It stays because a metric-matched fallback is right anyway, on the
   platforms that have one of these faces. It is not load-bearing. */
@font-face{
  font-family:"Archivo Fallback";
  src:local("Arial"),local("Helvetica Neue"),local("Liberation Sans");
  size-adjust:99.52%;
  ascent-override:88%;
  descent-override:21%;
  line-gap-override:0%;
}

:root{
  /* ---- core palette ---- */
  --lw-paper:#ffffff;         /* page ground */
  --lw-ink:#101010;           /* text, borders, filled buttons */
  --lw-yellow:#FFCC00;        /* the one accent — highlight, hover, badge */
  --lw-red:#ec3013;           /* link hover only; never a surface */

  /* Tints of ink, for the rare moment a hairline or a muted line is
     needed. Kept as alpha over paper so they work on any ground. */
  --lw-ink-70:rgba(16,16,16,.70);
  --lw-ink-45:rgba(16,16,16,.45);
  --lw-ink-12:rgba(16,16,16,.12);
  --lw-ink-06:rgba(16,16,16,.06);

  /* ---- platform brand colours ---- */
  --lw-espn:#D50A0A;
  --lw-yahoo:#5F01D1;
  --lw-fantrax:#0B5FA5;
  --lw-sleeper:#101010;

  /* ---- type ---- */
  --lw-font:"Archivo","Archivo Fallback",system-ui,-apple-system,sans-serif;
  --lw-w-regular:400;
  --lw-w-bold:800;            /* nav, labels, buttons */
  --lw-w-black:900;           /* display, wordmark */

  /* ---- rhythm ---- */
  --lw-gutter:clamp(20px,4vw,48px);
  --lw-radius-pill:999px;
  --lw-border:2px;

  /* ---- motion ---- */
  --lw-ease-card:cubic-bezier(.2,.9,.25,1);
  --lw-ease-pop:cubic-bezier(.22,1,.36,1);
}

*,*::before,*::after{box-sizing:border-box;}
html,body{margin:0;padding:0;}
/* Every page is a column that is at least a screen tall, so the footer can
   never ride up. Without this, any page whose body is briefly short — a
   members page still checking the session, an empty state, a stub — drew its
   footer a third of the way down with the bottom two-thirds left blank, which
   reads as a broken page before a single feature has loaded. Content grows,
   the footer sits on the floor. */
body{
  background:var(--lw-paper);
  color:var(--lw-ink);
  font-family:var(--lw-font);
  font-size:15px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  min-height:100dvh;
  display:flex;
  flex-direction:column;
}
@supports not (min-height:100dvh){body{min-height:100vh;}}
.lw-foot{margin-top:auto;}
a{color:var(--lw-ink);text-decoration:none;}
a:hover{color:var(--lw-red);}
img{display:block;max-width:100%;}
/* The `hidden` attribute is only a UA rule, so any author rule that sets
   display beats it — .lw-gbtn{display:flex} kept the Google button on
   screen while the DOM said hidden:true. Make the attribute mean it. */
[hidden]{display:none!important;}
*:focus-visible{outline:2px solid var(--lw-ink);outline-offset:3px;}

/* ══════════════════════════════════════════════════════════════════
   Buttons — pills, always. Two weights: filled (primary) and
   outlined (secondary). Both hover to yellow rather than a tint,
   which is what keeps the palette to three colours.
   ══════════════════════════════════════════════════════════════ */
.lw-btn{
  display:inline-flex;align-items:center;justify-content:center;
  height:46px;padding:0 26px;
  border:var(--lw-border) solid transparent;border-radius:var(--lw-radius-pill);
  font-family:inherit;font-size:14px;font-weight:var(--lw-w-bold);
  letter-spacing:.02em;text-transform:uppercase;white-space:nowrap;
  cursor:pointer;transition:background .14s ease,color .14s ease,border-color .14s ease;
}
.lw-btn-fill{background:var(--lw-ink);color:var(--lw-paper);}
.lw-btn-fill:hover{background:var(--lw-yellow);color:var(--lw-ink);}
.lw-btn-line{background:transparent;color:var(--lw-ink);border-color:var(--lw-ink);}
.lw-btn-line:hover{background:var(--lw-ink);color:var(--lw-paper);}

/* ══════════════════════════════════════════════════════════════════
   Site chrome — the marquee banner and the header.

   These live here rather than in each page because they must be
   IDENTICAL everywhere; a copy per page guarantees drift the moment
   one of them is tweaked. Pages supply only the markup (which differs
   per page anyway, since each marks its own nav item as current).
   ══════════════════════════════════════════════════════════════ */
.lw-banner{background:var(--lw-yellow);overflow:hidden;padding:15px 0;user-select:none;flex:none;}
/* Two identical runs translated -50% for a seamless loop, so each run
   has to be at least a viewport wide or a gap opens on big monitors —
   that's what the copy count is for, not repetition for its own sake. */
.banner-track{display:flex;width:max-content;animation:lw-marquee 60s linear infinite;}
.banner-run{display:flex;gap:72px;padding-right:72px;align-items:center;}
.banner-run span{font-size:18px;font-weight:var(--lw-w-bold);letter-spacing:.04em;white-space:nowrap;}
.banner-run a{text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:2px;}
.banner-run a:hover{color:var(--lw-red);}

.lw-nav{
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:24px;
  padding:20px var(--lw-gutter);flex:none;
}
.brand{display:flex;align-items:center;gap:7px;justify-self:start;}
.brand:hover{color:var(--lw-ink);}
/* The mark art is cropped flush to the circle, so a 50% radius clips
   the four white corners and it sits on any ground, not just paper. */
.brand-mark{
  display:block;width:42px;height:42px;flex:none;
  border-radius:50%;background:var(--lw-yellow);
}
.brand-name{font-size:27px;font-weight:var(--lw-w-black);letter-spacing:-.03em;white-space:nowrap;}

.navlinks{display:flex;align-items:center;gap:38px;justify-self:center;}
.navgroup{position:relative;}
.navtop{
  display:inline-flex;align-items:center;gap:8px;
  font-size:17px;font-weight:var(--lw-w-bold);letter-spacing:.02em;
  text-transform:uppercase;white-space:nowrap;padding:10px 0;
}
/* The page you're on keeps a yellow underscore so the nav always says
   where you are without a second breadcrumb. */
.navtop.here{box-shadow:inset 0 -.28em 0 var(--lw-yellow);}
.navtop .caret{width:12px;height:12px;flex:none;transition:transform .15s ease;}
.navgroup:hover .caret,.navgroup:focus-within .caret{transform:rotate(180deg);}
.drop{
  position:absolute;top:calc(100% + 10px);left:50%;
  transform:translateX(-50%) translateY(-4px);
  min-width:252px;padding:8px;z-index:40;
  background:var(--lw-paper);border:var(--lw-border) solid var(--lw-ink);border-radius:10px;
  opacity:0;visibility:hidden;
  /* Hiding lags by 140ms so a diagonal cut across the gap toward the
     first item doesn't snap the menu shut mid-movement. Opening stays
     instant — the delay only ever applies on the way out. */
  transition:opacity .15s ease .14s,transform .15s ease .14s,visibility 0s linear .29s;
}
/* Invisible bridge across the 10px gap under the trigger. Without it
   the pointer leaves .navgroup on the way down and the menu vanishes,
   which is the "fiddly" part — the gap is visual only, not a dead zone. */
.drop::before{content:"";position:absolute;left:0;right:0;top:-14px;height:14px;}
.navgroup:hover .drop,.navgroup:focus-within .drop{
  opacity:1;visibility:visible;transform:translateX(-50%) translateY(0);
  transition:opacity .15s ease,transform .15s ease,visibility 0s;
}
/* The menu parents are BUTTONS on every page (2026-08-25): "Tools" is the
   label on a menu, not a destination, and clicking it used to send a
   reader to the pricing page. Strip the browser's chrome but never with
   the `font` shorthand — it resets font-size and font-weight and outranks
   .navtop, so the two parents would render at different sizes. */
button.navtop{
  background:none;border:0;margin:0;cursor:pointer;
  font-family:inherit;line-height:inherit;color:inherit;
}
/* Click-to-open. Required on touch, where hover does not exist and the
   narrow-screen rule below hides .drop outright — opacity alone cannot
   resurrect a display:none menu, so this restores display too. */
.navgroup.open .drop{
  display:block;
  opacity:1;visibility:visible;transform:translateX(-50%) translateY(0);
  transition:opacity .15s ease,transform .15s ease,visibility 0s;
}

/* Sliding from one menu straight to its neighbour is a menubar switch, not
   a fresh open. The panels are wider than the gap between their triggers —
   they overlap by about 80px — so the 290ms hide delay left two bordered
   boxes stacked on each other for a third of a second. While the pointer is
   anywhere in the nav row the menu you left closes at once, and only one is
   ever on screen. Leaving the row altogether still gets the forgiving
   delay, which is the case it was written for.

   Scoped to the whole nav bar rather than to .navlinks: member home has no
   .navlinks at all — its Rankings and Tools groups sit in .actions, hard
   against the right edge, where two 252px panels hanging off triggers 22px
   apart overlap almost completely. That page was the one that needed this
   most and the one the rule did not reach. */
.lw-nav:hover .navgroup:not(:hover) .drop{transition:none;}
.drop a{
  display:flex;align-items:center;gap:9px;padding:11px 12px;border-radius:6px;
  font-size:15px;font-weight:var(--lw-w-bold);letter-spacing:.02em;
  text-transform:uppercase;white-space:nowrap;
  transition:background .12s ease,color .12s ease;
}
.drop a:hover{background:var(--lw-yellow);color:var(--lw-ink);}
/* The current page is marked by underlining its LABEL, not by filling
   the row: hover is already a yellow fill, so a yellow current row made
   the whole menu look highlighted the moment you moved onto a sibling.
   This echoes the yellow underscore the nav parent carries. */
.drop a.here .lbl{box-shadow:inset 0 -.26em 0 var(--lw-yellow);}
.drop a.here:hover .lbl{box-shadow:inset 0 -.26em 0 var(--lw-ink);}
/* The Free tags that used to sit on the right of each rankings row are
   gone — the menu reads cleaner as plain labels, and "Free" on two of five
   items invited the question of what the other three cost. */

.actions{
  display:flex;align-items:center;gap:10px;justify-self:end;
  /* Menu injected by lw-header.js — its defaults are the old dark
     chrome, so pages still on the dark theme are untouched by these. */
  --lw-menu-bg:var(--lw-paper);
  --lw-menu-border:var(--lw-ink);
  --lw-menu-text:var(--lw-ink);
  --lw-menu-dim:var(--lw-ink-45);
  --lw-menu-hover:var(--lw-yellow);
  --lw-menu-radius:10px;
  --lw-menu-shadow:0 10px 24px rgba(16,16,16,.14);
  /* White circle, ink initial. Yellow is the hover, matching every other
     round control in this file (.cta-small, .lw-gbtn, .lw-foot-social a). */
  --lw-avatar-bg:var(--lw-paper);
  --lw-avatar-text:var(--lw-ink);
  --lw-avatar-border:var(--lw-ink);
  --lw-avatar-hover:var(--lw-yellow);
}
/* lw-header.js swaps this pair for an avatar menu when a session
   exists — it looks for .actions, .loginlink and .cta-small by name,
   so those hooks have to survive any restyle of this header. */
.loginlink{
  display:inline-flex;align-items:center;height:48px;padding:0 26px;
  border:var(--lw-border) solid var(--lw-ink);border-radius:var(--lw-radius-pill);
  font-size:15px;font-weight:var(--lw-w-bold);letter-spacing:.02em;
  text-transform:uppercase;white-space:nowrap;transition:background .14s ease,color .14s ease;
}
/* Yellow, not ink — filling this on hover made it identical to the
   Sign up button sitting beside it, so the two read as one control. */
.loginlink:hover{background:var(--lw-yellow);color:var(--lw-ink);}
.cta-small{
  display:inline-flex;align-items:center;height:48px;padding:0 28px;
  border:var(--lw-border) solid var(--lw-ink);border-radius:var(--lw-radius-pill);
  background:var(--lw-ink);color:var(--lw-paper);
  font-size:15px;font-weight:var(--lw-w-bold);letter-spacing:.02em;
  text-transform:uppercase;white-space:nowrap;transition:background .14s ease,color .14s ease;
}
.cta-small:hover{background:var(--lw-yellow);color:var(--lw-ink);}

/* ══════════════════════════════════════════════════════════════════
   Footer — ink hairline, uppercase micro type, circular socials.
   ══════════════════════════════════════════════════════════════ */
/* Three columns, not space-between: with flex the middle group lands
   wherever the two outer groups' unequal widths leave it, so the links
   only LOOK centred when the copyright and the socials happen to match.
   Equal 1fr rails on either side centre it against the page instead. */
.lw-foot{
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;
  gap:20px;padding:17px var(--lw-gutter);
  border-top:var(--lw-border) solid var(--lw-ink);
}
.lw-foot > :first-child{justify-self:start;}
.lw-foot > :last-child{justify-self:end;}
/* The Contact control is a <button> (it opens a dialog rather than going
   anywhere) but it sits in the same row as Terms and Privacy and has to read
   as one of them. Styling it here rather than in lw-contact.js means the three
   can never drift: change the footer type once and all three move. */
.lw-foot-txt,.lw-foot a,.lw-foot .lw-contact-link{
  font-size:13px;font-weight:var(--lw-w-bold);
  letter-spacing:.06em;text-transform:uppercase;
}
.lw-foot .lw-contact-link{color:var(--lw-ink);}
.lw-foot .lw-contact-link:hover{color:var(--lw-red);}
.lw-foot-links{display:flex;align-items:center;justify-content:center;gap:28px;}
.lw-foot-social{display:flex;align-items:center;gap:10px;}
.lw-foot-social a{
  display:grid;place-items:center;width:38px;height:38px;
  border-radius:var(--lw-radius-pill);
  background:var(--lw-ink);color:var(--lw-paper);
  transition:background .14s ease,color .14s ease;
}
.lw-foot-social a:hover{background:var(--lw-yellow);color:var(--lw-ink);}

/* ══════════════════════════════════════════════════════════════════
   Motion. Every animation here is decorative — the page reads the
   same without it, which is why reduced-motion can turn the lot off.
   ══════════════════════════════════════════════════════════════ */
@keyframes lw-marquee{from{transform:translate3d(0,0,0);}to{transform:translate3d(-50%,0,0);}}

/* ══════════════════════════════════════════════════════════════════
   Chrome breakpoints. These belong to the header/footer, NOT to any
   page's content — each page sets its own content breakpoints, which
   land at different widths. Tying them together clipped the Sign up
   button once already.
   ══════════════════════════════════════════════════════════════ */
/* Tablet: still three columns, but the larger type and buttons push the
   row 1px past the viewport, so everything gives a little back rather
   than the page gaining a scrollbar. */
@media (max-width:900px){
  .lw-nav{gap:16px;}
  .navlinks{gap:22px;}
  .navtop{font-size:15px;}
  /* Anchor parents stay real links on narrow screens, so their menu is
     redundant and goes away. A BUTTON parent has no destination — its menu
     is the only route to those links — so a click-opened one stays, and
     becomes a full-width panel under the bar rather than a 252px card
     centred on a trigger near the edge, which hung 4px off-screen at 375. */
  .drop{display:none;}
  .lw-nav{position:relative;}
  /* static, so the absolutely-positioned panel resolves against .lw-nav
     rather than against its own trigger. */
  .navgroup{position:static;}
  .navgroup.open .drop{
    left:var(--lw-gutter);right:var(--lw-gutter);
    transform:translateY(0);min-width:0;
  }
  .brand-name{font-size:22px;}
  .loginlink,.cta-small{height:44px;padding:0 18px;font-size:13.5px;}
}
/* Brand + two menus + two buttons stop fitting one row at about 690px. */
@media (max-width:760px){
  .lw-nav{grid-template-columns:auto auto;gap:10px 12px;padding:14px var(--lw-gutter);}
  /* Centred on their own row, not left-aligned: the pages are symmetric
     everywhere else, so pinning two short links to the left edge left a
     wide dead gap beside them and read as a layout accident. */
  .navlinks{
    grid-column:1 / -1;order:3;justify-self:center;
    gap:26px;overflow-x:auto;scrollbar-width:none;
    margin:0 -2px;padding:0 2px 2px;max-width:100%;
  }
  .navlinks::-webkit-scrollbar{display:none;}
  .navtop{font-size:13px;}
  .loginlink,.cta-small{height:40px;padding:0 16px;font-size:12.5px;}
  .brand-mark{width:34px;height:34px;}
  .brand-name{font-size:21px;}
}
@media (max-width:640px){
  .banner-run span{font-size:13px;}
  /* Three columns don't fit a phone — the 1fr rails squeeze the
     copyright into four wrapped lines. Stack and centre instead. */
  .lw-foot{
    grid-template-columns:1fr;justify-items:center;
    gap:11px;padding:13px var(--lw-gutter);text-align:center;
  }
  .lw-foot > :first-child,.lw-foot > :last-child{justify-self:center;}
  .lw-foot-txt{order:3;}
  .lw-foot-links{order:1;gap:22px;}
  .lw-foot-social{order:2;}
  .lw-foot-social a{width:34px;height:34px;}
}

/* ==========================================================================
   SHARED AUTH MODAL  (lw-login.js)
   Logging in used to take you to login.html and then bounce you back, which
   loses your place — and on the Rankings Game it loses a list you may have
   spent ten minutes dragging into order. This is the same visual language as
   the page-level modals, extracted so login looks identical everywhere.
   Prefixed lw- because rankings-game.html already owns unprefixed .modal /
   .overlay / .gbtn for its own entry modal; the two must not collide.
   ========================================================================== */
.lw-overlay{
  display:none;position:fixed;inset:0;z-index:120;background:rgba(16,16,16,.55);
  padding:20px;overflow:auto;
}
.lw-overlay.open{display:grid;place-items:center;}
.lw-modal{
  position:relative;width:min(430px,100%);background:var(--lw-paper);
  border:var(--lw-border) solid var(--lw-ink);border-radius:18px;
  padding:clamp(22px,3vw,32px);
}
.lw-modal .lw-x{
  position:absolute;top:12px;right:14px;width:32px;height:32px;border-radius:50%;
  border:none;background:none;font-size:24px;line-height:1;color:var(--lw-ink-45);cursor:pointer;
}
.lw-modal .lw-x:hover{color:var(--lw-ink);}
.lw-modal h2{
  margin:0 0 18px;font-size:clamp(24px,2.6vw,34px);font-weight:var(--lw-w-black);
  letter-spacing:-.035em;text-transform:uppercase;line-height:1;
}
.lw-modal .lw-msub{margin:-8px 0 18px;font-size:13.5px;line-height:1.5;color:var(--lw-ink-70);}
.lw-gbtn{
  display:flex;align-items:center;justify-content:center;gap:11px;width:100%;height:52px;
  border:var(--lw-border) solid var(--lw-ink);border-radius:var(--lw-radius-pill);
  background:var(--lw-paper);font-family:inherit;font-size:14px;font-weight:var(--lw-w-black);
  color:var(--lw-ink);cursor:pointer;transition:background .14s ease;
}
.lw-gbtn:hover{background:var(--lw-yellow);}
.lw-gbtn svg{width:19px;height:19px;flex:none;}
.lw-or{
  display:flex;align-items:center;gap:14px;margin:14px 0;
  font-size:11px;font-weight:var(--lw-w-bold);letter-spacing:.16em;
  text-transform:uppercase;color:var(--lw-ink-45);
}
.lw-or::before,.lw-or::after{content:"";flex:1;height:2px;background:var(--lw-ink-12);}
.lw-modal form{display:flex;flex-direction:column;gap:9px;}
.lw-modal input{
  height:50px;padding:0 18px;font-family:inherit;font-size:14.5px;color:var(--lw-ink);
  background:var(--lw-paper);border:var(--lw-border) solid var(--lw-ink-12);
  border-radius:var(--lw-radius-pill);
}
.lw-modal input::placeholder{color:var(--lw-ink-45);}
.lw-modal input:focus-visible{outline:none;border-color:var(--lw-ink);}
.lw-modal .lw-primary{
  height:52px;border:none;border-radius:var(--lw-radius-pill);
  background:var(--lw-ink);color:var(--lw-paper);font-family:inherit;font-size:13.5px;
  font-weight:var(--lw-w-black);letter-spacing:.06em;text-transform:uppercase;
  cursor:pointer;transition:background .14s ease,color .14s ease;
}
.lw-modal .lw-primary:hover:not(:disabled){background:var(--lw-yellow);color:var(--lw-ink);}
.lw-modal .lw-primary:disabled{opacity:.5;cursor:not-allowed;}
/* Everything under the button is two groups, not three loose lines:
   [ the form, and the way out of it ] then [ the other path, and the legal ].
   Previously all three sat at near-identical sizes (12.5/13/11) with near-even
   gaps (11/14/10), so nothing read as belonging to anything. Forgot-password
   now sits tight to the button it belongs with, and a single larger step
   separates the pair below. Two type sizes, not three. */
.lw-mmsg{display:none;font-size:13px;margin:12px 0 0;}
.lw-mmsg.err{display:block;color:var(--lw-red);}
.lw-mmsg.note{display:block;color:var(--lw-ink-70);}
.lw-mmsg a{text-decoration:underline;}

/* group one — still part of the form */
.lw-forgot{
  background:none;border:0;padding:0;margin:12px 0 0;font-family:inherit;font-size:13px;
  color:var(--lw-ink-45);text-decoration:underline;cursor:pointer;
}
.lw-forgot:hover{color:var(--lw-ink);}

/* group two — the alternative, and the small print that goes with it */
.lw-mfine{font-size:13px;color:var(--lw-ink-45);margin:22px 0 0;}
.lw-mfine a{color:var(--lw-ink);font-weight:var(--lw-w-black);text-decoration:underline;}
.lw-mfine a:hover{color:var(--lw-red);}
.lw-agree{font-size:11.5px;line-height:1.45;color:var(--lw-ink-45);margin:6px 0 0;max-width:34ch;}
.lw-agree a{text-decoration:underline;}
.lw-agree a:hover{color:var(--lw-ink);}
@media (max-width:420px){
  .lw-modal{border-radius:16px;}
  .lw-modal h2{font-size:26px;}
}

/* ==========================================================================
   Player signal chip (assets/lw-signals.js renders it)

   Monochrome on purpose: the palette is paper, ink and one yellow, and a
   red badge would smuggle in a fourth colour. A player who cannot play is
   a filled ink pill (OUT, IR, SUS); day-to-day is outlined. The detail —
   "Out · Knee · Surgery" — rides in the title attribute so the row itself
   stays quiet. */
.lw-sig{
  display:inline-block;vertical-align:.12em;margin-left:6px;
  padding:1px 6px 2px;border-radius:var(--lw-radius-pill);
  font-size:8.5px;font-weight:var(--lw-w-black);letter-spacing:.1em;
  line-height:1.4;white-space:nowrap;
  border:1.5px solid var(--lw-ink-45);color:var(--lw-ink-45);
}
.lw-sig.hard{background:var(--lw-ink);border-color:var(--lw-ink);color:var(--lw-paper);}

/* The information circle, and what it holds.

   The boards printed the market in full on the meta row, next to position
   and team, and on a 200-row list that turned the line people scan into a
   line they have to read. The facts now sit behind this, opened by CLICK
   rather than hover, because hover does not exist on a phone and the
   injury detail had been trapped in a title attribute for exactly that
   reason. */
.lw-i{
  display:inline-grid;place-items:center;vertical-align:.05em;margin-left:7px;
  width:15px;height:15px;padding:0;border-radius:50%;
  border:1.5px solid var(--lw-ink-45);background:transparent;color:var(--lw-ink-45);
  font-family:inherit;font-size:9.5px;font-weight:var(--lw-w-black);font-style:italic;
  line-height:1;cursor:pointer;letter-spacing:0;flex:none;
  position:relative;
}
/* The circle is 15px because that is the size that sits properly beside
   9.5px meta text, and it should stay 15px. What it should not be is a
   15px TARGET: that is a third of what a finger needs, repeated once per
   row down a 200-player board, and the panel behind it is the only place
   the injury and market detail lives on a phone.

   So the target grows and the circle does not. The pseudo-element is
   invisible, centred on the button, and part of it, so a tap anywhere in
   40px opens the right player's panel.

   40 and not Apple's 44: a board row is around 48px, so 44px targets on
   consecutive rows can meet in the middle and open the player above the
   one that was aimed at. Being slightly under the guideline beats being
   accurate about the wrong player.

   pointer:coarse, so this is a finger's problem and a finger's fix. A
   mouse already hits 15px, and an invisible 40px pad around every circle
   on a 200-row board would sit over the player names and swallow the
   drag that selects one. */
@media (pointer:coarse){
  .lw-i::after{
    content:"";position:absolute;top:50%;left:50%;
    width:40px;height:40px;transform:translate(-50%,-50%);
  }
}
.lw-i:hover{border-color:var(--lw-ink);color:var(--lw-ink);}
.lw-i:focus-visible{outline:none;box-shadow:0 0 0 2px var(--lw-yellow);}
.lw-i[aria-expanded="true"]{background:var(--lw-ink);border-color:var(--lw-ink);color:var(--lw-paper);}

/* Sentences, not the mono fragments the slate uses: there is room in here,
   and the panel is read rather than scanned. Normal case on purpose, since
   the meta row around it is uppercase and tracked. */
.lw-mkt{
  display:block;margin:6px 0 2px;padding:8px 11px;
  border:var(--lw-border) solid var(--lw-ink);border-radius:10px;
  background:var(--lw-paper);
  font-size:12px;font-weight:var(--lw-w-bold);letter-spacing:0;line-height:1.45;
  text-transform:none;color:var(--lw-ink);white-space:normal;
}
.lw-mkt span{display:block;}
.lw-mkt span + span{margin-top:3px;}
.lw-mkt[hidden]{display:none;}

/* The board search. It sits above the column heads, which is where the
   first row begins as far as anyone reading is concerned, and it pins
   there so a name typed 60 rows down still has somewhere to go. */
.lw-find{
  position:sticky;top:0;z-index:26;background:var(--lw-paper);
  padding:10px 0 8px;display:flex;align-items:center;gap:10px;
}
.lw-find input{
  flex:1 1 auto;min-width:0;height:46px;padding:0 18px;
  font-family:inherit;font-size:14.5px;color:var(--lw-ink);background:var(--lw-paper);
  border:var(--lw-border) solid var(--lw-ink);border-radius:var(--lw-radius-pill);
}
.lw-find input::placeholder{color:var(--lw-ink-45);}
.lw-find input:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--lw-yellow);}
.lw-find input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none;}
.lw-find .lw-find-x{
  flex:none;height:46px;padding:0 16px;border-radius:var(--lw-radius-pill);
  border:var(--lw-border) solid var(--lw-ink);background:var(--lw-paper);color:var(--lw-ink);
  font-family:inherit;font-size:12px;font-weight:var(--lw-w-black);
  letter-spacing:.12em;text-transform:uppercase;cursor:pointer;
}
.lw-find .lw-find-x[hidden]{display:none;}
.lw-find-none{
  padding:26px 4px;font-size:14px;font-weight:var(--lw-w-bold);color:var(--lw-ink-45);
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important;}
}

/* ---------- the field-zoom guard ----------
   Safari on iOS zooms the whole page in whenever a field it focuses is
   under 16px, and it does not zoom back out when the field is left. The
   member is then stranded on a page wider than the screen, scrolling
   sideways to read a board they were only trying to search.

   Every field on this site was under 16px — the login pair at 14.5, the
   player searches at 12.5 to 14.5, the league sync fields at 15, the
   Rankings Game's fifty rank boxes at 15 — so it fired on signing in,
   on searching any board, on syncing a league and on entering the
   competition. Nothing sets maximum-scale to suppress it, and nothing
   should: that would fix the symptom by taking pinch-zoom away from
   people who need it.

   Here rather than in seventeen page rules, because the next field
   somebody adds would otherwise bring the bug back with it. `!important`
   because the page-level rules it has to beat are more specific and load
   after this file; this is a floor, not a preference. Phones only, so
   the tighter type the desktop layouts are built around is untouched.

   Checkboxes and radios are exempt: they render no text, and iOS does
   not zoom for them. */
@media (max-width:760px){
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea{
    font-size:16px!important;
  }
}
