
  .flag.svelte-1xqp54w {
    /* Sized in em, so it scales with whatever text it sits next to rather than
       needing its own step on the type scale. */
    width: 1em;
    height: auto;
    margin-left: 0.4em;
    vertical-align: -0.1em;
    border-radius: 2px;
    /* The white cross would otherwise bleed into a white row. */
    border: 1px solid rgba(0, 0, 0, 0.15);
  }


  .custom-dropdown.svelte-1f0skxm {
    position: relative;
    user-select: none;
  }

  .dropdown-trigger.svelte-1f0skxm {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background-color: var(--accent-muted);
    border: 1px solid var(--accent-line);
    border-radius: 10px;
    color: var(--accent-ink);
    font-size: var(--text-md, 1.3125rem);
    font-weight: 700;
    cursor: pointer;
    transition: all 0.2s ease;
    /* In ch so the trigger tracks the type scale like its label does; a fixed
       px minimum left the button oversized at the small end. */
    min-width: 8ch;
    justify-content: space-between;
    -webkit-tap-highlight-color: transparent;
  }

  .dropdown-trigger.svelte-1f0skxm:active {
    background-color: var(--accent-soft);
    transform: scale(0.98);
  }

  .dropdown-trigger.svelte-1f0skxm:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }

  .trigger-label.svelte-1f0skxm,
  .item-label.svelte-1f0skxm {
    flex: 1;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .chevron.svelte-1f0skxm {
    flex: none;
    width: 18px;
    height: 18px;
    transition: transform 0.2s ease;
    color: var(--accent-ink);
  }

  .chevron.open.svelte-1f0skxm {
    transform: rotate(180deg);
  }

  .dropdown-menu.svelte-1f0skxm {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    background-color: #fff;
    border-radius: 12px;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
    padding: 6px;
    min-width: 100%;
    width: max-content;
    max-width: 70vw;
    z-index: 200;
    border: 1px solid rgba(0, 0, 0, 0.05);
    display: flex;
    flex-direction: column;
    gap: 4px;
    animation: svelte-1f0skxm-slideIn 0.2s ease-out;
  }

  @keyframes svelte-1f0skxm-slideIn {
    from {
      opacity: 0;
      transform: translateY(-10px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  .dropdown-item.svelte-1f0skxm {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border: none;
    background: none;
    border-radius: 8px;
    color: #4a5568;
    font-size: var(--text-md, 1.3125rem);
    font-weight: 600;
    cursor: pointer;
    text-align: left;
    transition: background-color 0.2s;
    -webkit-tap-highlight-color: transparent;
  }

  .dropdown-item.svelte-1f0skxm:hover {
    background-color: #f7fafc;
  }

  /* Arrow-key navigation is pointless if you can't see where you are. Applies
     to the trigger too, which previously showed only the browser default. */
  .dropdown-trigger.svelte-1f0skxm:focus-visible,
  .dropdown-item.svelte-1f0skxm:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
  }

  .dropdown-item.selected.svelte-1f0skxm {
    background-color: var(--accent-soft);
    color: var(--accent-ink);
  }

  .check-icon.svelte-1f0skxm {
    flex: none;
    width: 16px;
    height: 16px;
    color: var(--accent-ink);
  }


  body {
    margin: 0;
    padding: 0;
    background-color: #f9f9fb;
    color: #333;
    font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  }

  main.svelte-1n46o8q {
    /* --- Type scale ---
       Every font-size in the app, this component and Dropdown alike, resolves
       to one of these five steps, so changing the scale is one edit rather than
       a dozen.

       They are in rem on purpose: rem follows the reader's browser and OS font
       setting, which px silently ignores. Someone who has turned text size up
       system-wide now gets that here too.

       --text-scale multiplies the lot. The rem values below are the sizes the
       app shipped with over a 16px root, so scale 1 reproduces those exactly;
       0.7 was picked after trying the range, and 0.75 is one step up from
       that. It was a
       reader-facing dropdown for a while -- that came out again, so this is the
       one number to edit to resize the whole app.

       Custom properties inherit, so child components pick these up without any
       prop passing; the palette above works the same way. */
    --text-scale: 0.75;

    --text-xs: calc(1.125rem * var(--text-scale, 1)); /* 18px at scale 1 */
    --text-sm: calc(1.1875rem * var(--text-scale, 1)); /* 19px */
    --text-md: calc(1.3125rem * var(--text-scale, 1)); /* 21px */
    --text-lg: calc(1.6875rem * var(--text-scale, 1)); /* 27px */
    --text-xl: calc(2.5rem * var(--text-scale, 1)); /* 40px */

    width: 100%;
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
  }

  /* --- Navbar --- */
  .navbar.svelte-1n46o8q {
    background-color: #fff;
    min-height: 60px;
    display: flex;
    align-items: center;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    position: sticky;
    top: 0;
    z-index: 100;
  }

  .navbar-content.svelte-1n46o8q {
    width: 100%;
    padding: 10px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 15px;
  }

  .logo.svelte-1n46o8q {
    font-size: var(--text-xl);
    font-weight: 800;
    color: var(--accent-ink);
    letter-spacing: 1px;
  }

  .controls.svelte-1n46o8q {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    /* Without this the row sizes to max-content once it wraps below the logo,
       so its own flex-wrap never triggers and the last control is pushed off
       the right edge instead of onto a second line. */
    flex: 1 1 auto;
    min-width: 0;
  }

  /* --- Checkbox --- */
  .checkbox-label.svelte-1n46o8q {
    display: flex;
    align-items: center;
    cursor: pointer;
    gap: 10px;
  }

  .checkbox-label.svelte-1n46o8q input[type="checkbox"]:where(.svelte-1n46o8q) {
    width: 18px;
    height: 18px;
    cursor: pointer;
    accent-color: var(--accent);
  }

  .checkbox-text.svelte-1n46o8q {
    font-size: var(--text-md);
    font-weight: 600;
    color: #333;
    white-space: nowrap;
  }

  /* --- Scroll Container --- */
  .scroll.svelte-1n46o8q {
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Stops a drag past the top from chaining out to the document, where the
       browser would start its own pull-to-refresh on top of ours. */
    overscroll-behavior-y: contain;
  }

  /* Visible to a screen reader, not on screen. The clip-rect form rather than
     display:none or visibility:hidden, both of which hide it from the reader
     too and would defeat the point. */
  .sr-only.svelte-1n46o8q {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  /* --- Pull to refresh --- */
  .pull-indicator.svelte-1n46o8q {
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    color: #4a5568;
  }

  /* Only when the finger is off: animating during the drag would make the
     indicator lag the pull. */
  .pull-indicator.settling.svelte-1n46o8q {
    transition: height 0.2s ease-out;
  }

  .pull-text.svelte-1n46o8q {
    font-size: var(--text-xs);
    font-weight: 600;
    white-space: nowrap;
  }

  .pull-text.ready.svelte-1n46o8q {
    color: var(--accent-ink);
  }

  /* --- Match List --- */
  .day.svelte-1n46o8q {
    /* The day's heading sticks; without this the section establishes nothing
       and the sticky offset is measured against the scroll container. */
    position: relative;
  }

  .match-list.svelte-1n46o8q {
    max-width: 100%;
    margin: 0 auto;
    /* It is a <ul> now, for the list semantics a screen reader needs. None of
       the default list chrome is wanted. */
    list-style: none;
    padding: 0;
  }

  /* h2/h3 now rather than divs, so the day and league headings are real
     headings. Their default margins would break the flush-to-edge banding. */
  .date-header.svelte-1n46o8q,
  .league-header.svelte-1n46o8q {
    margin: 0;
  }

  .date-header.svelte-1n46o8q {
    background-color: var(--accent);
    padding: 12px 20px;
    font-size: var(--text-md);
    font-weight: 800;
    color: var(--accent-contrast);
    position: sticky;
    top: 0;
    z-index: 20;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    letter-spacing: 0.5px;
  }

  .league-header.svelte-1n46o8q {
    background-color: var(--accent-soft);
    padding: 10px 20px;
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--accent-ink);
    border-bottom: 1px solid var(--accent-line-soft);
    text-transform: uppercase;
    letter-spacing: 1px;
  }

  .league-name-inline.svelte-1n46o8q {
    font-size: var(--text-xs);
    font-weight: 600;
    color: #4a5568;
    margin-top: 2px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }

  .match-row.svelte-1n46o8q {
    display: flex;
    align-items: flex-start;
    /* Clears the sticky day and league headings when scrollToNow() brings a
       row to the top; without it the first row lands underneath them. */
    scroll-margin-top: 5rem;
    padding: 14px 20px;
    background-color: #fff;
    border-bottom: 1px solid #edf2f7;
    gap: 16px;
    transition: background-color 0.2s ease;
  }

  .match-row.svelte-1n46o8q:hover {
    background-color: #f8fafc;
  }

  /* A fixture that kicked off and one that starts in six hours used to look
     identical. The bar is the at-a-glance cue; the NU badge carries the same
     information in text for anyone the colour doesn't reach. */
  .match-row.live.svelte-1n46o8q {
    box-shadow: inset 3px 0 0 var(--accent);
    background-color: var(--accent-muted);
  }

  /* A background tint rather than opacity. Dimming the row to 0.55 would drag
     the muted greys down to roughly 2.6:1 and undo the contrast fix a few rules
     below; the badge does the distinguishing instead. */
  .match-row.finished.svelte-1n46o8q {
    background-color: #f1f5f9;
  }

  .state-badge.svelte-1n46o8q {
    display: inline-block;
    margin-top: 2px;
    padding: 1px 6px;
    border-radius: 4px;
    font-size: var(--text-xs);
    font-weight: 800;
    letter-spacing: 0.5px;
  }

  .state-badge.live.svelte-1n46o8q {
    background-color: var(--accent);
    color: var(--accent-contrast);
  }

  .state-badge.finished.svelte-1n46o8q {
    background-color: #e2e8f0;
    color: #4a5568;
  }

  .retry.svelte-1n46o8q {
    padding: 10px 20px;
    border: 1px solid var(--accent-line);
    border-radius: 10px;
    background-color: var(--accent-muted);
    color: var(--accent-ink);
    font-size: var(--text-md);
    font-weight: 700;
    cursor: pointer;
  }

  .retry.svelte-1n46o8q:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
  }

  .match-time.svelte-1n46o8q {
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--accent-ink);
    /* ch is one digit wide, so the column tracks the font instead of needing a
       matching px bump every time the scale changes. flex-shrink: 0 is what
       actually stops "20:45" breaking across two lines when the row is tight. */
    min-width: 5ch;
    flex-shrink: 0;
    /* Equal-width digits, so kick-off times line up column-wise. */
    font-variant-numeric: tabular-nums;
    /* Column so the NU/SLUT badge sits under the time instead of widening it. */
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }

  .match-info.svelte-1n46o8q {
    flex: 1;
    min-width: 0;
  }

  .teams.svelte-1n46o8q {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    font-size: var(--text-lg);
    font-weight: 700;
    color: #2d3748;
  }

  .team-name.svelte-1n46o8q {
    /* Truncates again, now that a tap on a cut name shows it in full (see
       showTruncated). The name is its own span so the ellipsis lands on the
       name and the flag after it is never the part that gets cut. */
    display: flex;
    align-items: center;
    max-width: 100%;
  }

  .team-name.svelte-1n46o8q .flag {
    flex-shrink: 0;
  }

  .players.svelte-1n46o8q {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 4px;
  }

  .players-side.svelte-1n46o8q {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
  }

  /* Names the club once for the row of tags that follows it, replacing the
     "(Club)" that used to be repeated inside every single tag. */
  .players-club.svelte-1n46o8q {
    font-size: var(--text-xs);
    font-weight: 700;
    color: #4a5568;
  }

  .player-tag.svelte-1n46o8q {
    font-size: var(--text-xs);
    /* Was #718096: 3.8:1 here and 4.0:1 on white, both under the 4.5:1 WCAG AA
       wants at this size. #4a5568 is 7.2:1 here, 7.5:1 on white -- and the
       same grey was used for league names and messages, so all three moved. */
    color: #4a5568;
    background-color: #f7fafc;
    padding: 1px 6px;
    border-radius: 4px;
    border: 1px solid #edf2f7;
    white-space: nowrap;
  }

  .match-channels.svelte-1n46o8q {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
    margin-bottom: 4px;
  }

  .channel-tag.svelte-1n46o8q {
    background-color: var(--accent-muted);
    color: var(--accent-ink);
    font-size: var(--text-xs);
    padding: 3px 8px;
    border-radius: 4px;
    font-weight: 700;
    white-space: nowrap;
    border: 1px solid var(--accent-line);
  }

  /* --- Truncation & toast --- */
  .truncate.svelte-1n46o8q {
    max-width: 100%;
    min-width: 0;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .toast.svelte-1n46o8q {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    max-width: calc(100% - 32px);
    box-sizing: border-box;
    padding: 12px 16px;
    border: none;
    border-radius: 10px;
    background-color: #2d3748;
    color: #fff;
    font: inherit;
    font-size: var(--text-md);
    font-weight: 600;
    text-align: left;
    overflow-wrap: anywhere;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
    z-index: 300;
    cursor: pointer;
    animation: svelte-1n46o8q-toast-in 0.2s ease-out;
  }

  @keyframes svelte-1n46o8q-toast-in {
    from {
      opacity: 0;
      transform: translate(-50%, 10px);
    }
    to {
      opacity: 1;
      transform: translate(-50%, 0);
    }
  }

  /* --- Loading, error & empty states --- */
  .message-container.svelte-1n46o8q {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px;
    gap: 16px;
  }

  .spinner.svelte-1n46o8q {
    width: 30px;
    height: 30px;
    border: 3px solid #e2e8f0;
    border-top: 3px solid var(--accent);
    border-radius: 50%;
    animation: svelte-1n46o8q-spin 0.8s linear infinite;
  }

  /* For the pull indicator, which has 40px to sit in. */
  .spinner.small.svelte-1n46o8q {
    width: 20px;
    height: 20px;
    border-width: 2px;
  }

  @keyframes svelte-1n46o8q-spin {
    to {
      transform: rotate(360deg);
    }
  }

  .message-text.svelte-1n46o8q {
    font-size: var(--text-md);
    color: #4a5568;
    font-weight: 500;
  }

