/* base.css — CSS variables, reset, shared body, header, and toast */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  color-scheme: dark;
  --bg:           #0f1410;
  --surface:      #181f1a;
  --surface2:     #1f2921;
  --border:       #2e3d30;
  --blue:         #1a5fa8;
  --blue-lt:      #4a90d9;
  --gold:         #c49a1a;
  --gold-lt:      #e8b82a;
  --text:         #e8ede9;
  --text-dim:     #7a8f7d;
  --text-mute:    #5f7862;
  --win-color:    #4a9a4a;
  --lose-color:   #c05050;
  --elim-bg:      #2a1f1f;
  --elim-text:    #8a5a5a;
  --line-color:   #4a7a8a;
  --clear-color:  #c05050;
  --clear-border: #8a3a3a;
  --live-color:   #e03030;
  /* Diagonal hatch behind a "Potential Outcome" card. A plain rgba (not a
     color-mix on --blue-lt) because the bracket image exporter reads this
     token straight into a canvas fillStyle, which parses CSS colours but not
     colour functions. Keep it in every theme block below. */
  --proj-hatch:   rgba(74, 144, 217, 0.17);

  /* Medal colors for bucket top-3 */
  --medal-gold-bg:     #3d2d00;
  --medal-gold-border: #7a5c10;
  --medal-gold-text:   #f2c83a;
  --medal-silver-bg:   #1e2630;
  --medal-silver-border:#40566a;
  --medal-silver-text: #a8c0d0;
  --medal-bronze-bg:   #2d1600;
  --medal-bronze-border:#5c3018;
  --medal-bronze-text: #c87840;

  /* Per-field tag colors (defaults; user-overridable in Settings > Fields) */
  --field-1: #0d9488; /* teal */
  --field-2: #ea580c; /* orange */
  --field-3: #7c3aed; /* purple */
  --field-4: #db2777; /* pink */
  --field-5: var(--blue-lt);

  /* Border radius scale */
  --radius-sm: 0.35em;
  --radius-xs: 0.2em;
  --radius-md: 0.6em;

  /* Type scale */
  --text-xs: 0.72rem;
  --text-sm: 0.78rem;
  --text-md: 0.9rem;
  --text-lg: 1rem;

  /* Button sizing tokens — change here to resize all buttons at once */
  --btn-font-size: var(--text-sm);
  --btn-pad-v:     0.55em;
  /* Horizontal padding tiers: standard for full buttons, compact for
     dense toolbars (mode switchers, inline clears). Anything else is a
     deliberate one-off and should say why. */
  --btn-pad-h:         1.1em;
  --btn-pad-h-compact: 0.6em;
  --btn-h:         1.8rem;

  /* Bracket slot sizing — set by JS via setProperty */
  --slot-h:    10vh;
  --card-h:    8vh;
  --row-h:     calc(var(--card-h) / 3);
  --col-w:     14vw;
  --col-gap:   2vw;
  --col-hdr-h: 1.6em;
}

body.light {
  color-scheme: light;
  --bg:        #f0f4f1;
  --surface:   #ffffff;
  --surface2:  #e8ede9;
  --border:    #c8d8ca;
  --blue:      #1a5fa8;
  --blue-lt:   #1a4a8a;
  --gold:      #a07800;
  --gold-lt:   #7a5800;
  --text:      #1a2a1c;
  --text-dim:  #4a6a50;
  --text-mute: #557a5b; /* ≥4.5:1 on white surface (WCAG AA) */
  --win-color: #2a6a18;
  --lose-color:#8a2a2a;
  --elim-bg:   #f5e8e8;
  --elim-text: #8a4a4a;
  --line-color:#5a8a9a;
  --clear-color:#8a2a2a;
  --clear-border:#c05050;
  --live-color: #c81e1e; /* ≥4.5:1 on white surface */
  --proj-hatch:rgba(26, 74, 138, 0.16);

  /* Medal colors — light mode */
  --medal-gold-bg:     #fffacc;
  --medal-gold-border: #c8a000;
  --medal-gold-text:   #5a3c00;
  --medal-silver-bg:   #e4edf5;
  --medal-silver-border:#7090a8;
  --medal-silver-text: #283848;
  --medal-bronze-bg:   #f5e8d8;
  --medal-bronze-border:#a86030;
  --medal-bronze-text: #4a2010;

  /* Per-field tag colors — darker shades for AA contrast on light surfaces.
     --field-5 references --blue-lt, which is already overridden above. */
  --field-1: #0f766e; /* teal */
  --field-2: #c2410c; /* orange */
  --field-3: #6d28d9; /* purple */
  --field-4: #be185d; /* pink */
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Barlow', sans-serif;
  font-size: clamp(0.92rem, 0.08vw + 0.9rem, 1rem);
  min-height: 100vh;
  min-height: 100svh;
  transition: background 0.2s, color 0.2s;
}

/* ── Header name block ── */
.header-name-block { flex: 1; min-width: 0; }
/* The name block is flex:1, so it stretches to the controls — but the click
   target for goHome must hug the TEXT, or a click in the empty space beside
   a short tournament name would navigate. fit-content shrinks the h1 and
   subtitle boxes to their content without touching the header's layout. */
#siteName, .site-subtitle { width: fit-content; max-width: 100%; }
/* goHome fires at every width since 2026-08-02 (owner), so the affordance is
   no longer gated on the desktop breakpoint. The hover half stays harmless on
   touch, where :hover simply never matches. */
.site-logo[data-action], #siteName[data-action], .site-subtitle[data-action] { cursor: pointer; }
#siteName[data-action]:hover, .site-logo[data-action]:hover { opacity: 0.82; }
.site-subtitle[data-action]:hover { opacity: 0.82; }
.site-subtitle {
  display: block;
  visibility: hidden;
  font-size: 0.65em;
  color: var(--gold);
  font-family: 'Oswald', sans-serif;
  letter-spacing: 0.12em;
  margin-top: 0.1em;
}

/* ── Header ── */
.site-header {
  background: var(--surface);
  border-bottom: 0.15em solid var(--gold);
  padding: 0.8em 1em;
  padding-top: max(0.8em, calc(0.8em + env(safe-area-inset-top, 0px)));
  display: flex;
  align-items: center;
  gap: 0.8em;
  position: sticky;
  top: 0;
  z-index: 100;
}
.site-header h1 {
  font-family: 'Oswald', sans-serif;
  font-size: clamp(1.05rem, 0.18vw + 1rem, 1.35rem);
  font-weight: 700;
  color: var(--gold-lt);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  line-height: 1;
}
.header-controls { margin-left: auto; display: flex; align-items: center; gap: 0.6em; }

/* Public page only: Edit (bracket layout / bucket challenge) sits next to the
   hamburger rather than behind it — owner, 2026-08-01, wants a primary action
   always reachable rather than one tap further in. Wrapping it WITH the
   hamburger, rather than giving Edit its own margin-left:auto, is what keeps
   the two adjacent regardless of how long the tournament name runs: only ONE
   thing in the row needs to claim the free space, and .header-menu-btn's own
   auto margin (still in effect on every OTHER page, which has no cluster) is
   overridden back to 0 here so it does not fight this wrapper for it. */
.header-menu-cluster { margin-left: auto; display: flex; align-items: center; gap: 0.5em; flex-shrink: 0; }
.header-menu-cluster .header-menu-btn { margin-left: 0; }
/* Edit's height comes from .admin-public-btn's padding, which doesn't land on
   the same pixel height as the theme toggle / hamburger's fixed 2.75rem box —
   owner, 2026-08-02: "set the edit button to match the height of the other
   two". Pinned here rather than in .admin-public-btn itself, which other
   (non-cluster) buttons still size by padding. */
.header-menu-cluster .admin-public-btn { height: 2.75rem; }

/* Theme toggle: a persistent icon button beside the hamburger on every page,
   not text buried at the bottom of the collapsible menu (owner, 2026-08-01:
   "I still don't like the light/mode dark mode. Move it back to the image
   icon and place it a touch further left of the hamburger menu"). Sized to
   match .header-menu-btn so the two sit as a matched pair; the cluster's own
   gap is what puts a "touch" of space between it and the hamburger. */
.theme-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  flex-shrink: 0;
  padding: 0;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  color: var(--text-dim);
  cursor: pointer;
  touch-action: manipulation;
}
.theme-toggle-btn .theme-icon { width: 1.55rem; height: 1.55rem; display: block; }

/* Outline "cancel / dismiss" button. Lives HERE, not in admin.css, because
   index.html does not load admin.css — the Save-image dialog's Cancel, the
   Team Path stepper's Back/Done and the notification panel's Close all carried
   this class and rendered as raw browser buttons. One definition, both pages. */
.admin-clear-btn { font-family: 'Oswald', sans-serif; font-size: var(--btn-font-size); font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; padding: var(--btn-pad-v) var(--btn-pad-h-compact); border-radius: var(--radius-xs); border: 0.07em solid var(--clear-border); background: transparent; color: var(--clear-color); cursor: pointer; }
.admin-clear-btn:hover,
.admin-clear-btn:active { background: color-mix(in srgb, var(--lose-color) 10%, transparent); }


/* Narrow screens: the persistent cluster (theme toggle + hamburger, plus
   Edit when visible) must always stay ON the header's one row and fit
   within the viewport width — letting the whole header wrap put the
   cluster on its OWN row below the name, which grew the header far taller
   than the actual content needed even for a short tournament name (owner,
   2026-08-02: "the header can't grow this large, buttons have to fit in
   the max width"). So .site-header itself no longer wraps; instead
   .header-name-block (flex:1, min-width:0 from the base rule above) is
   free to SHRINK to whatever room is left beside the logo and the cluster
   (which stays flex-shrink:0), and the name/subtitle text wraps onto
   multiple lines WITHIN that narrower column — still never a true
   one-word-per-line sliver on a typical name, just no longer guaranteed a
   14em floor when space is genuinely tight. The display type drops its
   wide tracking so multi-line names stay compact either way. */
@media (max-width: 720px) {
  .header-name-block { flex: 1 1 14em; }
  .site-header h1 { letter-spacing: 0.1em; line-height: 1.15; }
  .header-controls { flex-wrap: wrap; justify-content: flex-end; row-gap: 0.35em; }
  /* Phones: the logo shares a row with a name that can wrap to three lines,
     so cap it below the desktop step rather than letting it set the header
     height. --logo-h-sm is the same scale one notch down. */
  .site-logo { height: var(--logo-h-sm, 2.8em); max-width: var(--logo-maxw-sm, 6.5em); }
}
/* Cross-app toggle button (admin ↔ public) — shared by all pages. The theme
   toggle uses this too now (owner, 2026-07-31: match the other menu
   buttons, text not an icon) — its own .theme-toggle rules are gone, not
   just unused; nothing references that class anymore. */
.admin-public-btn {
  font-family: 'Oswald', sans-serif;
  font-size: var(--btn-font-size);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: var(--btn-pad-v) 0.88em;
  border-radius: var(--radius-xs);
  border: 0.07em solid var(--border);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
}
.admin-public-btn:hover,
.admin-public-btn:active { color: var(--text); border-color: var(--text-dim); }

/* Results timestamp — end-justified in header name div */
.header-timestamp {
  font-family: 'Barlow', sans-serif;
  font-size: 0.62rem;
  color: var(--text-mute);
  letter-spacing: 0.04em;
  margin-top: 0.3em;
  text-align: right;
}

/* ── Toast ── */
.toast { position: fixed; bottom: 1.5em; left: 50%; transform: translateX(-50%) translateY(1.2em); background: var(--surface2); border: 0.07em solid var(--blue); border-radius: 0.4em; padding: 0.6em 1.2em; font-size: 0.84rem; color: var(--blue-lt); opacity: 0; transition: all 0.25s; pointer-events: none; z-index: 999; white-space: nowrap; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.error { border-color: var(--clear-color); color: var(--clear-color); }

/* ── Focus-visible ring ── */
button:focus-visible,
[role="tab"]:focus-visible,
a:focus-visible,
select:focus-visible,
.view-tab:focus-visible,
.team-chip:focus-visible,
.lineup-tool-btn:focus-visible { outline: 0.13em solid var(--blue-lt); outline-offset: 0.15em; }

/* ── Primary buttons (shared baseline) ── */
.admin-save-btn,
.sched-save-btn,
.bucket-edit-save-btn,
.lineup-submit-btn {
  font-family: 'Oswald', sans-serif;
  font-size: var(--btn-font-size);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: var(--btn-pad-v) var(--btn-pad-h);
  border-radius: var(--radius-xs);
  background: var(--blue);
  color: #fff;
  border: 0.07em solid var(--blue);
  cursor: pointer;
}
.admin-save-btn:hover, .admin-save-btn:active,
.sched-save-btn:hover, .sched-save-btn:active,
.bucket-edit-save-btn:hover, .bucket-edit-save-btn:active,
.lineup-submit-btn:hover, .lineup-submit-btn:active { background: var(--blue-lt); border-color: var(--blue-lt); }
.admin-save-btn:disabled,
.sched-save-btn:disabled,
.bucket-edit-save-btn:disabled,
.lineup-submit-btn:disabled { opacity: 0.5; cursor: not-allowed; }

@media (max-width: 1023px) {
  .toast { bottom: calc(6em + env(safe-area-inset-bottom, 0px)); }
}

/* ── Touch target sizing (coarse pointer = touchscreen) ── */
@media (pointer: coarse) {
  .admin-public-btn { min-height: 2.75rem; }
}

/* Per-tournament header logo (white-label). Set via img.src from the
   validated theme-colors logo data URI; hidden when none is configured.
   Size comes from --logo-h / --logo-maxw, which applyThemeColors() sets from
   the tournament's logoScale — a wordmark and a round crest want very
   different heights, so one hardcoded number is wrong for somebody. The
   fallbacks here are the 'md' step, i.e. what a tournament gets before it
   ever touches the setting. */
.site-logo {
  height: var(--logo-h, 3.4em);
  width: auto;
  max-width: var(--logo-maxw, 8.5em);
  object-fit: contain;
  border-radius: 0.25em;
  margin-right: 0.15em;
  align-self: center;
}

/* ── tt-dialog: shared in-app confirm/prompt (tt-common.js ttDialog) ── */
.tt-dialog-overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: rgba(0,0,0,0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1em;
}
.tt-dialog {
  background: var(--surface);
  border: 0.07em solid var(--border);
  border-radius: 0.5em;
  padding: 1.3em 1.3em 1.1em;
  width: min(92vw, 26em);
  display: flex;
  flex-direction: column;
  gap: 1em;
  box-shadow: 0 8px 28px rgba(0,0,0,0.55);
}
.tt-dialog-msg {
  font-family: 'Barlow', sans-serif;
  font-size: var(--text-md);
  color: var(--text);
  line-height: 1.5;
  white-space: pre-line;   /* messages use \n for emphasis lines */
}
.tt-dialog-input {
  font-family: 'Barlow', sans-serif;
  font-size: max(1rem, 16px);
  padding: 0.45em 0.55em;
  border-radius: var(--radius-xs);
  border: 0.07em solid var(--border);
  background: var(--surface2);
  color: var(--text);
}
.tt-dialog-input:focus { outline: 0.13em solid var(--blue-lt); border-color: var(--blue-lt); }
.tt-dialog-actions {
  display: flex;
  gap: 0.6em;
  justify-content: flex-end;
  /* Three-answer dialogs (save / discard / cancel) don't fit one phone row. */
  flex-wrap: wrap;
}
.tt-dialog-btn {
  font-family: 'Oswald', sans-serif;
  font-size: var(--btn-font-size);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: var(--btn-pad-v) var(--btn-pad-h);
  border-radius: var(--radius-xs);
  border: 0.07em solid var(--border);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
}
.tt-dialog-btn:hover { color: var(--text); border-color: var(--text-dim); }
.tt-dialog-btn--primary {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
}
.tt-dialog-btn--primary:hover { opacity: 0.88; color: #fff; }
.tt-dialog-btn--danger {
  background: var(--lose-color);
  border-color: var(--lose-color);
}
@media (pointer: coarse) { .tt-dialog-btn { min-height: 44px; } }

/* ── Print: force a white-paper palette ──────────────────────────────────
   Everything derives from the tokens, so overriding them (at body AND
   body.light specificity, after the theme blocks, so print wins in either
   theme) restyles the whole app for paper. */
/* Paper palette: black on white, minimal ink, no tinted panels.
   Applied two ways — automatically when printing (the @media block below)
   and on demand by the bracket image exporter, which adds .print-palette to
   get the same look in a PNG a TD is going to print or photocopy.
   KEEP THE TWO TOKEN LISTS IN SYNC: CSS can't share one declaration block
   between a class and a media query. */
body.print-palette,
body.print-palette.light {
  color-scheme: light;
  --bg:        #ffffff;
  --surface:   #ffffff;
  --surface2:  #ffffff;
  --border:    #999999;
  --blue:      #1a4a8a;
  --blue-lt:   #1a4a8a;
  --gold:      #7a5800;
  --gold-lt:   #7a5800;
  --text:      #000000;
  --text-dim:  #333333;
  --text-mute: #555555;
  --win-color: #2a6a18;
  --lose-color:#8a2a2a;
  --line-color:#666666;
  --live-color:#c81e1e;
  --proj-hatch:rgba(0, 0, 0, 0.13);
}
body.print-palette * { box-shadow: none !important; text-shadow: none !important; }

@media print {
  body, body.light {
    color-scheme: light;
    --bg:        #ffffff;
    --surface:   #ffffff;
    --surface2:  #f2f2f2;
    --border:    #999999;
    --blue:      #1a4a8a;
    --blue-lt:   #1a4a8a;
    --gold:      #7a5800;
    --gold-lt:   #7a5800;
    --text:      #000000;
    --text-dim:  #333333;
    --text-mute: #555555;
    --win-color: #2a6a18;
    --lose-color:#8a2a2a;
    --line-color:#666666;
    --live-color:#c81e1e;
    --proj-hatch:rgba(0, 0, 0, 0.13);
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
  * { box-shadow: none !important; text-shadow: none !important; }
}

/* The hidden attribute must always win: JS toggles visibility exclusively
   via el.hidden (CSP forbids inline style attributes), and several hidden
   elements carry classes whose display rules would otherwise override the
   UA default. */
[hidden] { display: none !important; }
.u-mx-auto { margin: 0 auto; }
/* CSP refactor: spacing/visibility utilities replacing one-off inline styles */
.u-invisible { visibility: hidden; }
.u-dim-70 { opacity: 0.7; }
.u-push-right-b { margin-left: auto; }
.u-flexrow-gap { display: flex; gap: 0.6em; margin-top: 0.5em; }
.u-mt-05 { margin-top: 0.5em; }
.u-mt-06 { margin-top: 0.6em; }
.u-mt-075 { margin-top: 0.75em; }
.u-mt-09 { margin-top: 0.9em; }
.u-mt-1 { margin-top: 1em; }
.u-mt-15 { margin-top: 1.5em; }
.u-mb-06 { margin-bottom: 0.6em; }
.u-mb-1 { margin-bottom: 1em; }
.u-maxw-10 { max-width: 10em; }

/* Paper mode, continued: flatten everything that spends ink for decoration
   only. Field tags carry their colour INLINE (per-tournament field palette),
   so they need !important to be overridden; the championship tint, the
   losers-final panel and card-header fills are all just emphasis. Win/loss
   colours are deliberately KEPT — dark green and dark red are cheap and they
   carry meaning a photocopy still needs. */
body.print-palette .game-field-tag {
  color: var(--text-dim) !important;
  border-color: var(--border) !important;
  background: none !important;
}
body.print-palette .champ-center--desktop,
body.print-palette .champ-center--flight,
body.print-palette .champ-center--ifnec,
body.print-palette .flight-col--champ,
body.print-palette .bc-hdr,
body.print-palette .admin-res-hdr {
  background: none !important;
}
body.print-palette .champ-center--desktop,
body.print-palette .flight-col--champ {
  border-color: var(--border) !important;
}

/* ── Header menu — EVERY width ─────────────────────────────────────────
 Was mobile-only, behind a max-width:1279px query. The header kept growing —
 Share, Project winners, Notifications, theme, Refresh, Edit, a panel link —
 and a row of seven chips is no tidier on a laptop than on a phone, so the
 hamburger now applies at all widths (owner, 2026-07-30).

 updateHeaderMenu() still decides WHETHER to show it (two or more visible
 controls), so a page with one control keeps it inline. Nothing here is
 breakpoint-dependent any more; the rules just needed un-nesting. */
/* REM, NOT EM — this is the whole reason the button looked right in desktop
   DevTools and shrank to nothing in the installed PWA. A <button> does not
   inherit font-size: the UA stylesheet gives it its own (13.3px in Chrome,
   different in iOS Safari), so an em size here resolved against a number
   that changes per browser, while the tournament name beside it is sized in
   rem off the root. The two drifted apart, and on iOS the button ended up
   shorter than the name-and-subtitle block next to it. rem ties it to the
   same root as everything else it sits beside.
   2.75rem = 44px at the default root, which is also the minimum touch
   target. The glyph scales with it — growing the box alone would leave the
   bars marooned in the middle.
   The padding trim is what moves the RATIO. The button is the tallest thing
   in the header, so the header's height tracks it 1:1 and growing the button
   alone chases its own tail — 44px in a 0.8em-padded header is still only
   63% of it. Tightening the padding holds the header at the height it
   already had while the control inside it gets bigger. */
.site-header {
  padding-top: max(0.45rem, calc(0.45rem + env(safe-area-inset-top, 0px)));
  padding-bottom: 0.45rem;
}
.header-menu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  flex-shrink: 0;
  margin-left: auto;
  padding: 0;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  color: var(--text-dim);
  cursor: pointer;
  touch-action: manipulation;
}
.header-menu-btn svg { width: 1.55rem; height: 1.55rem; }
.header-menu-btn[aria-expanded="true"] { color: var(--text); border-color: var(--text-dim); }

/* The panel. position:absolute against the sticky header so it overlays the
   page instead of reflowing it — opening the menu must not move the bracket
   underneath, or the tap that opens it lands on something else on close. */
.site-header { position: sticky; }
/* EVERY rule here is scoped to .has-menu. The panel look — absolute, boxed,
   shadowed — is only correct for something a hamburger opens and closes.
   Unscoped, it applied to any .header-controls under 1280px, so a page with
   no hamburger (admin, lineup, score) rendered a floating panel with no way
   to shut it: a menu stuck permanently open over the content. A page below
   the two-control threshold gets a plain inline row instead. */
.site-header.has-menu .header-controls {
  position: absolute;
  top: 100%;
  right: 0.6em;
  z-index: 120;
  flex-direction: column;
  align-items: stretch;
  gap: 0.4em;
  min-width: 12em;
  max-width: min(18em, calc(100vw - 1.2em));
  margin: 0.35em 0 0;
  padding: 0.6em;
  background: var(--surface);
  border: 0.07em solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 0.5em 1.5em rgba(0, 0, 0, 0.35);
}
/* Collapsed only when the hamburger is actually there to reopen them —
   otherwise a visitor gets no hamburger AND no controls, which once put
   "Notify me" out of reach entirely. */
.site-header.has-menu .header-controls:not(.open) { display: none; }
/* Full-width rows read as a menu rather than a row of chips, and give a
   comfortable touch target without a separate coarse-pointer rule. */
.site-header.has-menu .header-controls > * { width: 100%; justify-content: center; min-height: 2.75rem; }
.site-header.has-menu .header-controls .admin-public-btn { text-align: center; }

/* Team branding banner — a team's own logo + colors as a bold header band,
   owner, 2026-08-02: "team path, and standings would be the perfect place
   to make use of team logos and colors" (bolder treatment, not a subtle
   accent). Shared here (not bracket.css or admin.css alone) because it's
   used on the public Team Path view AND as a live preview on the coach
   panel's own Team tab while a coach is picking colors. Background comes
   from a per-team gradient set via data-css (arbitrary hex, can't live in
   a stylesheet) — text-shadow is what keeps the name legible regardless of
   which colors a team actually picked. */
.team-brand-banner {
  display: flex;
  align-items: center;
  gap: 0.8em;
  padding: 0.9em 1.1em;
  /* Fixed, not content-driven — a big logo used to grow the whole banner
     taller (owner, 2026-08-02: "should be a fixed height and not increased
     to fit a logo"). Bigger than a Standings row on purpose (owner,
     2026-08-02: "the team-brand-banner was supposed to be set back to the
     larger size, but all team-brand-banners should have a uniform height")
     — every use of this class (Team Path banner, coach/admin previews,
     Lineups/Roster tab headers) shares the one rule, so "uniform" falls out
     for free from it being a single class. overflow:hidden is what makes
     the fixed height stick: without it a long name + a wide logo would just
     spill past the box instead of being contained by it. */
  height: 5rem;
  overflow: hidden;
  border-radius: var(--radius-sm);
  margin-bottom: 1em;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.65);
}
/* No background/padding wash here (there used to be a translucent white
   frame) — it was meant to give a transparent logo some contrast, but most
   uploaded logos already carry their own opaque backing square, so the
   wash just showed as a mismatched pale box around it (owner, 2026-08-02:
   "what is happening surrounding that logo?"). A plain, unframed image
   reads correctly either way. */
/* A dedicated right-side zone, logo centered inside it, rather than the
   logo packed immediately after a variable-length name (owner, 2026-08-02:
   "Team logo should be centered on the right ~1/3 of the card in the team
   path... the preview... in coach panel" — same markup, so the fix applies
   to both automatically; widened to 3/8 shortly after: "center the logo in
   the right 3/8 of the div instead of 1/3"). flex:0 0 37.5% is also the real
   width limit (owner, 2026-08-02: "there does need to be a limit on logo
   width" — a wide wordmark logo was eating most of the banner/row);
   .team-brand-name stays flex:1, so it gets whatever's left of the other
   ~62.5%. */
.team-brand-logo-slot { flex: 0 0 37.5%; min-width: 0; display: flex; align-items: center; justify-content: center; }
.team-brand-logo {
  /* ~75% of the banner's own fixed height, sized well within it rather than
     the other way around (owner, 2026-08-02: "Team logos should be 70-90%
     of the height of the div" / banner "should be a fixed height and not
     increased to fit a logo"). Width follows the logo's own aspect ratio
     (owner, 2026-08-02: "Allow a non-square crop for team logos... height
     should be the determining factor for sizing"); max-width:100% is what
     actually enforces the slot above as the real cap on a wide logo.  */
  height: 3.75rem;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  border-radius: var(--radius-xs);
}
/* Logo AFTER the name in DOM order (owner, 2026-08-02: "move logos to the
   right of team names — more space, less alignment issues") — a name of
   any length gets its full run of space on the left instead of sharing a
   line with a fixed-width image ahead of it. brandNameOutlineColor (set via
   data-css as a ring of text-shadows on the banner, tt-common.js
   teamBrandBannerCss — see its comment for why not -webkit-text-stroke) is
   inherited, not a fill — .team-brand-name still gets its own color from
   the parent's `color` and reads the same outline/shadow either way. */
.team-brand-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: 'Oswald', sans-serif;
  /* Scaled to the banner's own (now bigger, fixed) height (owner,
     2026-08-02: "increase team name font size to an appropriate scale
     within the div"). */
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: 0.03em;
}
.team-brand-hint {
  font-size: 0.7rem;
  color: var(--text-mute);
  margin: -0.6em 0 1em;
}

/* ── Pull-to-refresh / manual refresh ────────────────────────────────────
   Shared by the public bracket, admin, and coach panels (owner, 2026-08-02:
   "the refresh button should be available in coach and admin panel also") —
   lives here rather than bracket.css because admin.html/coach.html don't
   load that sheet. The gesture and #refreshBtn wiring live in tt-common.js
   (ttSetupRefresh), driven by whichever page-specific "reload the data"
   function each page passes in.

   Deliberately NOT animated by a CSS transition while the finger is down:
   the indicator is transformed directly from the touchmove handler, which
   stays passive, so a pull never waits on JS to decide whether the page may
   scroll. The transition below is switched on only for the release. */
.ptr-indicator {
  position: fixed;
  top: 0;
  left: 50%;
  z-index: 130;             /* above the sticky header (100) and its menu (120) */
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.2em;
  height: 2.2em;
  margin-left: -1.1em;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface2);
  box-shadow: 0 0.15em 0.5em rgba(0, 0, 0, 0.35);
  color: var(--text-dim);
  opacity: 0;
  transform: translateY(-3em);
  pointer-events: none;     /* never eats a tap meant for the header */
}
.ptr-indicator.ptr-armed   { color: var(--gold-lt); border-color: var(--gold); }
.ptr-indicator.ptr-settle  { transition: transform 0.22s ease, opacity 0.22s ease; }
.ptr-spinner { width: 1.2em; height: 1.2em; }
.ptr-indicator.ptr-spin .ptr-spinner { animation: ptrSpin 0.7s linear infinite; }
/* One completed turn on success (owner, 2026-08-02) — the looping spin says
   "working", this says "done". ease-out so it lands rather than stops dead. */
.ptr-indicator.ptr-done .ptr-spinner { animation: ptrSpin 0.5s ease-out 1; }
@keyframes ptrSpin { to { transform: rotate(360deg); } }

/* The header Refresh button borrows the same spinner while a manual refresh
   is in flight, so the two entry points read as one action. */
#refreshBtn.is-refreshing { opacity: 0.65; }

@media (prefers-reduced-motion: reduce) {
  .ptr-indicator.ptr-spin .ptr-spinner,
  .ptr-indicator.ptr-done .ptr-spinner { animation: none; }
  .ptr-indicator.ptr-settle { transition: none; }
}

/* ── Share overlay / menu (generic) ───────────────────────────────────
   Moved from bracket.css (owner, 2026-08-02: coach panel's own Share for
   roster/lineup needed the same overlay/box/menu/actions look, and
   admin.html/coach.html don't load that file). bracket.js's own
   .share-themes/.share-scope/.share-align/.share-opt-note option rows, and
   the offscreen .share-frame render iframe, are bracket-specific and stayed
   in bracket.css. The spectator notification panel (bracket.js) also reuses
   this block wholesale, same as before the move. */
.team-share-wrap { position: relative; display: inline-flex; }
.share-menu {
  position: absolute;
  top: calc(100% + 0.4em);
  right: 0;
  z-index: 200;
  min-width: 11em;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 0.07em solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 0.5em 1.6em rgba(0,0,0,0.35);
  overflow: hidden;
}
.share-menu-item {
  padding: 0.7em 1em;
  font-family: 'Barlow', sans-serif;
  font-size: var(--text-sm);
  color: var(--text);
  text-align: left;
  text-decoration: none;
  background: none;
  border: 0;
  border-bottom: 0.07em solid var(--border);
  cursor: pointer;
  white-space: nowrap;
}
.share-menu-item:last-child { border-bottom: 0; }
.share-menu-item:hover { background: color-mix(in srgb, var(--blue) 14%, transparent); color: var(--blue-lt); }
@media (pointer: coarse) { .share-menu-item { min-height: 44px; display: flex; align-items: center; } }

.share-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 1.5em;
}
.share-box {
  background: var(--surface);
  border: 0.07em solid var(--border);
  border-radius: var(--radius-md);
  padding: 1.2em;
  max-width: min(92vw, 60em);
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  gap: 0.8em;
}
.share-title {
  font-family: 'Oswald', sans-serif;
  font-size: 0.95rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text);
}
.share-opts { display: flex; flex-wrap: wrap; gap: 1em; }
.share-opt {
  display: flex;
  align-items: center;
  gap: 0.45em;
  font-family: 'Barlow', sans-serif;
  font-size: var(--text-sm);
  color: var(--text-dim);
  cursor: pointer;
}
/* Checkerboard so a transparent-background render is still readable. */
.share-preview-wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  border: 0.07em solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface2);
}
.share-preview { display: block; max-width: 100%; height: auto; }
.share-actions { display: flex; align-items: center; justify-content: flex-end; gap: 0.6em; flex-wrap: wrap; }
/* Cancel goes hard left so the three things you can DO with the content sit
   together on the right, in the order you'd reach for them. */
.share-actions .admin-clear-btn { margin-right: auto; }
.share-act { flex: 0 0 auto; min-height: 2.5rem; padding-left: 1.1em; padding-right: 1.1em; }
.share-dl { background: var(--blue); border-color: var(--blue); color: #fff; }
/* The dialog's action row is at its BOTTOM, so its menus open upward — the
   downward one would land off the box. */
.share-menu--up { top: auto; bottom: calc(100% + 0.4em); }
@media (pointer: coarse) {
  .share-act { min-height: 44px; }
}
/* Narrow screens: the three actions share one row and Cancel drops to its own
   line under them. Left as-is they wrapped one at a time, stranding Share —
   the primary action — alone at the bottom right looking like an afterthought. */
@media (max-width: 34rem) {
  .share-actions { gap: 0.5em; }
  .share-act, .share-actions .team-share-wrap { flex: 1 1 0; }
  .share-actions .team-share-wrap .share-act { width: 100%; }
  .share-actions .admin-clear-btn { order: 9; flex: 1 1 100%; margin-right: 0; }
}
.share-hint {
  font-family: 'Barlow', sans-serif;
  font-size: var(--text-xs);
  color: var(--text-mute);
  text-align: right;
}

/* Header corner as a link back to the public page, on the admin and coach
   panels (owner, 2026-08-02). Wrapping the logo + name in an <a> must not
   change how the header looks or lays out, so this only removes the anchor's
   own styling and re-establishes the flex row it replaced. */
.header-home-link {
  display: flex;
  align-items: center;
  gap: inherit;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  /* Hugs its text and pushes the rest of the header right, rather than
     stretching. The public header learned this the hard way: a name-block set
     to flex:1 reaches the header controls, so at 1920px a click 1100px away
     from the tournament name still navigated. */
  margin-right: auto;
}
.header-home-link:hover #adminSiteName,
.header-home-link:hover #coachSiteName { color: var(--gold-lt); }
