/* KarateShowCase tenant — components
 *
 * Generated by tools/consolidate-tenant-css.mjs from 50 source files,
 * concatenated in their original cascade order. Edit the sources, re-run the
 * tool; do not hand-edit this file.
 */

/* ══════════════════════════════════════════════════════════════════════
   dojo-global-team-nav-hide.v1.css
   ══════════════════════════════════════════════════════════════════════ */
/* ── Team-only nav hide ────────────────────────────────────────────────────
 * A destination that belongs to the competition team has no nav entry for a
 * student of the dojo who is not on it. firestore.rules stopped serving those
 * records to an ordinary member; this stops offering them, so the reader meets
 * a bar that does not mention the team rather than a screen that never fills.
 *
 * A separate class from ks-feature-hidden on purpose. "This dojo does not run a
 * competition team" and "you are not on this dojo's team" are independent
 * reasons to hide the same entry, and either may apply without the other. One
 * class would make the two indistinguishable and leave whichever ran last
 * deciding.
 *
 * Selector shape copied from dojo-global-feature-nav-hide.v1.css for the same
 * reason it has that shape: .dock-more-dropdown li carries
 * `display: block !important` in three stylesheets, so hiding needs a class
 * that out-specifies them and carries !important of its own -- an inline style
 * loses. It has to win in the primary dock, the Resources dropdown, and the
 * mobile menu's own override, because the priority-nav component moves entries
 * between the first two at runtime.
 * ───────────────────────────────────────────────────────────────────────── */

li.ks-team-hidden,
.nav-links li.ks-team-hidden,
.dock-more-dropdown li.ks-team-hidden,
.nav-links.mobile-open .dock-more-dropdown li.ks-team-hidden {
  display: none !important;
}

/* The same rule for entrances that are not nav items. The footer offered every
   reader a Match Library link, and the roster became team-only underneath it,
   so a visitor clicking it was returned to the page they clicked from. Marked
   with data-ks-team-only in the markup rather than by id, because there is no
   reason for the toggle to learn a new name each time one of these appears. */
[data-ks-team-only].ks-team-hidden {
  display: none !important;
}


/* ══════════════════════════════════════════════════════════════════════
   dojo-global-command-dock-brand.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── NAV — COMMAND DOCK ─────────────────────────────────────────────────── */
    body>nav {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      z-index: var(--ks-z-sticky);
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 clamp(.85rem, 2vw, 1.5rem);
      height: 72px;
      background: rgba(4, 9, 20, 0.55);
      backdrop-filter: blur(14px) saturate(1.3);
      -webkit-backdrop-filter: blur(14px) saturate(1.3);
      border-bottom: 1px solid rgba(255, 255, 255, 0.04);
      box-shadow: 0 2px 20px rgba(0, 0, 0, 0.3)
    }

    /* The basis was a flat 260px, which the logo took 98px of, so any dojo whose
       name needed more than the remaining 152px was truncated -- at 1440px, with
       60px of unused bar sitting between the links and the sign-in controls. The
       cap, not the space, was the constraint, and it applied to every role at
       every width.

       auto asks for the name's own width and still yields under pressure, which
       is what the 0 1 was for. Nothing else here changes: the nav is
       space-between, so a brand that takes its natural width simply moves the
       links along rather than displacing anything. */
    .nav-brand {
      display: flex;
      align-items: center;
      gap: 10px;
      cursor: pointer;
      flex: 0 1 auto;
      min-width: 0
    }

    /* A ceiling rather than the old fixed basis: an auto basis asks for the
       whole name, and a long enough one asked for more of the line than there
       was to give, which pushed the bar into horizontal overflow. A share
       scales with the viewport where a pixel cap cannot -- generous enough that
       ordinary names never meet it, bounded enough that no name can overrun the
       bar.

       Desktop only. Below 1100px .nav-brand-text is display:none and the brand
       is the logo alone, so a 30% ceiling there would be a limit on a logo that
       cannot shrink, for no benefit. */
    @media (min-width: 1101px) {
      .nav-brand {
        max-width: 30%;
      }
    }

    .nav-brand-logo {
      height: 38px;
      width: auto;
      max-width: 120px;
      object-fit: contain;
      flex-shrink: 0
    }

    .nav-brand-text {
      display: flex;
      flex-direction: column;
      min-width: 0;
      overflow: hidden
    }

    /* The dojo's name is nowrap inside a box flex is allowed to crush to
       nothing, and nothing here used to say what happens when the text is wider
       than the box it is in. The answer the browser gives is to paint it anyway:
       at 1280px a signed-in competitor -- who carries an extra My Profile item
       on the right, which is flex-shrink:0 -- had the brand squeezed to 59px and
       the title rendered straight across the links beside it.
       .nav-right never gives ground, so the brand absorbs all of it.

       Clipping to the box is what makes that impossible. It is not only a
       1280px problem: the width where it starts is set by how long the tenant's
       name is, so a dojo with a long one overlapped at any size. An ellipsis
       says "there is more name here" honestly; overlapping text says nothing
       and ruins the line it lands on. */
    /* Raleway, not Cinzel. An inscriptional serif reads ceremonial, and the
       brief is Apple/Tesla — one type system platform-wide, where a dojo
       expresses itself through its logo, its imagery and its accent rather
       than through its own typeface. Raleway carries uppercase tracking
       better at this size, so the tracking tightens slightly to compensate. */
    .nav-title {
      font-family: var(--ks-display);
      font-size: 1rem;
      font-weight: 700;
      letter-spacing: 1.1px;
      color: var(--ink-inverse);
      line-height: 1.1;
      text-transform: uppercase;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis
    }

    /* Wrapping instead of clipping, so this turned into two lines and pushed
       the whole 72px bar out of rhythm before the title had even run out. */
    /* Quiet, not coloured. This is a tagline under the dojo's name, and the
       premium move is to let it recede: coloured small caps is the ornament
       the gold theme leaned on. Muted inverse ink also means it cannot be made
       illegible by a tenant's accent choice, which a coloured version could. */
    .nav-sub {
      font-size: .52rem;
      letter-spacing: 1.5px;
      color: color-mix(in oklab, var(--ink-inverse) 58%, transparent);
      text-transform: uppercase;
      margin-top: 2px;
      font-weight: 600;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-global-command-dock-menu-controls.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Glass Pill ────────────────────────────────────────────────────────── */
    .nav-links {
      display: flex;
      align-items: center;
      gap: 2px;
      list-style: none;
      /* A white wash over the bar rather than a second named navy: the pill
         stays correctly raised whatever --surface-inverse becomes, instead of
         drifting out of step with the bar it sits on. */
      background: rgba(255, 255, 255, 0.06);
      backdrop-filter: blur(20px) saturate(1.4);
      -webkit-backdrop-filter: blur(20px) saturate(1.4);
      border: 1px solid rgba(255, 255, 255, 0.10);
      border-radius: 40px;
      padding: 4px 6px;
      box-shadow:
        0 4px 20px rgba(0, 0, 0, 0.3),
        0 0 0 1px rgba(255, 255, 255, 0.03),
        inset 0 1px 0 rgba(255, 255, 255, 0.04);
      margin: 0 clamp(.45rem, 1vw, 1rem);
      flex-shrink: 1;
      max-width: min(760px, 58vw);
      overflow: visible
    }

    .nav-links li {
      display: none
    }

    .nav-links li.dock-primary,
    .nav-links li.dock-more-wrap {
      display: flex;
      align-items: center
    }

    .nav-links a {
      color: rgba(255, 255, 255, 0.55);
      text-decoration: none;
      font-size: clamp(.58rem, .72vw, .68rem);
      font-weight: 800;
      letter-spacing: .85px;
      text-transform: uppercase;
      padding: 8px clamp(9px, .85vw, 14px);
      border-radius: 30px;
      transition: color .2s ease, background .2s ease;
      white-space: nowrap;
      cursor: pointer;
      position: relative
    }

    .nav-links a::after {
      display: none
    }

    .nav-links a:hover {
      color: rgba(255, 255, 255, 0.9);
      background: rgba(255, 255, 255, 0.06)
    }

    /* The one place the dojo's colour appears in the dock, and the one place it
       carries meaning: this is where you are. A wash rather than a fill, so the
       label stays white and legible whatever accent a tenant picks. */
    .nav-links a.active {
      color: var(--ink-inverse);
      background: color-mix(in oklab, var(--accent) 26%, transparent);
      box-shadow: 0 0 12px color-mix(in oklab, var(--accent) 14%, transparent)
    }

    /* ── The glider ─────────────────────────────────────────────────────────
       The active pill as ONE element that slides between links. Same paint as
       a.active — the tenant's accent through the same color-mix — so handing
       the pill to the glider changes where it moves, never what it is. The
       handover is conditional on the glider actually running
       (:has(.is-on)), which is the no-JS/stacked-menu fallback in one line. */
    .nav-links {
      position: relative;
    }

    .nav-glider {
      position: absolute;
      top: 0;
      left: 0;
      border-radius: 30px;
      background: color-mix(in oklab, var(--accent) 26%, transparent);
      box-shadow: 0 0 12px color-mix(in oklab, var(--accent) 14%, transparent);
      opacity: 0;
      pointer-events: none;
      z-index: 0;
      will-change: transform;
      transition:
        transform .34s cubic-bezier(.3, .7, .25, 1),
        width .34s cubic-bezier(.3, .7, .25, 1),
        opacity .18s ease-out;
    }

    .nav-glider.is-on {
      opacity: 1;
    }

    .nav-glider.no-anim {
      transition: none;
    }

    .nav-links li:not(.nav-glider) {
      position: relative;
      z-index: 1;
    }

    .nav-links:has(.nav-glider.is-on) a.active {
      background: transparent;
      box-shadow: none;
    }

    @media (prefers-reduced-motion: reduce) {
      .nav-glider {
        transition: opacity .18s ease-out;
      }
    }

    @media (max-width: 900px) {
      /* The mobile-cascade defect class, again (see the failsafe file's
         history): the drawer restyles `.nav-links li { display: block
         !important }`, which out-guns a bare `.nav-glider { display: none }`
         on specificity and RESURRECTS the glider below the breakpoint — an
         absolutely-positioned pill stranded at its desktop coordinates,
         quietly widening the page sideways (measured: scrollWidth 527 on a
         390 viewport, the glider's own right edge). Same importance, higher
         specificity, wins regardless of file order. */
      .nav-links li.nav-glider {
        display: none !important;
      }
    }

    /* ── More Dropdown ─────────────────────────────────────────────────────── */
    .dock-more-wrap {
      position: relative
    }

    .dock-more-trigger {
      color: rgba(255, 255, 255, 0.55) !important;
      cursor: pointer;
      user-select: none
    }

    .dock-more-trigger.more-active {
      color: var(--ink-inverse) !important;
      background: color-mix(in oklab, var(--accent) 26%, transparent);
      box-shadow: 0 0 12px color-mix(in oklab, var(--accent) 14%, transparent)
    }

    .dock-more-caret {
      font-size: .55rem;
      margin-left: 2px;
      display: inline-block;
      transition: transform .2s ease
    }

    .dock-more-wrap.open .dock-more-caret {
      transform: rotate(180deg)
    }

    .dock-more-dropdown {
      position: absolute;
      top: calc(100% + 12px);
      right: -8px;
      min-width: 200px;
      background: color-mix(in srgb, var(--surface-inverse) 98%, transparent);
      backdrop-filter: blur(24px) saturate(1.4);
      -webkit-backdrop-filter: blur(24px) saturate(1.4);
      border: 1px solid rgba(255, 255, 255, 0.12);
      border-radius: 16px;
      padding: 8px;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.03);
      list-style: none;
      opacity: 0;
      visibility: hidden;
      transform: translateY(-6px);
      transition: opacity .2s ease, transform .2s ease, visibility .2s ease;
      pointer-events: none
    }

    .dock-more-wrap.open .dock-more-dropdown {
      opacity: 1;
      visibility: visible;
      transform: translateY(0);
      pointer-events: auto
    }

    .dock-more-dropdown li {
      display: block !important
    }

    .dock-more-dropdown a {
      display: block;
      padding: 11px 14px;
      border-radius: 10px;
      font-size: .7rem;
      letter-spacing: .9px
    }

    .dock-more-dropdown a:hover {
      background: rgba(255, 255, 255, 0.06)
    }

    /* Coloured text on the dark band, so this is the one that needs the
       lightness floor — the platform blue at #1552D8 would be 1.6:1 here. */
    .dock-more-dropdown a.active {
      color: var(--accent-on-inverse);
      background: color-mix(in oklab, var(--accent) 12%, transparent);
      box-shadow: none
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-global-button-system.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── BUTTONS ─────────────────────────────────────────────────────────────── */
    .btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      padding: 12px 24px;
      /* The platform's control corner, not a literal. This was 3px, which was
         the base every other button in the product then overrode -- twenty-two
         distinct values across thirty-four stylesheets, four of them visible on
         the demo dojo's home page at once. See --ks-r-control in
         assets/css/ks-tokens.v1.css for the measurement and why controls get a
         semantic rather than a step. */
      border-radius: var(--ks-r-control);
      font-family: 'Raleway', sans-serif;
      font-weight: 700;
      font-size: .7rem;
      letter-spacing: 2.5px;
      text-transform: uppercase;
      cursor: pointer;
      border: none;
      /* Named properties rather than `all`: `all` also animates outline-width
         and outline-offset, so the keyboard focus ring fades in over
         --duration-base instead of landing at once. The list is the union of
         everything the .btn variants actually move on :hover/:active/:disabled
         — background/border-color/color/box-shadow/transform from the variant
         hovers, filter from .btn-gold:hover's brightness(), opacity from
         `#view-admin .btn:disabled`. Any per-view rule that outranks this one
         has to name its properties too, or it puts outline back in the list. */
      transition-property: background, border-color, color, box-shadow, transform, filter, opacity;
      transition-duration: var(--duration-base);
      transition-timing-function: var(--ease-out);
      white-space: nowrap;
      position: relative;
      overflow: hidden
    }

    .btn:active {
      transform: translateY(0);
      box-shadow: none
    }

    /* ── PRIMARY vs DESTRUCTIVE ──────────────────────────────────────────────
       These are the two buttons a reader must never confuse, and colour alone
       does not separate them: a colour-blind reader, or anyone moving fast,
       gets the same signal from two saturated fills. The SHAPE carries it.

         .btn-primary    FILLED with the dojo's accent. Save, Add, Create.
         .btn-danger     OUTLINED, in danger's own hue, and it carries an icon.
                         Delete, Remove, Revoke.
         .btn-danger-confirm  FILLED danger, and ONLY for the confirming step of
                         a destructive flow — the second press, never the first.

       .btn-gold is kept as an alias because the class is spelled into markup
       and scripts across every screen. It is a colour name for a role, and the
       colour it named is gone; new markup should say .btn-primary. */
    .btn-primary,
    .btn-gold {
      background: var(--ks-accent);
      color: var(--ks-on-accent);
      box-shadow: 0 2px 12px color-mix(in oklab, var(--accent) 25%, transparent), 0 0 0 1px color-mix(in oklab, var(--accent) 6%, transparent);
      border: 1px solid color-mix(in oklab, var(--accent) 30%, transparent);
      /* See .btn above: `all` would animate the focus ring's outline-width.
         Same property list, but this rule's own .4s / easing is kept — it is a
         deliberately slower lift than the base button. The ::before sheen
         sweep below carries its own `transition: left`, untouched by this. */
      transition-property: background, border-color, color, box-shadow, transform, filter, opacity;
      transition-duration: .4s;
      transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1);
    }

    .btn-primary:hover,
    .btn-gold:hover {
      transform: translateY(-3px);
      box-shadow: 0 8px 30px color-mix(in oklab, var(--accent) 50%, transparent), 0 0 15px color-mix(in oklab, var(--accent) 20%, transparent), 0 0 0 1px color-mix(in oklab, var(--accent) 40%, transparent);
      filter: brightness(1.1);
    }

    .btn-primary::before,
    .btn-gold::before {
      content: '';
      position: absolute;
      top: 0;
      left: -100%;
      width: 100%;
      height: 100%;
      background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent);
      transition: left .55s;
      pointer-events: none
    }

    .btn-primary:hover::before,
    .btn-gold:hover::before {
      left: 100%
    }

    .btn-outline {
      background: rgba(255, 255, 255, 0.02);
      color: var(--ks-accent-strong);
      border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
      backdrop-filter: blur(8px)
    }

    .btn-outline:hover {
      background: color-mix(in oklab, var(--accent) 12%, transparent);
      transform: translateY(-3px);
      box-shadow: 0 8px 25px color-mix(in oklab, var(--accent) 30%, transparent), 0 0 10px color-mix(in oklab, var(--accent) 10%, transparent);
      border-color: color-mix(in oklab, var(--accent) 80%, transparent);
    }

    .btn-dark {
      background: rgba(255, 255, 255, 0.03);
      color: var(--white);
      border: 1px solid rgba(255, 255, 255, 0.1);
      backdrop-filter: blur(8px)
    }

    .btn-dark:hover {
      background: rgba(255, 255, 255, 0.06);
      border-color: color-mix(in oklab, var(--accent) 30%, transparent);
      color: var(--ks-accent-strong);
      transform: translateY(-2px)
    }

    .btn-ghost {
      background: transparent;
      color: var(--muted);
      border: 1px solid rgba(255, 255, 255, 0.08)
    }

    .btn-ghost:hover {
      color: var(--white);
      border-color: rgba(255, 255, 255, 0.2);
      background: rgba(255, 255, 255, 0.03)
    }

    .btn-sm {
      padding: 8px 16px;
      font-size: .64rem;
      letter-spacing: 2px
    }

    .btn-full {
      width: 100%;
      justify-content: center
    }

    /* Outlined, and quieter than primary on purpose. Its hue is --ks-danger,
       which is theme-aware and already held to 4.5:1 on both surfaces by
       verify-theme-token-contrast.mjs — the old rgba(214,69,69,…) literals were
       held to nothing. */
    .btn-danger {
      background: var(--ks-danger-bg);
      color: var(--ks-danger);
      border: 1px solid var(--ks-danger-line)
    }

    .btn-danger:hover {
      background: color-mix(in oklab, var(--ks-danger) 16%, var(--ks-danger-bg));
      border-color: var(--ks-danger);
      transform: translateY(-2px)
    }

    /* The icon is not decoration. Colour alone separates destructive from
       primary only for readers who see colour and are not in a hurry, so the
       mark is what carries the meaning when the hue does not land. Supplied by
       markup where the button has one; this draws it for buttons that do not,
       so a destructive action cannot ship as a plain word. */
    .btn-danger:not(:has(svg)):not(:has(.ks-icon))::after {
      content: '';
      width: .85em;
      height: .85em;
      flex-shrink: 0;
      background: currentColor;
      -webkit-mask: var(--ks-danger-mark) center / contain no-repeat;
      mask: var(--ks-danger-mark) center / contain no-repeat;
    }

    /* Filled danger exists for exactly one moment: the confirming press of a
       destructive flow, where the reader has already said what they intend and
       the button should look like the thing about to happen. Never the first
       press. */
    .btn-danger-confirm {
      background: var(--ks-danger);
      color: var(--ks-ink-inverse);
      border: 1px solid var(--ks-danger)
    }

    .btn-danger-confirm:hover {
      background: color-mix(in oklab, var(--ks-danger) 85%, #000);
      border-color: color-mix(in oklab, var(--ks-danger) 85%, #000);
      transform: translateY(-2px)
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-global-feature-nav-hide.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Capability nav hide ──────────────────────────────────────────────────
     * A screen its dojo has switched off has no nav entry. This is a class
     * rather than an inline style because .dock-more-dropdown li carries
     * `display: block !important` in three separate stylesheets, and an inline
     * style loses to !important -- so the Resources entries stayed visible while
     * the primary dock entries hid correctly.
     *
     * The class selector out-specifies those rules (0,2,1 against 0,1,1) and
     * carries !important of its own, so it wins wherever they apply: the primary
     * dock, the Resources dropdown, and the mobile menu's own override.
     * ──────────────────────────────────────────────────────────────────────── */
    li.ks-feature-hidden,
    .nav-links li.ks-feature-hidden,
    .dock-more-dropdown li.ks-feature-hidden,
    .nav-links.mobile-open .dock-more-dropdown li.ks-feature-hidden {
      display: none !important;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-next-event.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Next Event Card ──────────────────────────────────────────────────── */
    .cc-next-event-body {
      display: flex;
      flex-direction: column;
      flex: 1;
      gap: .6rem;
      text-align: center;
      align-items: center;
    }

    .cc-next-event-img {
      width: 100%;
      height: 110px;
      object-fit: cover;
      border-radius: 8px;
      border: 1px solid #E8E0CE;
    }

    .cc-next-event-badge {
      display: inline-block;
      font-size: .7rem;
      font-weight: 900;
      letter-spacing: 2px;
      text-transform: uppercase;
      padding: 4px 14px;
      border-radius: 4px;
      align-self: center;
    }

    .cc-badge-tournament {
      color: #FFFFFF;
      background: #1A2942;
      border: 1px solid rgba(26, 41, 66, 0.5);
    }

    .cc-badge-practice {
      color: var(--ks-accent-strong);
      background: color-mix(in oklab, var(--accent) 18%, transparent);
      border: 1px solid color-mix(in oklab, var(--accent) 40%, transparent);
    }

    .cc-badge-team {
      color: #4C1D95;
      background: rgba(155, 89, 182, 0.16);
      border: 1px solid rgba(155, 89, 182, 0.35);
    }

    .cc-badge-other {
      color: #334155;
      background: rgba(148, 163, 184, 0.18);
      border: 1px solid rgba(148, 163, 184, 0.35);
    }

    .cc-next-event-title {
      font-family: var(--ks-display);
      font-size: 1.3rem;
      font-weight: 900;
      color: #0A1324;
      line-height: 1.25;
      text-align: center;
    }

    .cc-next-event-detail {
      display: flex;
      align-items: center;
      gap: .4rem;
      font-size: 1rem;
      color: #334155;
      font-weight: 700;
      justify-content: center;
    }

    .cc-next-event-detail-icon {
      color: var(--ks-accent-strong);
      font-size: .75rem;
      width: 16px;
      text-align: center;
      flex-shrink: 0;
    }

    .cc-next-event-actions {
      display: flex;
      flex-wrap: wrap;
      gap: .45rem;
      margin-top: auto;
      padding-top: .5rem;
      justify-content: center;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-next-event-empty.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    .cc-next-event-empty {
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #9EADC6;
      font-size: .9rem;
      font-weight: 600;
      font-style: italic;
      text-align: center;
      padding: 2rem 1rem;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-calendar-card.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Calendar Card ────────────────────────────────────────────────────── */
    .cc-calendar-body {
      flex: 1;
      display: flex;
      flex-direction: column;
    }

    .cc-calendar-nav {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: .75rem;
      margin-bottom: .6rem;
    }

    .cc-calendar-nav-btn {
      width: 30px;
      height: 30px;
      border-radius: 50%;
      border: 1px solid rgba(10, 19, 36, 0.15);
      background: rgba(10, 19, 36, 0.04);
      color: var(--ks-ink);
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: .9rem;
      font-weight: 900;
      transition: all .2s ease;
    }

    .cc-calendar-nav-btn:hover {
      background: color-mix(in oklab, var(--accent) 12%, transparent);
      border-color: color-mix(in oklab, var(--accent) 50%, transparent);
      color: var(--ks-accent-strong);
    }

    .cc-calendar-month-label {
      font-family: var(--ks-display);
      font-size: .95rem;
      font-weight: 800;
      color: var(--ks-ink);
      letter-spacing: 2px;
      text-transform: uppercase;
    }

    .cc-calendar-weekdays {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      gap: 2px;
      margin-bottom: 3px;
    }

    .cc-calendar-weekday {
      text-align: center;
      font-size: .62rem;
      font-weight: 800;
      color: #64748B;
      text-transform: uppercase;
      letter-spacing: 1px;
      padding: 4px 0;
    }

    .cc-calendar-grid {
      display: grid;
      grid-template-columns: repeat(7, 1fr);
      gap: 2px;
      flex: 1;
    }

    .cc-calendar-grid .home-calendar-mini-cell {
      min-height: 34px;
      font-size: .78rem;
      cursor: pointer;
      color: var(--ks-ink);
      font-weight: 700;
      background: transparent;
      border: none;
      border-radius: 6px;
      transition: all .2s ease;
      display: flex;
      align-items: center;
      justify-content: center;
      position: relative;
    }

    .cc-calendar-grid .home-calendar-mini-cell:hover {
      background: color-mix(in oklab, var(--accent) 10%, transparent);
    }

    .cc-calendar-grid .home-calendar-mini-cell.is-empty {
      color: #C9D1DC;
    }

    .cc-calendar-grid .home-calendar-mini-cell.is-today {
      color: var(--ks-ink);
      font-weight: 900;
      background: color-mix(in oklab, var(--accent) 12%, transparent);
      border: 2px solid var(--ks-accent);
      border-radius: 50%;
    }

    .cc-calendar-grid .home-calendar-mini-cell.has-event .home-calendar-mini-dot {
      background: var(--ks-accent);
    }

    .cc-calendar-grid .home-calendar-mini-cell.selected {
      background: linear-gradient(135deg, var(--ks-accent), var(--accent-deep));
      color: var(--ks-on-accent);
      font-weight: 900;
      border-radius: 50%;
      border: 2px solid rgba(240, 220, 154, 0.6);
      box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 25%, transparent);
      animation: none;
    }

    .cc-calendar-legend {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 1.25rem;
      margin-top: .6rem;
      padding-top: .5rem;
      border-top: 1px solid rgba(10, 19, 36, 0.08);
    }

    .cc-calendar-legend-item {
      display: flex;
      align-items: center;
      gap: .3rem;
      font-size: .62rem;
      font-weight: 700;
      color: #64748B;
    }

    .cc-legend-dot {
      width: 8px;
      height: 8px;
      border-radius: 50%;
    }

    .cc-legend-dot-practice {
      background: var(--ks-accent);
    }

    .cc-legend-dot-event {
      background: #3498db;
      /* A square, matching the grid's event mark — the type distinction is
         shape as well as colour there, so the legend draws the same pair. */
      border-radius: 1px;
    }

    /* ── Calendar selected-date banner (inside calendar card) ──────────── */
    .cc-calendar-banner {
      display: none;
      margin-top: .5rem;
      padding: .6rem .8rem;
      border-radius: 8px;
      background: rgba(10, 19, 36, 0.04);
      border: 1px solid rgba(10, 19, 36, 0.1);
      text-align: left;
    }

    .cc-calendar-banner.show {
      display: block;
    }

    .cc-calendar-banner-date {
      font-family: var(--ks-display);
      font-size: .82rem;
      font-weight: 800;
      color: var(--ks-ink);
      margin-bottom: .25rem;
    }

    .cc-calendar-banner-events {
      display: flex;
      flex-direction: column;
      gap: .25rem;
    }

    .cc-calendar-banner-item {
      font-size: .92rem;
      color: var(--ks-ink);
      font-weight: 700;
      padding: .3rem .6rem;
      border-radius: 6px;
      background: #FFFFFF;
      border-left: 3px solid var(--ks-accent);
      box-shadow: 0 1px 3px rgba(10, 19, 36, 0.06);
    }

    .cc-calendar-banner-item:hover {
      background: color-mix(in oklab, var(--accent) 6%, transparent);
    }

    .cc-calendar-banner-empty {
      font-size: .75rem;
      color: #8095B0;
      font-style: italic;
    }

    .cc-calendar-banner-clear {
      background: none;
      border: none;
      color: var(--ks-accent-strong);
      font-size: .62rem;
      font-weight: 800;
      cursor: pointer;
      letter-spacing: 1px;
      text-transform: uppercase;
      margin-top: .35rem;
      padding: 2px 0;
    }

    .cc-calendar-banner-clear:hover {
      color: var(--ks-accent-strong);
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-events-header.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Upcoming Events Row ──────────────────────────────────────────────── */
    .cc-events-section {
      display: flex;
      flex-direction: column;
    }

    .cc-events-header {
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
      margin-bottom: .75rem;
    }

    .cc-events-header-left {
      display: flex;
      align-items: center;
      gap: .5rem;
    }

    .cc-events-header-icon {
      font-size: 1.3rem;
      color: var(--ks-accent-strong);
    }

    .cc-events-header-title {
      font-family: var(--ks-display);
      font-size: 1.25rem;
      font-weight: 900;
      color: #0A1324;
      letter-spacing: 2px;
      text-transform: uppercase;
    }

    .cc-events-view-all {
      font-size: .68rem;
      font-weight: 800;
      color: var(--ks-accent-strong);
      letter-spacing: 1px;
      text-transform: uppercase;
      cursor: pointer;
      text-decoration: none;
      display: flex;
      align-items: center;
      gap: .3rem;
      transition: color .2s ease;
    }

    .cc-events-view-all:hover {
      color: var(--ks-accent-strong);
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-event-cards.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    .cc-events-row {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 1rem;
    }

    .cc-event-card {
      background: #FFFFFF;
      border: 1px solid rgba(10, 19, 36, 0.08);
      border-radius: 14px;
      padding: 1.1rem;
      display: flex;
      flex-direction: column;
      gap: .5rem;
      box-shadow: 0 2px 8px rgba(10, 19, 36, 0.06), 0 1px 3px rgba(10, 19, 36, 0.03);
      transition: transform .35s cubic-bezier(.4, 0, .2, 1), box-shadow .35s ease, border-color .35s ease;
      text-align: center;
      opacity: 0;
      transform: translateY(20px);
    }

    .cc-event-card:hover {
      transform: translateY(-4px);
      box-shadow: 0 10px 28px rgba(10, 19, 36, 0.12), 0 0 0 1px color-mix(in oklab, var(--accent) 12%, transparent);
      border-color: color-mix(in oklab, var(--accent) 25%, transparent);
    }

    .cc-event-card-top {
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
      gap: .75rem;
    }

    .cc-event-card-icon-wrap {
      width: 48px;
      min-width: 48px;
      height: 48px;
      border-radius: 10px;
      background: rgba(10, 19, 36, 0.05);
      border: 1px solid rgba(10, 19, 36, 0.1);
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 1.3rem;
      color: var(--ks-accent-strong);
    }

    .cc-event-card-info {
      display: flex;
      flex-direction: column;
      gap: .25rem;
      flex: 1;
      min-width: 0;
      align-items: center;
    }

    .cc-event-card-badge {
      display: inline-block;
      font-size: .7rem;
      font-weight: 900;
      letter-spacing: 2px;
      text-transform: uppercase;
      padding: 2px 8px;
      border-radius: 3px;
      align-self: center;
    }

    .cc-event-card-title {
      font-family: var(--ks-display);
      font-size: 1.1rem;
      font-weight: 900;
      color: #0A1324;
      line-height: 1.25;
      text-align: center;
    }

    .cc-event-card-meta {
      display: flex;
      flex-direction: column;
      gap: .2rem;
      align-items: center;
    }

    .cc-event-card-meta-item {
      display: flex;
      align-items: center;
      gap: .35rem;
      font-size: .92rem;
      color: #1E293B;
      font-weight: 700;
      justify-content: center;
    }

    .cc-event-card-meta-icon {
      color: var(--ks-accent-strong);
      font-size: .65rem;
      width: 14px;
      text-align: center;
    }

    .cc-event-card-actions {
      display: flex;
      flex-wrap: wrap;
      gap: .4rem;
      margin-top: auto;
      padding-top: .6rem;
      justify-content: center;
    }

    .cc-events-empty {
      grid-column: 1 / -1;
      text-align: center;
      padding: 2rem;
      color: #8095B0;
      font-size: .95rem;
      font-weight: 700;
      font-style: italic;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-event-card-reveal.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Stagger fade-up on first reveal (toggled by JS IntersectionObserver) */
    .cc-event-card.cc-revealed {
      animation: cc-fade-up .5s cubic-bezier(.4, 0, .2, 1) forwards;
    }

    .cc-event-card:nth-child(2).cc-revealed {
      animation-delay: .1s;
    }

    .cc-event-card:nth-child(3).cc-revealed {
      animation-delay: .2s;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-next-event-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Next Event card internals ─────────────────────────────────────── */
    .cc-next-event-title {
      color: #FFFFFF;
    }

    .cc-next-event-detail {
      color: rgba(255, 255, 255, 0.75);
    }

    .cc-next-event-img {
      border-color: color-mix(in oklab, var(--accent) 25%, transparent);
    }

    .cc-next-event-empty {
      color: #9EADC6;
    }

    .cc-badge-tournament {
      background: color-mix(in oklab, var(--accent) 15%, transparent);
      color: var(--ks-band-accent);
      border: 1px solid color-mix(in oklab, var(--accent) 35%, transparent);
    }

    .cc-badge-practice {
      background: color-mix(in oklab, var(--accent) 12%, transparent);
      color: var(--ks-band-accent);
      border: 1px solid color-mix(in oklab, var(--accent) 30%, transparent);
    }

    .cc-badge-team {
      background: rgba(155, 89, 182, 0.18);
      color: #F5D0FE;
      border: 1px solid rgba(155, 89, 182, 0.35);
    }

    .cc-badge-other {
      background: rgba(148, 163, 184, 0.14);
      color: #E2E8F0;
      border: 1px solid rgba(148, 163, 184, 0.3);
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-calendar-card-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Calendar card internals ───────────────────────────────────────── */
    .cc-calendar-nav-btn {
      border-color: color-mix(in oklab, var(--accent) 25%, transparent);
      background: color-mix(in oklab, var(--accent) 8%, transparent);
      color: var(--ks-band-ink);
    }

    .cc-calendar-nav-btn:hover {
      background: color-mix(in oklab, var(--accent) 18%, transparent);
      border-color: color-mix(in oklab, var(--accent) 50%, transparent);
      color: var(--ks-band-accent);
    }

    .cc-calendar-month-label {
      color: var(--ks-band-ink);
    }

    .cc-calendar-weekday {
      color: #9EADC6;
    }

    .cc-calendar-grid .home-calendar-mini-cell {
      color: rgba(255, 255, 255, 0.85);
    }

    .cc-calendar-grid .home-calendar-mini-cell:hover {
      background: color-mix(in oklab, var(--accent) 12%, transparent);
    }

    .cc-calendar-grid .home-calendar-mini-cell.is-empty {
      color: rgba(255, 255, 255, 0.2);
    }

    .cc-calendar-grid .home-calendar-mini-cell.is-today {
      color: var(--ks-band-ink);
      background: color-mix(in oklab, var(--accent) 15%, transparent);
      border-color: var(--ks-accent);
    }

    .cc-calendar-grid .home-calendar-mini-cell.selected {
      background: linear-gradient(135deg, var(--ks-accent), var(--accent-deep));
      color: var(--ks-on-accent);
      border-color: rgba(240, 220, 154, 0.7);
    }

    .cc-calendar-legend {
      border-top-color: color-mix(in oklab, var(--accent) 12%, transparent);
    }

    .cc-calendar-legend-item {
      color: #9EADC6;
    }

    /* ── Calendar date-detail banner ───────────────────────────────────── */
    .cc-calendar-banner {
      background: color-mix(in oklab, var(--accent) 6%, transparent);
      border-color: color-mix(in oklab, var(--accent) 18%, transparent);
    }

    .cc-calendar-banner-date {
      color: var(--ks-band-ink);
    }

    .cc-calendar-banner-item {
      color: var(--ks-band-ink);
      background: rgba(15, 24, 48, 0.6);
      border-left-color: var(--ks-accent);
      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
    }

    .cc-calendar-banner-item:hover {
      background: color-mix(in oklab, var(--accent) 10%, transparent);
    }

    .cc-calendar-banner-empty {
      color: #9EADC6;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-event-cards-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Upcoming Event cards ──────────────────────────────────────────── */
    .cc-event-card {
      background: linear-gradient(160deg, #0C1628 0%, #122040 50%, #0E1830 100%);
      border: 1px solid color-mix(in oklab, var(--accent) 18%, transparent);
      box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35), inset 0 1px 0 color-mix(in oklab, var(--accent) 6%, transparent);
    }

    .cc-event-card:hover {
      border-color: color-mix(in oklab, var(--accent) 35%, transparent);
      box-shadow: 0 12px 36px rgba(0, 0, 0, 0.45), 0 0 18px color-mix(in oklab, var(--accent) 8%, transparent);
    }

    .cc-event-card-icon-wrap {
      background: color-mix(in oklab, var(--accent) 8%, transparent);
      border-color: color-mix(in oklab, var(--accent) 20%, transparent);
    }

    .cc-event-card-title {
      color: #FFFFFF;
    }

    .cc-event-card-meta-item {
      color: rgba(255, 255, 255, 0.75);
    }

    .cc-events-empty {
      color: #9EADC6;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-outline-button-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Buttons inside cards ──────────────────────────────────────────── */
    .cc-btn-outline {
      color: var(--ks-band-accent);
      border-color: color-mix(in oklab, var(--accent) 35%, transparent);
      background: color-mix(in oklab, var(--accent) 4%, transparent);
    }

    .cc-btn-outline:hover {
      border-color: color-mix(in oklab, var(--accent) 70%, transparent);
      color: var(--ks-band-accent);
      background: color-mix(in oklab, var(--accent) 10%, transparent);
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-command-center-events-header-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Section header titles (readable on light bg) ─────────────────── */
    .cc-events-header-title {
      color: #0A1324;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-fighter-belt-stripe-indicator.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Black stripe indicator for striped belt ranks */
    .belt-bar.belt-stripe::before {
      content: '';
      position: absolute;
      left: 0;
      right: 0;
      top: 50%;
      transform: translateY(-50%);
      height: 4px;
      background: linear-gradient(180deg, #222, #0a0a0a, #222);
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
      z-index: 3;
      border-radius: 0;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-fighter-belt-color-variants.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Belt Colors (scoped to belt-bar — does NOT affect badge pills) ── */
    .belt-bar.belt-black {
      background: linear-gradient(180deg, #1a1a1a 0%, #0a0a0a 40%, #111 100%);
      box-shadow: 1px 0 6px rgba(0, 0, 0, 0.7), 5px 0 16px rgba(0, 0, 0, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.06)
    }

    .belt-bar.belt-brown {
      background: linear-gradient(180deg, #5C3420 0%, #3E2215 50%, #4A2A1A 100%);
      box-shadow: 1px 0 6px rgba(62, 34, 21, 0.7), 5px 0 16px rgba(62, 34, 21, 0.25), inset -1px 0 0 rgba(255, 255, 255, 0.06)
    }

    .belt-bar.belt-blue {
      background: linear-gradient(180deg, #2563EB 0%, #1D4ED8 50%, #2255CC 100%);
      box-shadow: 1px 0 6px rgba(37, 99, 235, 0.6), 5px 0 16px rgba(37, 99, 235, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.1)
    }

    .belt-bar.belt-green {
      background: linear-gradient(180deg, #16803C 0%, #15703A 50%, #1A7D40 100%);
      box-shadow: 1px 0 6px rgba(22, 128, 60, 0.6), 5px 0 16px rgba(22, 128, 60, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.08)
    }

    .belt-bar.belt-red {
      background: linear-gradient(180deg, #C62828 0%, #B71C1C 50%, #C53030 100%);
      box-shadow: 1px 0 6px rgba(183, 28, 28, 0.6), 5px 0 16px rgba(183, 28, 28, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.08)
    }

    .belt-bar.belt-yellow {
      background: linear-gradient(180deg, #D4A017 0%, #C6930A 50%, #D4A520 100%);
      box-shadow: 1px 0 6px rgba(212, 160, 23, 0.55), 5px 0 16px rgba(212, 160, 23, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.12)
    }

    .belt-bar.belt-orange {
      background: linear-gradient(180deg, #D84315 0%, #BF360C 50%, #D04810 100%);
      box-shadow: 1px 0 6px rgba(191, 54, 12, 0.6), 5px 0 16px rgba(191, 54, 12, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.08)
    }

    .belt-bar.belt-white {
      background: linear-gradient(180deg, #F0F0F0 0%, #E0E0E0 50%, #EBEBEB 100%);
      box-shadow: 1px 0 5px rgba(200, 200, 200, 0.5), 4px 0 14px rgba(180, 180, 180, 0.15), inset -1px 0 0 rgba(0, 0, 0, 0.04);
      border-right-color: rgba(0, 0, 0, 0.08)
    }

    .belt-bar.belt-purple {
      background: linear-gradient(180deg, #7C3AED 0%, #6D28D9 50%, #7530E0 100%);
      box-shadow: 1px 0 6px rgba(109, 40, 217, 0.6), 5px 0 16px rgba(109, 40, 217, 0.2), inset -1px 0 0 rgba(255, 255, 255, 0.1)
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-fighter-detail-edit-panel.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── FIGHTER DETAIL ──────────────────────────────────────────────────────── */
    .edit-panel {
      background: rgba(24, 38, 64, 0.7);
      border: 1px solid rgba(255, 255, 255, 0.06);
      border-radius: 8px;
      padding: 1.25rem;
      margin: 1rem 1.5rem;
      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2)
    }

    .ep-title {
      font-family: var(--ks-display);
      font-size: .85rem;
      letter-spacing: 2px;
      color: var(--white);
      margin-bottom: 1rem
    }

    .fg {
      margin-bottom: .8rem
    }

    .fl {
      display: block;
      font-size: .6rem;
      font-weight: 700;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: var(--muted);
      margin-bottom: 4px
    }

    .fi-inp {
      width: 100%;
      padding: 9px 12px;
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid rgba(255, 255, 255, 0.1);
      border-radius: 4px;
      color: var(--white);
      font-family: 'Raleway', sans-serif;
      font-size: .88rem;
      transition: border-color .2s;
      -webkit-user-select: text;
      user-select: text
    }

    .fi-inp:focus {
      outline: none;
      border-color: color-mix(in oklab, var(--accent) 50%, transparent)
    }

    .fi-inp::placeholder {
      color: var(--dim)
    }

    select.fi-inp {
      cursor: pointer
    }

    input,
    textarea,
    select {
      -webkit-user-select: text;
      user-select: text
    }

    .form-row {
      display: flex;
      gap: .75rem
    }

    .form-row .fg {
      flex: 1
    }

    .photo-upload-label {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: .5rem;
      padding: .7rem;
      border: 1px dashed color-mix(in oklab, var(--accent) 30%, transparent);
      border-radius: 4px;
      cursor: pointer;
      color: var(--ks-accent-strong);
      font-size: .68rem;
      letter-spacing: 1.5px;
      text-transform: uppercase;
      transition: all .2s;
      margin-bottom: .5rem
    }

    .photo-upload-label:hover {
      border-color: var(--ks-accent);
      background: color-mix(in oklab, var(--accent) 15%, transparent)
    }

    .photo-upload-label input {
      display: none
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-fighter-detail-fight-list.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── FIGHT LIST (with YouTube thumbs) ───────────────────────────────────── */
    .fights-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
      gap: 1rem;
      padding: 0 1.5rem 3rem;
    }

    /* Card-style fight item with thumb above name */
    .fight-item {
      background: rgba(255, 255, 255, 0.02);
      border: 1px solid rgba(255, 255, 255, 0.06);
      border-radius: var(--radius-md);
      overflow: hidden;
      cursor: pointer;
      transition: all var(--duration-base) var(--ease-out);
      display: flex;
      flex-direction: column;
      box-shadow: var(--shadow-sm);
    }

    .fight-item:hover {
      border-color: color-mix(in oklab, var(--accent) 25%, transparent);
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35), 0 0 0 1px color-mix(in oklab, var(--accent) 6%, transparent);
      transform: translateY(-2px)
    }

    /* Thumbnail area */
    .fi-thumb {
      position: relative;
      width: 100%;
      aspect-ratio: 16/9;
      overflow: hidden;
      background: #000;
    }

    .fi-thumb img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform .4s
    }

    .fight-item:hover .fi-thumb img {
      transform: scale(1.04)
    }

    .fi-thumb-placeholder {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(135deg, rgba(10, 19, 36, 0.9), rgba(20, 35, 60, 0.9));
      color: var(--dim);
      flex-direction: column;
      gap: .5rem;
      max-height: 120px;
    }

    .fi-thumb-play {
      width: 44px;
      height: 44px;
      border-radius: 50%;
      background: color-mix(in oklab, var(--accent) 20%, transparent);
      border: 1.5px solid color-mix(in oklab, var(--accent) 40%, transparent);
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--ks-accent-strong);
      font-size: 1.2rem;
    }

    .fi-thumb-label {
      font-size: .58rem;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: var(--dim)
    }

    /* Row below thumb */
    .fi-body {
      display: flex;
      align-items: center;
      gap: .75rem;
      padding: .85rem 1rem
    }

    .fi-icon {
      width: 34px;
      height: 34px;
      border-radius: 50%;
      background: var(--mid);
      display: flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      font-size: 1rem
    }

    .fi-info {
      flex: 1;
      min-width: 0
    }

    .fi-title {
      font-weight: 700;
      font-size: .84rem;
      color: var(--white);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis
    }

    .fi-meta {
      font-size: .63rem;
      color: var(--muted);
      margin-top: 2px
    }

    .fi-score {
      font-family: var(--ks-display);
      font-size: .82rem;
      color: var(--ks-accent-strong);
      flex-shrink: 0;
      font-weight: 700
    }

    .fi-arr {
      color: var(--ks-accent-strong);
      flex-shrink: 0;
      font-size: 1.1rem
    }

    .section-label-left {
      font-size: .62rem;
      letter-spacing: 3px;
      text-transform: uppercase;
      color: var(--ks-accent-strong);
      margin-bottom: .8rem;
      padding: 0;
      font-weight: 700
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-fighter-detail-video-detail.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── VIDEO DETAIL — the match, its result and its timestamped coaching ──
       Re-skinned 2026-08-23 onto the light authenticated surface: the same
       selectors the page and its renderer have always used, painted from the
       foundation tokens instead of the retired dark shell. Every colour here
       is a token; the layout, ids and behaviours are unchanged. The role
       palettes the renderer used to inline (gold coach / teal competitor)
       are classes now — .note-item.is-coach / .is-competitor — so the thread
       reads with the same tints the rest of the product uses. */
    .vd-wrap {
      max-width: 780px;
      margin: 0 auto;
      padding: 0 var(--ks-gutter, 1rem) 3rem;
    }

    .vd-tournament-title {
      font-family: var(--ks-display);
      font-size: var(--ks-title-2, 1.2rem);
      font-weight: 800;
      letter-spacing: -.005em;
      color: var(--ks-ink);
      text-align: left;
      padding: 1.3rem .15rem .75rem;
    }

    .vd-back {
      display: inline-flex;
      align-items: center;
      gap: .4rem;
      margin-top: .9rem;
      padding: .55rem .9rem;
      border-radius: var(--ks-r-pill);
      font-size: var(--ks-label);
      letter-spacing: .08em;
      text-transform: uppercase;
      font-weight: 800;
      color: var(--ks-ink-2);
      cursor: pointer;
      transition: color var(--duration-fast, .15s) var(--ease-out, ease), background var(--duration-fast, .15s) var(--ease-out, ease);
    }

    .vd-back:hover {
      color: var(--ks-ink);
      background: var(--ks-surface-sunken);
    }

    /* The one card: player, result, actions, composer, thread. */
    .notes-container {
      border: 1px solid var(--ks-line);
      border-radius: var(--ks-r-lg);
      overflow: hidden;
      background: var(--ks-surface);
      box-shadow: var(--ks-shadow-1);
      margin: 0 auto 1rem;
    }

    .notes-container-hdr {
      display: flex;
      align-items: center;
      padding: .85rem 1.15rem;
      border-bottom: 1px solid var(--ks-line-soft);
    }

    .notes-container-hdr span {
      font-family: var(--ks-display);
      font-size: 1rem;
      font-weight: 800;
      letter-spacing: -.005em;
      color: var(--ks-ink);
    }

    /* video — padding-top trick for reliable 16:9 responsive iframe */
    .video-box {
      background:
        radial-gradient(75% 120% at 82% 0%, var(--ks-band-accent-soft) 0%, transparent 62%),
        linear-gradient(150deg, var(--ks-band-deep) 0%, var(--ks-band) 55%, var(--ks-band-raised) 100%);
      position: relative;
      width: 100%;
      padding-top: 56.25%;
      border-bottom: 1px solid var(--ks-line-soft);
      overflow: hidden;
    }

    .video-box iframe {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: none;
    }

    .video-box .video-placeholder {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
    }

    .video-placeholder {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: .6rem;
      color: var(--ks-band-ink-2);
    }

    .video-placeholder svg {
      width: 44px;
      height: 44px;
    }

    .video-placeholder p {
      font-size: var(--ks-body-sm);
    }

    /* The result row: who, the score, against whom. */
    .score-card {
      display: flex;
      align-items: center;
      gap: .6rem;
      padding: .85rem 1.15rem;
      border-bottom: 1px solid var(--ks-line-soft);
    }

    .score-fighter {
      display: flex;
      align-items: center;
      gap: .5rem;
      flex: 1;
      min-width: 0;
    }

    .score-badge {
      padding: .2rem .55rem;
      border-radius: var(--ks-r-pill);
      font-size: .62rem;
      font-weight: 800;
      letter-spacing: .1em;
      text-transform: uppercase;
      flex-shrink: 0;
      border: 1px solid transparent;
    }

    .badge-win {
      background: var(--ks-success-bg);
      color: var(--ks-success);
      border-color: var(--ks-success-line);
    }

    .badge-loss {
      background: var(--ks-danger-bg, var(--ks-surface-sunken));
      color: var(--ks-danger);
      border-color: color-mix(in oklab, var(--ks-danger) 30%, transparent);
    }

    .badge-tie {
      background: var(--ks-surface-sunken);
      color: var(--ks-ink-2);
      border-color: var(--ks-line);
    }

    .score-name {
      font-family: var(--ks-display);
      font-size: .95rem;
      font-weight: 800;
      color: var(--ks-ink);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .fi-score {
      color: var(--ks-ink);
      font-family: var(--ks-display);
      font-weight: 700;
    }

    .score-num {
      width: 40px;
      height: 40px;
      background: var(--ks-accent-soft);
      border: 1px solid color-mix(in oklab, var(--ks-accent) 30%, transparent);
      border-radius: var(--ks-r-sm);
      display: flex;
      align-items: center;
      justify-content: center;
      font-family: var(--ks-display);
      font-size: 1.35rem;
      font-weight: 700;
      color: var(--ks-accent-strong);
      flex-shrink: 0;
    }

    .score-num input {
      width: 100%;
      background: transparent;
      border: none;
      outline: none;
      text-align: center;
      color: var(--ks-accent-strong);
      font-family: var(--ks-display);
      font-size: 1.35rem;
      font-weight: 700;
      padding: 0;
    }

    .score-vs {
      color: var(--ks-ink-3);
      font-size: .72rem;
      letter-spacing: .12em;
      flex-shrink: 0;
      font-weight: 800;
      text-transform: uppercase;
    }

    .score-opp {
      display: flex;
      align-items: center;
      gap: .5rem;
      flex: 1;
      justify-content: flex-end;
      min-width: 0;
    }

    /* The opponent's number is a fact, not a danger: neutral ink. */
    .score-num-opp {
      width: 40px;
      height: 40px;
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      border-radius: var(--ks-r-sm);
      display: flex;
      align-items: center;
      justify-content: center;
      font-family: var(--ks-display);
      font-size: 1.35rem;
      font-weight: 700;
      color: var(--ks-ink-2);
      flex-shrink: 0;
    }

    .score-num-opp input {
      width: 100%;
      background: transparent;
      border: none;
      outline: none;
      text-align: center;
      color: var(--ks-ink-2);
      font-family: var(--ks-display);
      font-size: 1.35rem;
      font-weight: 700;
      padding: 0;
    }

    .opp-name-input {
      background: transparent;
      border: none;
      border-bottom: 1px solid var(--ks-line-strong);
      color: var(--ks-ink-2);
      font: inherit;
      font-size: var(--ks-body-sm);
      text-align: right;
      flex: 1;
      padding: 2px 0;
      transition: border-color var(--duration-fast, .15s) var(--ease-out, ease);
      min-width: 0;
    }

    .opp-name-input:focus {
      outline: none;
      border-color: var(--ks-accent);
    }

    /* notes section */
    .notes-section-hdr {
      padding: .95rem 1.15rem .35rem;
      text-align: left;
    }

    .notes-section-hdr span {
      font-size: var(--ks-label);
      font-weight: 850;
      letter-spacing: .08em;
      text-transform: uppercase;
      color: var(--ks-ink-3);
    }

    .notes-body {
      padding: .35rem 1.15rem 1rem;
    }

    /* A note: the same thread language the rest of the product speaks —
       a sunken row with the author's role as its left edge and tint. */
    .note-item {
      display: flex;
      align-items: flex-start;
      gap: .65rem;
      background: var(--ks-surface-sunken);
      border-left: 3px solid var(--ks-line-strong);
      border-radius: 0 var(--ks-r-md) var(--ks-r-md) 0;
      padding: .8rem .85rem;
      margin: 0 0 .6rem 0;
    }

    .note-item.is-coach {
      background: var(--ks-accent-soft);
      border-left-color: var(--ks-accent);
    }

    .note-item.is-competitor {
      background: var(--ks-info-bg, var(--ks-surface-sunken));
      border-left-color: var(--ks-info, var(--ks-line-strong));
    }

    .note-item.is-reply {
      margin-left: 2rem;
    }

    .note-check {
      width: 22px;
      height: 22px;
      border-radius: 50%;
      flex-shrink: 0;
      margin-top: 1px;
      display: flex;
      align-items: center;
      justify-content: center;
      background: var(--ks-surface);
      border: 1.5px solid var(--ks-line-strong);
      color: var(--ks-ink-3);
    }

    .note-item.is-coach .note-check {
      border-color: var(--ks-accent);
      color: var(--ks-accent-strong);
    }

    .note-item.is-competitor .note-check {
      border-color: var(--ks-info, var(--ks-line-strong));
      color: var(--ks-info, var(--ks-ink-2));
    }

    .note-check svg {
      width: 10px;
      height: 10px;
      stroke: currentColor;
      stroke-width: 2.5;
    }

    .note-time {
      font-family: var(--ks-display);
      font-size: .72rem;
      color: var(--ks-accent-strong);
      flex-shrink: 0;
      min-width: 36px;
      font-weight: 800;
      margin-top: 3px;
    }

    .note-text {
      font-size: var(--ks-body-sm);
      color: var(--ks-ink);
      flex: 1;
      line-height: 1.55;
    }

    /* The author's chip, drawn by the renderer as a class now. */
    .note-author {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      margin-top: .5rem;
      padding: 2px 8px;
      border-radius: var(--ks-r-pill);
      font-size: .58rem;
      font-weight: 800;
      letter-spacing: .08em;
      text-transform: uppercase;
      background: var(--ks-surface);
      border: 1px solid var(--ks-line-strong);
      color: var(--ks-ink-2);
    }

    .note-item.is-coach .note-author {
      border-color: color-mix(in oklab, var(--ks-accent) 45%, transparent);
      color: var(--ks-accent-strong);
    }

    .note-item.is-competitor .note-author {
      border-color: color-mix(in oklab, var(--ks-info, var(--ks-ink-3)) 45%, transparent);
      color: var(--ks-info, var(--ks-ink-2));
    }

    .note-author svg {
      width: 10px;
      height: 10px;
      stroke: currentColor;
    }

    .note-del {
      background: transparent;
      border: none;
      cursor: pointer;
      color: var(--ks-ink-3);
      font-size: .75rem;
      opacity: .6;
      transition: opacity var(--duration-fast, .15s) var(--ease-out, ease), color var(--duration-fast, .15s) var(--ease-out, ease);
      padding: 2px 4px;
      flex-shrink: 0;
      margin-top: 2px;
    }

    .note-item:hover .note-del,
    .note-del:focus-visible {
      opacity: 1;
    }

    .note-del:hover {
      color: var(--ks-danger);
    }

    /* add note */
    .add-note-section {
      padding: .85rem 1.15rem 1rem;
      border-bottom: 1px solid var(--ks-line-soft);
    }

    .add-note-inputs {
      display: flex;
      gap: .5rem;
      margin-bottom: .6rem;
    }

    .time-input {
      width: 64px;
      background: var(--ks-surface);
      border: 1px solid var(--ks-line-strong);
      border-radius: var(--ks-r-sm);
      padding: .5rem .3rem;
      color: var(--ks-accent-strong);
      font-family: var(--ks-display);
      font-size: .8rem;
      font-weight: 700;
      text-align: center;
      transition: border-color var(--duration-fast, .15s) var(--ease-out, ease), box-shadow var(--duration-fast, .15s) var(--ease-out, ease);
    }

    .add-note-text {
      flex: 1;
      background: var(--ks-surface);
      border: 1px solid var(--ks-line-strong);
      border-radius: var(--ks-r-sm);
      padding: .5rem .75rem;
      color: var(--ks-ink);
      font: inherit;
      font-size: var(--ks-body-sm);
      transition: border-color var(--duration-fast, .15s) var(--ease-out, ease), box-shadow var(--duration-fast, .15s) var(--ease-out, ease);
    }

    .time-input:focus,
    .add-note-text:focus {
      outline: none;
      border-color: var(--ks-accent);
      box-shadow: 0 0 0 3px var(--ks-accent-soft);
    }

    .add-note-text::placeholder,
    .time-input::placeholder {
      color: var(--ks-ink-3);
    }

    .add-note-btn-wrap {
      display: flex;
      justify-content: flex-start;
    }

/* A removal, shown rather than silently swallowed.
 *
 * Moderation moves a reported comment out of the tenant, and an ordinary hard
 * delete removes one outright. Either way its replies remain, and until this
 * existed they rendered nowhere at all — the loop hangs replies off a rendered
 * parent, so an absent parent took its whole reply chain with it, invisibly.
 * The tombstone is quiet on purpose: it says a line is gone and keeps the
 * thread readable, without implying anything about who or why. */
.note-item.note-item-removed {
  background: var(--ks-surface-sunken);
  border-left: 3px solid var(--ks-line);
  border-radius: 0 var(--ks-r-md) var(--ks-r-md) 0;
  padding: .6rem .75rem;
  margin: 0 0 .5rem 0;
  font-style: italic;
  color: var(--ks-ink-3);
  font-size: .8rem;
}

/* The admin queue's "Open the conversation" lands here and flashes the exact
   reported comment. A slow decay, not a blink: the reader arrives mid-scroll
   and the mark must survive until their eye finds it. */
.note-item-focused {
  outline: 2px solid var(--ks-accent);
  outline-offset: 2px;
  transition: outline-color 2.5s ease 1.2s;
}
@media (prefers-reduced-motion: reduce) {
  .note-item-focused { transition: none; }
}

    /* The timestamp is a control — it seeks the player — and looks like one. */
    #vd-notes-list .note-time {
      cursor: pointer;
      text-decoration: underline;
      text-underline-offset: 3px;
    }

    .note-del.note-act-reply {
      color: var(--ks-accent-strong);
      opacity: .8;
      font-weight: 800;
      margin-right: .25rem;
    }

    .note-del.note-act-edit {
      color: var(--ks-accent-strong);
      margin-right: .25rem;
    }

    .note-del.note-act-report {
      margin-right: .25rem;
    }

    .note-loading {
      color: var(--ks-ink-3);
      font-size: .85rem;
      padding: .75rem;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-overlays-modals.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── OVERLAYS & MODALS ───────────────────────────────────────────────────── */
    .overlay {
      position: fixed;
      inset: 0;
      z-index: var(--z-overlay);
      background: rgba(2, 6, 15, .93);
      backdrop-filter: blur(10px);
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 1.5rem;
      opacity: 0;
      pointer-events: none;
      transition: opacity .3s
    }

    .overlay.open {
      opacity: 1;
      pointer-events: all
    }

    .modal {
      background: #0C1828;
      border: 1px solid color-mix(in oklab, var(--accent) 30%, transparent);
      border-top: 2px solid var(--ks-accent);
      border-radius: 6px;
      width: 100%;
      max-width: 480px;
      max-height: 88vh;
      overflow-y: auto;
      transform: scale(.96);
      transition: transform .3s;
      box-shadow: 0 30px 80px rgba(0, 0, 0, 0.8)
    }

    .overlay.open .modal {
      transform: scale(1)
    }

    /* A WIDER COLUMN FOR A LONGER FORM.
       480px is right for the confirmations and short editors this component
       was built for. The Tournament Hub editor is thirteen fields and three
       notes areas — crammed into that column it becomes a scroll tube, which
       is the failure mode of putting a big form in a small dialog. The modifier
       widens the column and nothing else: the component keeps its own header,
       close control, backdrop, 88vh cap and scrolling, and stays full-width on
       a phone, where 88vh with the page behind it is already the sheet this
       form wants. */
    .modal.modal-wide {
      max-width: 760px;
    }

    .mhdr {
      padding: 1.1rem 1.25rem;
      border-bottom: var(--border-dim);
      display: flex;
      align-items: center;
      justify-content: space-between;
      position: sticky;
      top: 0;
      background: #0C1828;
      z-index: 10
    }

    .mhdr-title {
      font-family: var(--ks-display);
      font-size: .95rem;
      font-weight: 700;
      letter-spacing: 2px;
      color: var(--white)
    }

    .mclose {
      width: 28px;
      height: 28px;
      border-radius: 3px;
      background: transparent;
      border: 1px solid rgba(255, 255, 255, 0.12);
      color: var(--muted);
      cursor: pointer;
      font-size: .85rem;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all .2s
    }

    .mclose:hover {
      border-color: var(--ks-accent);
      color: var(--ks-accent-strong)
    }

    .mbody {
      padding: 1.25rem
    }

    .tab-row {
      display: flex;
      gap: 0;
      margin-bottom: 1.25rem;
      border: 1px solid rgba(255, 255, 255, 0.1);
      border-radius: 4px;
      overflow: hidden
    }

    .tab-btn {
      flex: 1;
      padding: 9px;
      font-family: 'Raleway', sans-serif;
      font-size: .68rem;
      font-weight: 700;
      letter-spacing: 1.5px;
      text-transform: uppercase;
      cursor: pointer;
      background: transparent;
      border: none;
      color: var(--muted);
      transition: all .2s
    }

    .tab-btn.active {
      background: color-mix(in oklab, var(--accent) 15%, transparent);
      color: var(--ks-accent-strong)
    }

    .tab-pane {
      display: none
    }

    .tab-pane.active {
      display: block
    }

    /* ── A refusal, beside the fields it is about ──────────────────────────
       Sign In used to close this dialog on the click and report the outcome as
       a toast over the page behind it. A toast is the wrong surface for it: it
       is transient, it is nowhere near the password box, and by the time it
       appears the dialog and everything typed into it are gone. This line stays
       until the reader types, which is the moment it stops being true. */
    .auth-inline-status {
      margin: .6rem 0 0;
      padding: .55rem .7rem;
      border-radius: 8px;
      font-size: .72rem;
      line-height: 1.5;
      border: 1px solid var(--ks-danger-line);
      background: var(--ks-danger-bg);
      color: var(--ks-danger)
    }

    .auth-inline-status[hidden] {
      display: none
    }

    .auth-inline-status[data-tone="info"] {
      border-color: var(--ks-line);
      background: var(--ks-canvas);
      color: var(--ks-ink-2)
    }

    /* ── THE LIGHT MODAL ── opt-in per dialog while the dark generation is
       retired surface by surface. #m-add-fight wears it first (2026-08-23):
       add ks-modal-light beside .modal and every primitive inside — header,
       close, labels, inputs — follows the app-surface tokens. The scrim above
       stays dark; that is what a scrim is. */
    .modal.ks-modal-light {
      background: var(--ks-surface);
      border: 1px solid var(--ks-line);
      border-top: 3px solid var(--ks-accent);
      border-radius: var(--ks-r-lg);
      color: var(--ks-ink);
      box-shadow: 0 30px 80px rgba(9, 18, 44, .35);
    }

    .modal.ks-modal-light .mhdr {
      background: var(--ks-surface);
      border-bottom: 1px solid var(--ks-line-soft);
    }

    .modal.ks-modal-light .mhdr-title {
      color: var(--ks-ink);
      letter-spacing: .05em;
    }

    .modal.ks-modal-light .mclose {
      border-color: var(--ks-line-strong);
      color: var(--ks-ink-3);
    }

    .modal.ks-modal-light .mclose:hover {
      border-color: var(--ks-accent);
      color: var(--ks-accent-strong);
    }

    .modal.ks-modal-light .fl {
      color: var(--ks-ink-3);
    }

    .modal.ks-modal-light .fi-inp {
      background: var(--ks-surface);
      border: 1px solid var(--ks-line-strong);
      border-radius: var(--ks-r-sm);
      color: var(--ks-ink);
    }

    .modal.ks-modal-light .fi-inp:focus {
      border-color: var(--ks-accent);
      box-shadow: 0 0 0 3px var(--ks-accent-soft);
    }

    .modal.ks-modal-light .fi-inp::placeholder {
      color: var(--ks-ink-3);
    }

    /* Coached footage: the URL field stays visible but read-only, and says so. */
    .modal.ks-modal-light .fi-inp[readonly] {
      background: var(--ks-surface-sunken);
      color: var(--ks-ink-2);
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-toast.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── TOAST ─────────────────────────────────────────────────────────────────
       A confirmation is the smallest thing the product ever says. It used to be
       the loudest: a bright green block on near-black, in a product that is
       otherwise a light surface with dark ink. It read as an alert whether or
       not anything was wrong.

       Now it is a small card on the same surface as everything else, and the
       only colour is a three-pixel edge -- green when something worked, red
       when it did not. It carries the meaning without shouting it, and it
       inherits light and dark from the token layer rather than picking sides.
       ─────────────────────────────────────────────────────────────────────── */
    .toast {
      position: fixed;
      bottom: 1.5rem;
      right: 1.5rem;
      z-index: var(--z-toast);
      background: var(--ks-surface, #FFFFFF);
      border: 1px solid var(--ks-line, #DCE3ED);
      border-left: 3px solid var(--ks-success, #12784A);
      border-radius: var(--radius-sm);
      padding: 9px 14px;
      font-size: .78rem;
      font-weight: 600;
      line-height: 1.45;
      color: var(--ks-ink, #101828);
      box-shadow: 0 1px 2px rgba(16, 27, 48, .06), 0 14px 32px -16px rgba(16, 27, 48, .45);
      transform: translateY(10px);
      opacity: 0;
      transition: opacity .28s ease, transform .28s cubic-bezier(.2, .7, .3, 1);
      pointer-events: none;
      max-width: 20rem;
      letter-spacing: .2px
    }

    .toast.show {
      transform: translateY(0);
      opacity: 1
    }

    .toast-err {
      border-left-color: var(--ks-danger, #B3122B)
    }

    /* ── Where a toast may sit on a phone ─────────────────────────────────────
       Bottom-right is the desktop convention and it is fine there. On a phone
       this used to sit under the header, centred, on the theory that "the only
       thing beneath it is the tenant's own band" -- which was true until the
       flagship hero became crest-first, and the welcome toast landed exactly
       on the tenant's crest: transient feedback covering primary branding, on
       every tenant whose identity opens the page. The notification panel
       drops from the same corner, so the top was contested twice over.

       So it docks ABOVE the bottom dock instead -- centred, clear of the
       thumb's targets, colliding with nothing that persists: the crest and
       the panel own the top, the dock keeps its own ground, and the offset
       carries the dock's own height expression (60px + the safe-area inset;
       if the dock's height ever changes, this moves with it — same contract
       as the breakpoint, which is also the dock's). Still pointer-events:
       none, same markup, same timing -- one anchor decided by what owns each
       edge of a phone screen. */
    @media (max-width: 768px) {
      .toast {
        top: auto;
        bottom: calc(60px + env(safe-area-inset-bottom, 0px) + .75rem);
        right: auto;
        left: 50%;
        margin-inline: 0;
        max-width: min(calc(100vw - 2rem), 22rem);
        text-align: center;
        transform: translate(-50%, 12px);
      }

      .toast.show {
        transform: translate(-50%, 0)
      }
    }

    @media (prefers-reduced-motion: reduce) {
      .toast {
        transition: opacity .3s
      }
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-session-badge.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── SESSION BADGE ───────────────────────────────────────────────────────── */
    .session-badge {
      display: inline-flex;
      align-items: center;
      gap: .4rem;
      padding: 4px 10px;
      border-radius: 20px;
      font-size: .6rem;
      font-weight: 700;
      letter-spacing: 1px;
      text-transform: uppercase;
    }



/* ══════════════════════════════════════════════════════════════════════
   dojo-hotel-cards.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* /* ── HOTEL CARDS ─────────────────────────────────────────────────────────── */
    .hotel-card {
      display: flex;
      align-items: flex-start;
      gap: 1rem;
      background: rgba(18, 31, 54, 0.94);
      border: 1px solid rgba(255, 255, 255, 0.11);
      border-radius: 8px;
      padding: 1rem 1.25rem;
      transition: border-color .2s
    }

    .hotel-card:hover {
      border-color: color-mix(in oklab, var(--accent) 30%, transparent)
    }

    .hotel-icon {
      font-size: 1.5rem;
      flex-shrink: 0;
      padding-top: .1rem
    }

    .hotel-body {
      flex: 1;
      min-width: 0
    }

    .hotel-name {
      font-family: var(--ks-display);
      font-size: 1.1rem;
      font-weight: 800;
      color: var(--white);
      margin-bottom: .25rem
    }

    .hotel-meta {
      font-size: .92rem;
      font-weight: 600;
      color: var(--muted);
      line-height: 1.7
    }

    .hotel-meta span {
      color: var(--text)
    }

    .hotel-actions {
      display: flex;
      flex-direction: column;
      gap: .4rem;
      align-items: center;
      flex-shrink: 0
    }



/* ══════════════════════════════════════════════════════════════════════
   dojo-next-event-widget.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── NEXT EVENT WIDGET ───────────────────────────────────────────────────── */
    .next-event-wrap {
      position: absolute;
      top: 1rem;
      left: 1rem;
      z-index: 10;
      width: 230px;
      cursor: pointer
    }

    .next-event-card {
      background: var(--ks-accent);
      border-radius: 6px;
      overflow: hidden;
      box-shadow: 0 4px 24px color-mix(in oklab, var(--accent) 35%, transparent), 0 8px 32px rgba(0, 0, 0, 0.5);
      border: 1px solid rgba(240, 220, 154, 0.4);
      transition: all .3s cubic-bezier(0.165, 0.84, 0.44, 1);
      position: relative;
      overflow: hidden
    }

    .next-event-card::before {
      content: '';
      position: absolute;
      top: 0;
      left: -100%;
      width: 100%;
      height: 100%;
      background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent);
      transition: left .6s;
      pointer-events: none
    }

    .next-event-card:hover::before {
      left: 100%
    }

    .next-event-card:hover {
      transform: translateY(-3px);
      box-shadow: 0 12px 40px color-mix(in oklab, var(--accent) 60%, transparent)
    }

    .next-event-hdr {
      padding: .45rem .75rem;
      display: flex;
      align-items: center;
      justify-content: space-between;
      border-bottom: 1px solid rgba(0, 0, 0, 0.12)
    }

    .next-event-label {
      font-size: .62rem;
      letter-spacing: 3px;
      text-transform: uppercase;
      color: #160E00;
      font-weight: 900
    }

    .next-event-badge {
      font-size: .58rem;
      font-weight: 900;
      letter-spacing: 1.5px;
      padding: 3px 9px;
      border-radius: 2px;
      background: rgba(0, 0, 0, 0.2);
      color: #160E00
    }

    .next-event-body {
      padding: .85rem .9rem;
      display: flex;
      gap: .75rem;
      align-items: flex-start
    }

    .next-event-date-block {
      flex-shrink: 0;
      text-align: center;
      background: rgba(0, 0, 0, 0.15);
      border-radius: 4px;
      padding: .4rem .55rem;
      min-width: 46px
    }

    .next-event-mon {
      font-size: .58rem;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: #160E00;
      font-weight: 800
    }

    .next-event-day {
      font-family: var(--ks-display);
      font-size: 1.5rem;
      color: #160E00;
      line-height: 1;
      font-weight: 900
    }

    .next-event-info {
      flex: 1;
      min-width: 0
    }

    .next-event-name {
      font-family: var(--ks-display);
      font-size: .85rem;
      color: #160E00;
      margin-bottom: .25rem;
      font-weight: 900;
      line-height: 1.3
    }

    .next-event-loc {
      font-size: .72rem;
      color: #160E00;
      font-weight: 700;
      opacity: .85
    }

    .next-event-hotel {
      margin-top: .6rem;
      padding: .55rem .7rem;
      background: rgba(0, 0, 0, 0.18);
      border-radius: 4px;
      border: 1px solid rgba(0, 0, 0, 0.15)
    }

    .next-event-hotel-title {
      font-size: .62rem;
      letter-spacing: 2px;
      text-transform: uppercase;
      color: #160E00;
      font-weight: 900;
      margin-bottom: .3rem
    }

    .next-event-hotel-name {
      font-size: .8rem;
      color: #160E00;
      font-weight: 900;
      margin-bottom: .15rem
    }

    .next-event-hotel-meta {
      font-size: .68rem;
      color: #160E00;
      font-weight: 700;
      opacity: .85
    }

    .next-event-links {
      display: flex;
      gap: .5rem;
      padding: .6rem .9rem;
      border-top: 1px solid rgba(0, 0, 0, 0.15)
    }

    .next-event-link {
      font-size: .6rem;
      font-weight: 900;
      letter-spacing: 1.5px;
      text-transform: uppercase;
      color: #160E00;
      text-decoration: none;
      transition: opacity .2s
    }

    .next-event-link:hover {
      opacity: .7
    }

    .next-event-close {
      background: none;
      border: none;
      cursor: pointer;
      color: #160E00;
      font-size: 1rem;
      line-height: 1;
      padding: 2px 4px;
      opacity: .6;
      transition: opacity .2s;
      font-weight: 900
    }

    .next-event-close:hover {
      opacity: 1
    }



/* ══════════════════════════════════════════════════════════════════════
   dojo-find-tournaments-empty-loading-states.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    .ft-empty {
      text-align: center;
      padding: 3rem 1rem;
      color: var(--muted);
      font-size: .82rem;
      border: 1px dashed rgba(255, 255, 255, 0.1);
      border-radius: 8px
    }

    .ft-empty-icon {
      font-size: 2.5rem;
      margin-bottom: .75rem;
      opacity: .5
    }

    .ft-loading {
      text-align: center;
      padding: 2rem;
      color: var(--ks-accent-strong);
      font-size: .78rem;
      letter-spacing: 1px
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-score-card-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Score card */
    .score-badge {
      font-size: .68rem
    }

    .score-name {
      font-size: 1rem
    }

    .score-vs {
      font-size: .82rem
    }

    .opp-name-input {
      font-size: .95rem
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-modals-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Modals */
    .mhdr-title {
      font-size: 1.1rem
    }

    .tab-btn {
      font-size: .82rem
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-toast-session-badge-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Toast */
    .toast {
      font-size: .9rem
    }



    /* Session badge */
    .session-badge {
      font-size: .72rem
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-event-cards-blocks-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Event Cards & Blocks */
    .event-card-name {
      font-size: 1.35rem;
      color: #FFFFFF;
      font-weight: 700;
    }

    .event-card-meta {
      font-size: .95rem;
      color: #E0DCD2;
      font-weight: 600;
    }

    .event-card-desc {
      font-size: .95rem;
      color: #E0DCD2;
    }

    .event-hotel-sub-title {
      font-size: .75rem;
      color: var(--ks-accent-strong);
      font-weight: 800;
    }

    .hotel-sub-card {
      font-size: .95rem;
      color: #E0DCD2;
      font-weight: 500;
    }

    .hotel-sub-name {
      font-size: 1.05rem;
      color: #FFFFFF;
      font-weight: 800;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-hotels-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Hotels */
    .hotel-name {
      font-size: 1.15rem;
      color: #FFFFFF;
    }

    .hotel-meta {
      font-size: .95rem;
      color: #E0DCD2;
      font-weight: 600;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-next-event-widget-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Next event widget */
    .next-event-label {
      font-size: .75rem;
      color: #160E00;
      font-weight: 900;
    }

    .next-event-badge {
      font-size: .72rem;
      color: #160E00;
      font-weight: 900;
    }

    .next-event-mon {
      font-size: .72rem;
      color: #160E00;
      font-weight: 800;
    }

    .next-event-name {
      font-size: 1.15rem;
      color: #160E00;
      font-weight: 900;
    }

    .next-event-loc {
      font-size: .9rem;
      color: #160E00;
      font-weight: 800;
    }

    .next-event-hotel-title {
      font-size: .75rem;
      color: #160E00;
      font-weight: 900;
    }

    .next-event-hotel-name {
      font-size: 1.05rem;
      color: #160E00;
      font-weight: 900;
    }

    .next-event-hotel-meta {
      font-size: .9rem;
      color: #160E00;
      font-weight: 800;
    }

    .next-event-link {
      font-size: .78rem;
      color: #160E00;
      font-weight: 900;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-find-tournaments-typography.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* Find tournaments */
    .ft-form-title {
      font-size: 1rem
    }

    .ft-chip {
      font-size: .78rem
    }

    .ft-results-count {
      font-size: .82rem
    }

    .ft-card-name {
      font-size: 1.15rem;
      color: #FFFFFF;
      font-weight: 700;
    }

    .ft-card-meta {
      font-size: .95rem;
      color: #E0DCD2;
      font-weight: 600;
    }

    .ft-card-desc {
      font-size: .95rem;
      color: #E0DCD2;
      font-weight: 500;
    }

    .ft-card-distance-label {
      font-size: .75rem;
      color: var(--ks-accent-strong);
      font-weight: 700;
    }

    .ft-org-badge {
      font-size: .75rem;
    }

    .ft-ext-name {
      font-size: 1.05rem;
      color: #FFFFFF;
      font-weight: 700;
    }

    .ft-ext-desc {
      font-size: .88rem;
      color: #E0DCD2;
    }

    .ft-empty {
      font-size: .95rem
    }

    .ft-loading {
      font-size: .9rem
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-add-calendar-schedule.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Schedule-specific Add to Calendar overrides ──────────────── */
    #view-schedule .ks-add-cal-wrap {
      display: inline-flex;
    }

    #view-schedule .ks-add-cal-btn {
      display: inline-flex;
      align-items: center;
      padding: 5px 12px !important;
      border-radius: var(--ks-r-control)!important;
      font-size: .65rem !important;
      font-weight: 700;
      letter-spacing: .8px;
      text-transform: uppercase;
      cursor: pointer;
      transition: all .22s ease;
      background: transparent;
      color: #64748B;
      border: 1px solid #E2E8F0 !important;
    }

    #view-schedule .ks-add-cal-btn:hover {
      border-color: color-mix(in oklab, var(--accent) 35%, transparent) !important;
      color: var(--ks-accent-strong);
      background: color-mix(in oklab, var(--accent) 4%, transparent);
    }

    #view-schedule .ks-add-cal-menu {
      background: #fff;
      border: 1px solid #e2e8f0;
      box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
    }

    #view-schedule .ks-add-cal-opt {
      color: #334155;
      font-size: .78rem;
    }

    #view-schedule .ks-add-cal-opt:hover {
      background: color-mix(in oklab, var(--accent) 8%, transparent);
      color: var(--ks-accent-strong);
    }

    #view-schedule .ks-add-cal-opt+.ks-add-cal-opt {
      border-top: 1px solid #f1f5f9;
    }

    @media (max-width: 767px) {
      #view-schedule .ks-add-cal-btn {
        min-height: 36px;
        padding: 6px 14px !important;
        font-size: .62rem !important;
      }
    }



/* ══════════════════════════════════════════════════════════════════════
   dojo-add-calendar-dropdown.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ── Add to Calendar dropdown ─────────────────────────────────── */
    .ks-add-cal-wrap {
      position: relative;
      display: inline-flex;
    }

    .ks-add-cal-btn {
      font-size: .72rem !important;
      padding: 5px 12px !important;
      white-space: nowrap;
      display: inline-flex;
      align-items: center;
      gap: .35rem;
    }

    /* The sprite glyph that replaced the 📅 emoji, sized to the label. */
    .ks-add-cal-btn .ks-icon {
      width: 13px;
      height: 13px;
      flex-shrink: 0;
    }

    .ks-add-cal-menu {
      display: none;
      position: absolute;
      bottom: calc(100% + 6px);
      left: 0;
      z-index: 50;
      min-width: 190px;
      background: #1e293b;
      border: 1px solid rgba(202, 169, 104, .35);
      border-radius: 8px;
      box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
      overflow: hidden;
    }

    .ks-add-cal-wrap.open .ks-add-cal-menu {
      display: block;
    }

    .ks-add-cal-opt {
      display: block;
      width: 100%;
      padding: 10px 14px;
      font-size: .82rem;
      color: #e2e8f0;
      text-align: left;
      background: transparent;
      border: none;
      cursor: pointer;
      text-decoration: none;
      font-family: inherit;
      transition: background .15s;
    }

    .ks-add-cal-opt:hover {
      background: rgba(202, 169, 104, .15);
      color: #caa968;
    }

    .ks-add-cal-opt+.ks-add-cal-opt {
      border-top: 1px solid rgba(255, 255, 255, .08);
    }



/* ══════════════════════════════════════════════════════════════════════
   dojo-tournament-info-event-seminar-dark-cards.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* This file was the dark treatment for #view-find-tournaments -- event and
       seminar cards, the RSVP panel, hotel blocks, sections and buttons -- and
       set every property with !important, so nothing could restyle the view
       without fighting it.

       dojo-events-shell.v1.css now owns all of it through the semantic tokens,
       which is what lets this view answer for both themes instead of being dark
       whatever the reader asked for.

       Kept as a file rather than deleted: 166 link tags reference these by name
       and a 404 per visitor is the worse trade. */


/* ══════════════════════════════════════════════════════════════════════
   dojo-schedule-mini-calendar-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* This was part of the dark treatment for #view-schedule and set its colours
       with !important, so the view could not be restyled without fighting it.
       dojo-schedule-shell.v1.css owns them through the semantic tokens now, which
       is what lets this view answer for both themes.

       Its structural siblings are untouched: -responsive-dark carries padding and
       radius rather than colour, and -focus-visible-dark and -reduced-motion-dark
       set no !important, so ordinary cascade order is enough for those.

       Kept as a file rather than deleted: 166 link tags reference these by name
       and a 404 per visitor is the worse trade. */


/* ══════════════════════════════════════════════════════════════════════
   dojo-schedule-event-list-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* This was part of the dark treatment for #view-schedule and set its colours
       with !important, so the view could not be restyled without fighting it.
       dojo-schedule-shell.v1.css owns them through the semantic tokens now, which
       is what lets this view answer for both themes.

       Its structural siblings are untouched: -responsive-dark carries padding and
       radius rather than colour, and -focus-visible-dark and -reduced-motion-dark
       set no !important, so ordinary cascade order is enough for those.

       Kept as a file rather than deleted: 166 link tags reference these by name
       and a 404 per visitor is the worse trade. */


/* ══════════════════════════════════════════════════════════════════════
   dojo-schedule-actions-quicklinks-dark.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* This was part of the dark treatment for #view-schedule and set its colours
       with !important, so the view could not be restyled without fighting it.
       dojo-schedule-shell.v1.css owns them through the semantic tokens now, which
       is what lets this view answer for both themes.

       Its structural siblings are untouched: -responsive-dark carries padding and
       radius rather than colour, and -focus-visible-dark and -reduced-motion-dark
       set no !important, so ordinary cascade order is enough for those.

       Kept as a file rather than deleted: 166 link tags reference these by name
       and a 404 per visitor is the worse trade. */


/* ══════════════════════════════════════════════════════════════════════
   dojo-premium-profile-sections.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* The legacy --gold/--faint/--dim set is the app's original dark-only
       palette, from before the token layer existed. On a surface that follows
       the theme it is only ever right by accident: in the light theme the
       competitor's own name read at 2.11:1 and their belt at 1.27:1 -- there
       on screen and effectively invisible. --dim failed on the dark canvas
       too, at 3.8:1, so this was not a light-theme problem either. */
    /* ── PREMIUM PROFILE SECTIONS ────────────────────────────────────────── */
    .fd-profile-section {
      margin: 0 1.5rem;
      border-top: 1px solid rgba(255, 255, 255, 0.06);
      padding: .9rem 0 .7rem;
    }

    .fd-profile-section:first-child {
      border-top: none;
      padding-top: .5rem
    }

    .fd-profile-label {
      font-size: .6rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.5px;
      color: var(--ks-accent-strong);
      margin-bottom: .35rem;
      opacity: .8
    }

    .fd-profile-value {
      font-size: .82rem;
      color: var(--ks-ink-2);
      line-height: 1.55;
      white-space: pre-line;
      word-break: break-word
    }

    .fd-profile-value:empty {
      display: none
    }

    .fd-profile-inp {
      width: 100%;
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid rgba(255, 255, 255, 0.08);
      border-radius: 6px;
      padding: .45rem .6rem;
      color: var(--ks-ink-2);
      font-size: .8rem;
      font-family: inherit;
      resize: none;
      outline: none;
      transition: border-color .2s
    }

    .fd-profile-inp:focus {
      border-color: color-mix(in oklab, var(--accent) 15%, transparent)
    }

    .fd-profile-inp::placeholder {
      color: var(--ks-ink-3);
      font-style: italic;
      font-size: .75rem
    }

    textarea.fd-profile-inp {
      min-height: 52px
    }

    /* Achievement pills */
    .fd-achievements-wrap {
      display: flex;
      flex-wrap: wrap;
      gap: .35rem;
      margin-top: .2rem
    }

    .fd-ach-pill {
      display: inline-block;
      padding: 3px 10px;
      border-radius: 20px;
      background: color-mix(in oklab, var(--accent) 10%, transparent);
      border: 1px solid color-mix(in oklab, var(--accent) 25%, transparent);
      font-size: .65rem;
      font-weight: 700;
      letter-spacing: .5px;
      color: var(--ks-accent-strong);
      text-transform: uppercase
    }

    /* Social links row */
    .fd-socials-row {
      display: flex;
      gap: .7rem;
      align-items: center;
      margin-top: .25rem;
      flex-wrap: wrap
    }

    .fd-social-link {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      font-size: .72rem;
      color: var(--ks-ink-2);
      text-decoration: none;
      opacity: .7;
      transition: opacity .2s
    }

    .fd-social-link:hover {
      opacity: 1;
      color: var(--ks-accent-strong)
    }

    .fd-social-link svg {
      width: 14px;
      height: 14px;
      fill: currentColor
    }

    /* The participation figures, on the athlete band beside the name.
       Sized to be read across a room rather than squeezed under the belt line:
       they were 1.15rem numerals over a 0.5rem label, which at the foot of a
       cramped identity block was the smallest type on the page carrying two of
       its three facts. */
    .fd-pub-stats {
      display: flex;
      gap: clamp(1.25rem, 3vw, 2.5rem);
      flex-wrap: wrap;
      flex-shrink: 0;
    }

    .fd-pub-stat {
      min-width: 68px;
      padding-left: 1rem;
      border-left: 1px solid var(--ks-band-line);
    }

    .fd-pub-stat-num {
      font-family: var(--ks-display);
      font-size: clamp(1.7rem, 3vw, 2.4rem);
      font-weight: 700;
      color: var(--ks-band-accent);
      line-height: 1
    }

    .fd-pub-stat-label {
      font-size: .58rem;
      font-weight: 800;
      text-transform: uppercase;
      letter-spacing: .14em;
      color: var(--ks-band-ink-3);
      margin-top: .35rem
    }

    /* The kumite record, in the Matches tab.
       Styled as a caption on the list rather than as a headline: it summarises
       what is below it. It used to sit under the athlete's name in the same
       weight as their belt, which made a student's record the first thing the
       profile said about them. */
    .fd-match-record {
      display: flex;
      align-items: baseline;
      gap: .5rem;
      padding: .85rem 1.5rem .25rem;
    }

    .fd-match-record-label {
      font-size: .55rem;
      text-transform: uppercase;
      letter-spacing: 1px;
      color: var(--ks-ink-3);
    }

    .fd-match-record-value {
      font-size: .8rem;
      font-weight: 700;
      color: var(--ks-ink-2);
      letter-spacing: .04em;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-badge-premium-frame.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ══ PREMIUM BADGE FRAME ════════════════════════════════════════════════ */
    .home-badge-premium-frame {
      --badge-x: 0.5;
      --badge-y: 0.5;
      position: relative;
      display: inline-block;
      width: 100%;
      max-width: min(560px, 82vw);
      margin: 0 auto .35rem;
    }

    /* ── Soft white light bloom ─────────────────────────────────────────── */
    .home-badge-premium-frame::before {
      content: '';
      position: absolute;
      inset: -18%;
      z-index: 0;
      pointer-events: none;
      background:
        radial-gradient(ellipse 55% 50% at 50% 48%, rgba(255, 255, 255, 0.12) 0%, transparent 70%),
        radial-gradient(ellipse 40% 35% at 52% 42%, rgba(255, 255, 255, 0.08) 0%, transparent 60%),
        radial-gradient(ellipse 30% 28% at 48% 55%, rgba(255, 255, 255, 0.06) 0%, transparent 55%);
      filter: blur(18px);
      opacity: 0.85;
      transition: opacity 0.4s ease;
    }

    /* ── Gold dust sparkle layer ────────────────────────────────────────── */
    .home-badge-premium-frame::after {
      content: '';
      position: absolute;
      inset: -8%;
      z-index: 3;
      pointer-events: none;
      opacity: 0.18;
      background-image:
        radial-gradient(1px 1px at 15% 25%, color-mix(in oklab, var(--accent) 90%, transparent) 0%, transparent 100%),
        radial-gradient(1px 1px at 72% 18%, rgba(218, 190, 110, 0.8) 0%, transparent 100%),
        radial-gradient(1.5px 1.5px at 45% 72%, color-mix(in oklab, var(--accent) 70%, transparent) 0%, transparent 100%),
        radial-gradient(1px 1px at 88% 55%, rgba(255, 220, 140, 0.6) 0%, transparent 100%),
        radial-gradient(1px 1px at 28% 85%, color-mix(in oklab, var(--accent) 80%, transparent) 0%, transparent 100%),
        radial-gradient(1.2px 1.2px at 62% 38%, rgba(218, 190, 110, 0.7) 0%, transparent 100%),
        radial-gradient(0.8px 0.8px at 35% 48%, rgba(255, 220, 140, 0.65) 0%, transparent 100%),
        radial-gradient(1px 1px at 82% 78%, color-mix(in oklab, var(--accent) 75%, transparent) 0%, transparent 100%),
        radial-gradient(1.2px 1.2px at 8% 62%, rgba(218, 190, 110, 0.6) 0%, transparent 100%),
        radial-gradient(0.8px 0.8px at 55% 12%, color-mix(in oklab, var(--accent) 70%, transparent) 0%, transparent 100%),
        radial-gradient(1px 1px at 92% 35%, rgba(255, 220, 140, 0.55) 0%, transparent 100%),
        radial-gradient(1.3px 1.3px at 20% 92%, color-mix(in oklab, var(--accent) 65%, transparent) 0%, transparent 100%);
      background-size: 100% 100%;
      animation: badgeSparkle 11s ease-in-out infinite;
    }

    @keyframes badgeSparkle {

      0%,
      100% {
        opacity: 0.14;
        transform: translateY(0) scale(1);
      }

      33% {
        opacity: 0.22;
        transform: translateY(-2px) scale(1.02);
      }

      66% {
        opacity: 0.12;
        transform: translateY(1px) scale(0.99);
      }
    }

    /* ── Platinum edge glow (on image) ──────────────────────────────────── */
    .home-badge-premium-frame #home-logo-img {
      position: relative;
      z-index: 1;
      width: 100%;
      max-height: clamp(140px, 24vh, 250px);
      height: auto;
      display: block;
      margin-top: -3%;
      margin-bottom: -6%;
      object-fit: contain;
      filter:
        brightness(1.15) contrast(1.18) saturate(1.22) drop-shadow(0 0 18px rgba(200, 210, 230, 0.22)) drop-shadow(0 14px 42px rgba(0, 0, 0, 0.65));
      transition: transform 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94),
        filter 0.45s ease,
        opacity 0.6s ease;
    }

    /* ── Slow breathing aura ────────────────────────────────────────────── */
    .home-badge-premium-frame .badge-aura {
      position: absolute;
      inset: -12%;
      z-index: 0;
      pointer-events: none;
      border-radius: 50%;
      background: radial-gradient(ellipse 60% 55% at 50% 50%,
          rgba(200, 210, 235, 0.06) 0%,
          color-mix(in oklab, var(--accent) 3%, transparent) 40%,
          transparent 70%);
      animation: badgeBreathe 7s ease-in-out infinite;
    }

    @keyframes badgeBreathe {

      0%,
      100% {
        transform: scale(1);
        opacity: 0.6;
      }

      50% {
        transform: scale(1.04);
        opacity: 0.85;
      }
    }

    /* ── Mouse parallax spotlight ───────────────────────────────────────── */
    .home-badge-premium-frame .badge-spotlight {
      position: absolute;
      inset: -5%;
      z-index: 2;
      pointer-events: none;
      border-radius: 50%;
      background: radial-gradient(circle 180px at calc(var(--badge-x) * 100%) calc(var(--badge-y) * 100%),
          rgba(255, 255, 255, 0.07) 0%,
          transparent 70%);
      opacity: 0;
      transition: opacity 0.6s ease;
    }

    .home-badge-premium-frame:hover .badge-spotlight,
    .home-badge-premium-frame.badge-has-mouse .badge-spotlight {
      opacity: 1;
    }

    /* ── Premium hover state ────────────────────────────────────────────── */
    .home-badge-premium-frame:hover #home-logo-img {
      transform: translateY(-5px);
      filter:
        brightness(1.2) contrast(1.2) saturate(1.25) drop-shadow(0 0 24px rgba(200, 210, 230, 0.3)) drop-shadow(0 16px 48px rgba(0, 0, 0, 0.6));
    }

    .home-badge-premium-frame:hover::after {
      opacity: 0.28;
    }

    .home-badge-premium-frame:hover::before {
      opacity: 1;
    }

    /* ── Mobile safe ────────────────────────────────────────────────────── */
    @media (max-width: 768px) {
      .home-badge-premium-frame {
        max-width: min(420px, 84vw);
      }

      .home-badge-premium-frame::before {
        inset: -10%;
        filter: blur(12px);
        opacity: 0.5;
      }

      .home-badge-premium-frame::after {
        opacity: 0.10;
        animation-duration: 14s;
      }

      .home-badge-premium-frame .badge-aura {
        inset: -8%;
        animation-duration: 9s;
      }

      .home-badge-premium-frame .badge-spotlight {
        display: none;
      }

      .home-badge-premium-frame #home-logo-img {
        max-height: clamp(110px, 18vh, 170px);
        filter:
          brightness(1.15) contrast(1.18) saturate(1.22) drop-shadow(0 0 10px rgba(200, 210, 230, 0.15)) drop-shadow(0 10px 28px rgba(0, 0, 0, 0.6));
      }

      .home-badge-premium-frame:hover #home-logo-img {
        transform: translateY(-3px);
        filter:
          brightness(1.2) contrast(1.2) saturate(1.25) drop-shadow(0 0 14px rgba(200, 210, 230, 0.22)) drop-shadow(0 8px 24px rgba(0, 0, 0, 0.5));
      }
    }

    /* ── Accessibility: prefers-reduced-motion ──────────────────────────── */
    @media (prefers-reduced-motion: reduce) {

      .home-badge-premium-frame::after,
      .home-badge-premium-frame .badge-aura {
        animation: none !important;
      }

      .home-badge-premium-frame:hover #home-logo-img {
        transform: none;
      }

      .home-badge-premium-frame .badge-spotlight {
        display: none;
      }
    }

    /* Admin upload button z-index fix */
    .home-badge-premium-frame .admin-upload-btn {
      z-index: 10;
      position: relative;
    }



/* ══════════════════════════════════════════════════════════════════════
   dojo-tournament-hub-private-planning-ui.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ═══════════════════════════════════════════════════════════════════════
       Tournament Hub: private team tournament planning UI
       ═══════════════════════════════════════════════════════════════════════ */
    /* On the token layer rather than a fixed light palette. These two are the
       signed-in surfaces -- the hub is where every role lands -- and they were
       rendering as a white slab for anyone whose system is set to dark, because
       nothing here could tell which theme it was in. */
    .ks-team-hub-shell,
    .ks-tourney-admin-shell {
      background: var(--ks-canvas);
      color: var(--ks-ink);
    }

    /* The manager is its own view now rather than a panel inside #view-admin,
       and it was that view supplying the page canvas: background plus
       min-height:100vh. Without them the 72px .view.active reserves for the
       fixed nav shows the body gradient above the shell, and short content
       leaves the same dark band below it. Same two properties, same values,
       now carried by the view that actually needs them. */
    #view-tournament-manager {
      /* min-height dropped: the body is a flex column and .view.active grows
         into the space instead, so the canvas still reaches the bottom of a
         short page without a viewport of it appearing above the footer. */
      background: var(--ks-canvas);
      color: var(--ks-ink);
    }

    /* Shares the page measure and gutter with the band above it, so the hub's
       first card starts on the same left edge as the title. At 1120px in its own
       margin it sat forty pixels inside the band's copy, which reads as a
       misalignment rather than as an inset. */
    /* ── The stat strip ────────────────────────────────────────────────────
       Straddles the band's foot the way the home quick links straddle the hero
       -- the same signature move, so the two screens read as one product. */
    .ks-hub-stats-wrap {
      padding: 0 var(--ks-gutter);
      margin-top: clamp(-2.4rem, -3.5vw, -1.5rem);
      position: relative;
      z-index: 2;
    }

    .ks-hub-stats {
      max-width: var(--ks-measure);
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      background: var(--ks-surface);
      border: 1px solid var(--ks-line);
      border-radius: 18px;
      box-shadow: var(--ks-shadow-2);
      overflow: hidden;
    }

    .ks-hub-stats[hidden] {
      display: none;
    }

    .ks-hub-stat {
      padding: clamp(.9rem, 2vw, 1.35rem) 1rem;
      text-align: center;
    }

    .ks-hub-stat + .ks-hub-stat {
      border-left: 1px solid var(--ks-line-soft);
    }

    .ks-hub-stat strong {
      display: block;
      font-family: var(--ks-display);
      font-size: clamp(1.6rem, 3.4vw, 2.3rem);
      font-weight: 700;
      line-height: 1;
      color: var(--ks-accent-strong);
    }

    .ks-hub-stat span {
      display: block;
      margin-top: .4rem;
      font-size: .6rem;
      font-weight: 800;
      letter-spacing: .12em;
      text-transform: uppercase;
      color: var(--ks-ink-3);
    }

    /* ── This week ─────────────────────────────────────────────────────────── */
    .ks-hub-week-list {
      display: grid;
      gap: .45rem;
    }

    .ks-hub-week-row {
      display: flex;
      align-items: center;
      gap: .75rem;
      width: 100%;
      padding: .5rem .55rem;
      border: 1px solid transparent;
      border-radius: 12px;
      background: none;
      text-align: left;
      cursor: pointer;
      transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
    }

    .ks-hub-week-row:hover,
    .ks-hub-week-row:focus-visible {
      background: var(--ks-accent-soft);
      border-color: var(--ks-accent);
    }

    .ks-hub-week-row:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: 1px;
    }

    .ks-hub-week-date {
      flex-shrink: 0;
      width: 44px;
      padding: .3rem 0;
      border-radius: 10px;
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      text-align: center;
    }

    .ks-hub-week-date span {
      display: block;
      font-size: .52rem;
      font-weight: 800;
      letter-spacing: .1em;
      color: var(--ks-ink-3);
    }

    .ks-hub-week-date strong {
      display: block;
      font-family: var(--ks-display);
      font-size: 1.05rem;
      line-height: 1.1;
      color: var(--ks-ink);
    }

    .ks-hub-week-copy {
      min-width: 0;
    }

    .ks-hub-week-copy strong {
      display: block;
      font-size: .82rem;
      font-weight: 800;
      color: var(--ks-ink);
      line-height: 1.3;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .ks-hub-week-copy span {
      display: block;
      margin-top: .1rem;
      font-size: .7rem;
      color: var(--ks-ink-3);
      font-weight: 600;
    }

    /* ── The member's monogram ─────────────────────────────────────────────── */
    .ks-hub-me-head {
      align-items: center;
    }

    .ks-hub-avatar {
      flex-shrink: 0;
      width: 52px;
      height: 52px;
      border-radius: 50%;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(160deg, var(--ks-band-raised), var(--ks-band-deep));
      border: 2px solid var(--ks-band-edge);
      color: var(--ks-band-accent);
      font-family: var(--ks-display);
      font-size: 1.05rem;
      font-weight: 700;
      letter-spacing: .04em;
    }

    /* ── The announcement ──────────────────────────────────────────────────── */
    .ks-hub-announcement-text {
      margin: 0;
      color: var(--ks-ink-2);
      font-size: .85rem;
      line-height: 1.6;
      font-weight: 600;
    }

    /* ── The featured tournament's cover ───────────────────────────────────
       A branded plate always: the tenant's band colours, the ribbon, a lift of
       gold. The listing's flyer sits over it when the tenant has uploaded one
       and the gateway serves it -- object-fit cover with a fixed height, so a
       flyer of any shape crops rather than reflows and nothing below it
       shifts. */
    .ks-hub-cover {
      position: relative;
      display: block;
      height: clamp(84px, 11vw, 128px);
      background:
        linear-gradient(115deg,
          transparent 55%,
          rgba(178, 34, 52, .55) 55.5% 59.5%,
          rgba(255, 255, 255, .32) 60% 61.8%,
          rgba(178, 34, 52, .45) 62.3% 64.4%,
          transparent 65%),
        radial-gradient(80% 130% at 8% 110%, color-mix(in oklab, var(--accent) 28%, transparent) 0%, transparent 55%),
        linear-gradient(150deg, var(--ks-band-deep) 0%, var(--ks-band) 55%, var(--ks-band-raised) 100%);
      border-bottom: 2px solid var(--ks-band-edge);
      overflow: hidden;
    }

    .ks-hub-cover img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    /* The affordance appears only when the cover really is a flyer. */
    .ks-hub-cover-open {
      display: none;
    }

    .ks-hub-cover-flyer .ks-hub-cover-open {
      display: inline-flex;
      position: absolute;
      right: .65rem;
      bottom: .6rem;
      padding: .3rem .65rem;
      border-radius: 999px;
      background: rgba(4, 8, 16, .72);
      color: var(--ks-band-ink);
      font-size: .58rem;
      font-weight: 800;
      letter-spacing: .1em;
      text-transform: uppercase;
    }

    .ks-hub-cover-flyer:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: -2px;
    }

    .ks-team-hub-next-body {
      padding-top: .85rem;
    }

    /* ── Travel, as a card ─────────────────────────────────────────────────── */
    .ks-hub-travel {
      margin-top: .65rem;
      border: 1px solid var(--ks-line);
      border-left: 3px solid var(--ks-accent);
      border-radius: 12px;
      background: var(--ks-surface-sunken);
      padding: .8rem .85rem;
    }

    .ks-hub-travel-head strong {
      display: block;
      margin-top: .1rem;
      color: var(--ks-ink);
      font-size: .95rem;
      font-weight: 850;
    }

    .ks-hub-travel-dates {
      display: block;
      margin-top: .15rem;
      color: var(--ks-ink-2);
      font-size: .78rem;
      font-weight: 700;
    }

    .ks-hub-travel-note {
      margin: .5rem 0 0;
      color: var(--ks-ink-2);
      font-size: .82rem;
      line-height: 1.55;
    }

    .ks-hub-travel .ks-team-hub-actions {
      margin-top: .65rem;
    }

    /* ── The phone's order is priority, not column membership ──────────────
       On a desktop the grid is tournaments beside the member's rail. Stacked
       naively that puts every tournament detail above This Week, which is the
       section an active member comes back for. display:contents dissolves the
       two column wrappers on a phone so the cards themselves take an explicit
       order: coach first for coaches, the member's own card, the featured
       tournament with its action, This Week, the announcement, then the rest.
       Desktop is untouched. */
    @media (max-width: 639px) {
      .ks-team-hub-grid {
        display: flex;
        flex-direction: column;
        gap: 1rem;
      }

      .ks-team-hub-grid > div {
        display: contents;
      }

      #ks-team-hub-coach { order: 1; }
      #ks-team-hub-me { order: 2; }
      #ks-team-hub-next { order: 3; }
      #ks-hub-week { order: 4; }
      #ks-hub-announcement { order: 5; }
      #ks-team-hub-my-events { order: 6; }
      #ks-team-hub-listing-rsvp-card { order: 7; }

      /* The remaining tournaments card has no id; it is the main column's
         second child and lands last, which is where secondary events belong. */
      .ks-team-hub-grid > div > .ks-team-hub-card:not([id]) { order: 8; }
    }

    /* ── Trip preparation, behind one door ─────────────────────────────────
       The same native-disclosure language as the tournament rows below, in a
       quieter register: the depth is a drawer inside the card, not a card of
       its own. Render-time decides its default -- open where there is room,
       closed where it was most of the scroll. */
    .ks-hub-prep {
      margin-top: .75rem;
      border: 1px solid var(--ks-line);
      border-radius: 12px;
      background: var(--ks-surface);
    }

    .ks-hub-prep-summary {
      list-style: none;
      cursor: pointer;
      padding: .7rem 2.2rem .7rem .85rem;
      position: relative;
      font-size: .68rem;
      font-weight: 800;
      letter-spacing: .12em;
      text-transform: uppercase;
      color: var(--ks-ink-2);
    }

    .ks-hub-prep-summary::-webkit-details-marker {
      display: none;
    }

    .ks-hub-prep-summary::after {
      content: '›';
      position: absolute;
      right: .9rem;
      top: 50%;
      translate: 0 -50%;
      font-size: 1.05rem;
      color: var(--ks-ink-3);
      transition: rotate var(--duration-fast) var(--ease-out);
    }

    .ks-hub-prep[open] > .ks-hub-prep-summary::after {
      rotate: 90deg;
    }

    @media (prefers-reduced-motion: reduce) {
      .ks-hub-prep-summary::after {
        transition: none;
      }
    }

    .ks-hub-prep-summary:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: -2px;
      border-radius: 12px;
    }

    .ks-hub-prep-body {
      padding: 0 .85rem .85rem;
    }

    .ks-hub-prep-body > :first-child {
      margin-top: 0;
    }

    /* ── The featured tournament reads like a headline, not a record ───────── */
    .ks-team-hub-next .ks-team-hub-card-title {
      font-family: var(--ks-display);
      font-size: clamp(1.35rem, 2.6vw, 1.9rem);
      letter-spacing: .01em;
    }

    @media (min-width: 960px) {
      .ks-team-hub-next .ks-team-hub-meta-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
      }
    }

    .ks-team-hub-wrap,
    .ks-tourney-admin-wrap {
      width: 100%;
      max-width: var(--ks-measure);
      margin: 0 auto;
      padding: clamp(1.25rem, 3vw, 2rem) var(--ks-gutter) var(--ks-section-gap);
    }

    .ks-team-hub-hero,
    .ks-tourney-admin-hero {
      background: linear-gradient(135deg, var(--ks-surface) 0%, var(--ks-surface-sunken) 100%);
      border: 1px solid var(--ks-line);
      border-radius: 18px;
      padding: 1.25rem;
      box-shadow: var(--ks-shadow-3);
      margin-bottom: 1rem;
    }

    .ks-team-hub-kicker,
    .ks-tourney-admin-kicker {
      color: var(--ks-accent-strong);
      font-size: .68rem;
      font-weight: 800;
      letter-spacing: 2px;
      text-transform: uppercase;
      margin-bottom: .35rem;
    }

    .ks-team-hub-title,
    .ks-tourney-admin-title {
      font-family: var(--ks-display);
      color: var(--ks-ink);
      font-size: clamp(1.55rem, 4vw, 2.35rem);
      line-height: 1.1;
      letter-spacing: .5px;
      margin: 0 0 .45rem;
    }

    .ks-team-hub-subtitle,
    .ks-tourney-admin-subtitle {
      color: var(--ks-ink-3);
      font-size: .9rem;
      line-height: 1.6;
      max-width: 720px;
    }

    .ks-team-hub-grid {
      display: grid;
      /* The tournaments are the page, so they take the width; the member's own
         cards are a rail. Near-equal columns left the featured event cramped on
         the left while one collapsed row floated over a plain of canvas on the
         right. */
      grid-template-columns: minmax(0, 1.5fr) minmax(300px, .9fr);
      gap: clamp(1rem, 2vw, 1.5rem);
      align-items: start;
    }

    .ks-team-hub-card,
    .ks-tourney-admin-card {
      background: var(--ks-surface);
      border: 1px solid var(--ks-line);
      border-radius: 18px;
      box-shadow: var(--ks-shadow-2);
      overflow: hidden;
    }

    .ks-team-hub-card-pad,
    .ks-tourney-admin-card-pad {
      padding: 1rem;
    }

    .ks-team-hub-next {
      border-top: 4px solid var(--ks-accent);
    }

    .ks-team-hub-card-head,
    .ks-tourney-admin-card-head {
      display: flex;
      justify-content: space-between;
      gap: .75rem;
      align-items: flex-start;
      margin-bottom: .8rem;
    }

    .ks-team-hub-card-title,
    .ks-tourney-admin-card-title {
      color: var(--ks-ink);
      font-size: 1.05rem;
      font-weight: 850;
      line-height: 1.25;
    }

    .ks-team-hub-label,
    .ks-tourney-admin-label {
      color: var(--ks-ink-3);
      font-size: .62rem;
      font-weight: 800;
      letter-spacing: 1.4px;
      text-transform: uppercase;
    }

    .ks-team-hub-countdown {
      min-width: 94px;
      padding: .55rem .65rem;
      border-radius: 14px;
      /* Was a fixed dark chip with gold on it, which inverts badly: flipping it
         through the ink pair puts the light theme's dark accent onto a
         near-black fill. An accent-tinted chip is the same language as the rest
         of the card, is distinct enough to still be the thing that shouts, and
         its foregrounds are the pairs the contrast tool already checks. */
      background: var(--ks-accent-soft);
      color: var(--ks-ink);
      text-align: center;
      border: 1px solid var(--ks-accent);
    }

    .ks-team-hub-countdown strong {
      display: block;
      color: var(--ks-accent-strong);
      font-size: 1.35rem;
      line-height: 1;
      font-family: var(--ks-display);
    }

    .ks-team-hub-countdown span {
      display: block;
      margin-top: .2rem;
      font-size: .56rem;
      font-weight: 800;
      letter-spacing: 1.3px;
      text-transform: uppercase;
    }

    .ks-team-hub-meta-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: .65rem;
      margin: .85rem 0;
    }

    .ks-team-hub-meta {
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      border-radius: 14px;
      padding: .72rem;
    }

    .ks-team-hub-meta span {
      display: block;
      color: var(--ks-ink-3);
      font-size: .58rem;
      font-weight: 800;
      letter-spacing: 1.2px;
      text-transform: uppercase;
      margin-bottom: .2rem;
    }

    .ks-team-hub-meta strong {
      color: var(--ks-ink);
      font-size: .82rem;
      line-height: 1.35;
    }

    .ks-team-hub-note {
      border-left: 3px solid var(--ks-accent);
      background: var(--ks-accent-soft);
      border-radius: 12px;
      padding: .78rem .85rem;
      color: var(--ks-ink-2);
      font-size: .82rem;
      line-height: 1.55;
      margin-top: .65rem;
    }

    /* The label sits on its own line above the text it labels. It was an inline
       <strong> immediately followed by an inline <span> with no whitespace
       between them, so every note on the hub read "Hotel InformationTeam block
       held at the Lincoln Court Hotel" -- on the block a competitor reads to
       find out where the team is staying and when it meets.

       Blocked rather than given a trailing space: this is a heading and its
       paragraph, not a sentence with a bold opening, and a space would still
       leave the two competing for one line. */
    .ks-team-hub-note strong {
      display: block;
      margin-bottom: .15rem;
      color: var(--ks-ink);
      font-weight: 800;
    }

    .ks-team-hub-actions,
    .ks-tourney-admin-actions {
      display: flex;
      flex-wrap: wrap;
      gap: .55rem;
      margin-top: .85rem;
    }

    .ks-team-hub-link,
    .ks-tourney-admin-link {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-height: 38px;
      padding: .58rem .85rem;
      border-radius: 999px;
      background: var(--ks-ink);
      color: var(--ks-surface);
      text-decoration: none;
      font-size: .68rem;
      font-weight: 850;
      letter-spacing: 1px;
      text-transform: uppercase;
      border: 1px solid var(--ks-ink);
      cursor: pointer;
    }

    .ks-team-hub-link.secondary,
    .ks-tourney-admin-link.secondary {
      background: var(--ks-surface);
      color: var(--ks-ink);
      border-color: var(--ks-line);
    }

    .ks-team-hub-list {
      display: grid;
      gap: .85rem;
    }

    /* ── Collapsed tournament rows ─────────────────────────────────────────
       Every tournament after the featured one is a <details> row: the summary
       carries name, dates, distance and the member's own answer, and the full
       card -- meta, notes, RSVP -- is behind one tap. This is what keeps the
       hub a page rather than a scroll through every detail of everything. */
    .ks-team-hub-event {
      overflow: hidden;
      transition: border-color var(--duration-base) var(--ease-out);
    }

    .ks-team-hub-event:hover,
    .ks-team-hub-event:focus-within {
      border-color: var(--ks-accent);
    }

    .ks-team-hub-event-summary {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: .75rem;
      flex-wrap: wrap;
      padding: .95rem 2.4rem .95rem 1rem;
      cursor: pointer;
      list-style: none;
      position: relative;
    }

    .ks-team-hub-event-summary::-webkit-details-marker {
      display: none;
    }

    /* The chevron says "this opens", and turning it says "this is open". */
    .ks-team-hub-event-summary::after {
      content: '›';
      position: absolute;
      right: 1rem;
      top: 50%;
      translate: 0 -50%;
      font-size: 1.15rem;
      font-weight: 700;
      color: var(--ks-ink-3);
      transition: rotate var(--duration-fast) var(--ease-out);
    }

    .ks-team-hub-event[open] > .ks-team-hub-event-summary::after {
      rotate: 90deg;
    }

    @media (prefers-reduced-motion: reduce) {
      .ks-team-hub-event-summary::after {
        transition: none;
      }
    }

    .ks-team-hub-event-summary:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: -2px;
      border-radius: 16px;
    }

    .ks-team-hub-event[open] > .ks-team-hub-event-summary {
      border-bottom: 1px solid var(--ks-line-soft);
    }

    .ks-team-hub-event-title {
      display: block;
      min-width: 0;
      flex: 1 1 12rem;
    }

    .ks-team-hub-event-title strong {
      display: block;
      color: var(--ks-ink);
      font-size: .95rem;
      font-weight: 850;
      line-height: 1.3;
    }

    .ks-team-hub-event-date {
      display: block;
      margin-top: .15rem;
      color: var(--ks-ink-3);
      font-size: .76rem;
      font-weight: 600;
    }

    .ks-team-hub-event-chips,
    .ks-team-hub-headchips {
      display: flex;
      align-items: center;
      gap: .45rem;
      flex-shrink: 0;
    }

    .ks-team-hub-headchips {
      flex-direction: column;
      align-items: flex-end;
      gap: .5rem;
    }

    .ks-team-hub-event-body {
      padding: .35rem 1rem 1rem;
    }

    /* ── The answer, as a chip ─────────────────────────────────────────────
       The same record the RSVP panel writes, readable without opening the row.
       Unset renders as an invitation rather than as a state, because "Not set"
       on a planning surface is a nag and "RSVP" is an action. */
    .ks-hub-chip {
      display: inline-flex;
      align-items: center;
      padding: .28rem .6rem;
      border-radius: 999px;
      border: 1px solid var(--ks-line);
      background: var(--ks-surface-sunken);
      color: var(--ks-ink-2);
      font-size: .6rem;
      font-weight: 800;
      letter-spacing: .08em;
      text-transform: uppercase;
      white-space: nowrap;
    }

    .ks-hub-chip-going {
      background: var(--ks-success-bg);
      border-color: var(--ks-success-line);
      color: var(--ks-success);
    }

    .ks-hub-chip-maybe {
      background: var(--ks-warning-bg);
      border-color: var(--ks-warning-line);
      color: var(--ks-warning);
    }

    .ks-hub-chip-unset {
      background: var(--ks-accent-soft);
      border-color: var(--ks-accent);
      color: var(--ks-accent-strong);
    }

    .ks-team-hub-mini-card {
      background: var(--ks-surface);
      border: 1px solid var(--ks-line);
      border-radius: 16px;
      padding: .95rem;
      box-shadow: var(--ks-shadow-1);
    }

    .ks-team-hub-empty,
    .ks-tourney-admin-empty,
    .ks-team-hub-access {
      background: var(--ks-surface);
      border: 1px dashed var(--ks-line);
      border-radius: 18px;
      padding: 1.35rem;
      color: var(--ks-ink-3);
      text-align: center;
      line-height: 1.6;
      font-size: .9rem;
    }

    .ks-tourney-admin-toolbar {
      display: flex;
      flex-wrap: wrap;
      gap: .65rem;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 1rem;
    }

    .ks-tourney-admin-controls {
      display: flex;
      flex-wrap: wrap;
      gap: .5rem;
      align-items: center;
    }

    .ks-tourney-admin-input,
    .ks-tourney-admin-select,
    .ks-tourney-admin-textarea {
      width: 100%;
      border: 1px solid var(--ks-line);
      border-radius: 12px;
      padding: .7rem .8rem;
      background: var(--ks-surface);
      color: var(--ks-ink);
      font-family: 'Raleway', sans-serif;
      font-size: .82rem;
    }

    .ks-tourney-admin-textarea {
      resize: vertical;
      min-height: 78px;
    }

    .ks-tourney-admin-form-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: .75rem;
    }

    .ks-tourney-admin-field.full {
      grid-column: 1 / -1;
    }

    /* The flyer field's own explanation: what is accepted, and — when the
       tournament is being kept private — why the control is closed. It reads
       as guidance, not as a second label competing with the one above it. */
    .ks-tourney-admin-hint {
      margin: .35rem 0 0;
      font-size: .68rem;
      line-height: 1.45;
      color: var(--ks-ink-3);
    }

    .ks-tourney-admin-field input[type="file"] {
      width: 100%;
      color: var(--ks-ink-2);
      font-size: .75rem;
    }

    .ks-tourney-admin-field input[type="file"]:disabled {
      opacity: .55;
      cursor: not-allowed;
    }

    .ks-tourney-admin-field label {
      display: block;
      color: var(--ks-ink-2);
      font-size: .6rem;
      font-weight: 850;
      letter-spacing: 1.2px;
      text-transform: uppercase;
      margin-bottom: .28rem;
    }

    .ks-tourney-admin-list {
      display: grid;
      gap: .85rem;
      margin-top: 1rem;
    }

    .ks-tourney-admin-event {
      background: var(--ks-surface);
      border: 1px solid var(--ks-line);
      border-radius: 18px;
      padding: 1rem;
      box-shadow: var(--ks-shadow-1);
    }

    .ks-tourney-admin-event.archived {
      opacity: .72;
    }

    .ks-rsvp-chip-row {
      display: flex;
      flex-wrap: wrap;
      gap: .4rem;
      margin: .7rem 0;
    }

    .ks-rsvp-chip {
      display: inline-flex;
      align-items: center;
      gap: .25rem;
      border-radius: 999px;
      padding: .32rem .55rem;
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      color: var(--ks-ink-2);
      font-size: .66rem;
      font-weight: 850;
    }

    .ks-rsvp-chip-button {
      cursor: pointer;
      font-family: 'Raleway', sans-serif;
      transition: border-color .15s ease, background .15s ease, color .15s ease, transform .08s ease;
    }

    .ks-rsvp-chip-button:hover,
    .ks-rsvp-chip-button.active {
      border-color: var(--ks-accent);
      background: var(--ks-accent-soft);
      color: var(--ks-accent-strong);
    }

    .ks-rsvp-chip-button:active {
      transform: scale(.98);
    }

    .ks-rsvp-list {
      border-top: 1px solid var(--ks-line);
      margin-top: .75rem;
      padding-top: .75rem;
      display: grid;
      gap: .45rem;
    }

    .ks-rsvp-list-row {
      display: flex;
      justify-content: space-between;
      gap: .65rem;
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      border-radius: 12px;
      padding: .55rem .65rem;
      color: var(--ks-ink-2);
      font-size: .74rem;
    }

    .ks-tourney-admin-status {
      min-height: 1.2rem;
      color: var(--ks-ink-3);
      font-size: .72rem;
      margin-top: .55rem;
    }

    @media (max-width: 820px) {

      .ks-team-hub-grid,
      .ks-tourney-admin-form-grid {
        grid-template-columns: 1fr;
      }

      .ks-team-hub-meta-grid {
        grid-template-columns: 1fr;
      }

      .ks-rsvp-buttons {
        grid-template-columns: 1fr;
      }
    }

    /* ── A member's own answers ──────────────────────────────────────────────
       One row per event they have replied to. The answer is a chip so it reads
       the same as the counts on the card above it, and it is tinted by status
       so "Going" and "Not Going" are not the same glance -- with the word still
       there, because colour alone would leave the distinction unreadable to
       anyone who cannot separate the two hues. */
    .ks-my-event-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: .75rem;
      padding: .6rem 0;
      border-bottom: 1px solid var(--ks-line-soft);
    }

    .ks-my-event-row:last-child {
      border-bottom: 0;
      padding-bottom: 0;
    }

    .ks-my-event-copy {
      min-width: 0;
    }

    .ks-my-event-name {
      font-weight: 800;
      color: var(--ks-ink);
      font-size: .82rem;
      /* Event names are free text, so a long one wraps rather than pushing the
         status chip off the side of the card. */
      overflow-wrap: anywhere;
    }

    .ks-my-event-date {
      color: var(--ks-ink-3);
      font-size: .72rem;
      margin-top: .1rem;
    }

    .ks-my-event-status {
      flex: 0 0 auto;
    }

    .ks-my-event-status[data-rsvp-status="going"] {
      background: var(--ks-success-bg);
      border-color: var(--ks-success-line);
      color: var(--ks-success);
    }

    .ks-my-event-status[data-rsvp-status="maybe"] {
      background: var(--ks-warning-bg);
      border-color: var(--ks-warning-line);
      color: var(--ks-warning);
    }

    .ks-my-event-status[data-rsvp-status="notGoing"] {
      background: var(--ks-danger-bg);
      border-color: var(--ks-danger-line);
      color: var(--ks-danger);
    }

    /* ── The one RSVP control ────────────────────────────────────────────────
       Four panels used to draw this capability four ways; ksRenderRsvpControl
       draws it once. The pressed segment IS the member's answer — no separate
       "Your RSVP:" line restating it — and the optional note lives behind a
       quiet disclosure instead of an always-open textarea. Tenant tokens
       throughout; the writers behind the buttons are unchanged. */
    .ks-rsvp-control {
      display: flex;
      flex-direction: column;
      gap: .55rem;
    }

    .ks-rsvp-control-row {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: .5rem .8rem;
    }

    .ks-rsvp-control-label {
      font-size: .85rem;
      font-weight: 700;
      color: var(--ks-ink-2);
    }

    .ks-rsvp-seggroup {
      display: inline-flex;
      gap: 2px;
      padding: 3px;
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      border-radius: var(--radius-full);
    }

    .ks-rsvp-seg {
      min-height: 34px;
      padding: .3rem .9rem;
      border: 0;
      border-radius: var(--radius-full);
      background: transparent;
      color: var(--ks-ink-2);
      font-size: .8rem;
      font-weight: 700;
      cursor: pointer;
      transition:
        background var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
    }

    .ks-rsvp-seg:hover {
      color: var(--ks-ink);
    }

    .ks-rsvp-seg.is-on {
      background: var(--ks-accent);
      color: var(--ks-on-accent);
    }

    .ks-rsvp-seg:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: 2px;
    }

    .ks-rsvp-note-toggle {
      border: 0;
      background: none;
      color: var(--ks-accent-strong);
      font-size: .8rem;
      font-weight: 600;
      cursor: pointer;
      padding: .25rem .2rem;
    }

    .ks-rsvp-note-toggle:hover,
    .ks-rsvp-note-toggle:focus-visible {
      text-decoration: underline;
    }

    .ks-rsvp-note-toggle:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: 2px;
      border-radius: var(--radius-sm);
    }

    .ks-rsvp-note-field {
      width: 100%;
      min-height: 56px;
      border: 1px solid var(--ks-line);
      border-radius: var(--radius-md);
      padding: .6rem .75rem;
      font-size: .85rem;
      font-family: inherit;
      color: var(--ks-ink);
      background: var(--ks-surface);
    }

    .ks-rsvp-note-field:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: 1px;
      border-color: var(--ks-accent);
    }

    .ks-rsvp-note-field[hidden] {
      display: none;
    }

    /* Phones get the group full-width with equal thirds — three honest
       touch targets instead of three small pills. */
    @media (max-width: 480px) {
      .ks-rsvp-seggroup {
        display: flex;
        width: 100%;
      }

      .ks-rsvp-seg {
        flex: 1;
        text-align: center;
        padding: .3rem .4rem;
      }
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-competitor-tournament-results.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ══════════════════════════════════════════════════════════════════════════
       COMPETITOR TOURNAMENT RESULTS — placements and the medals derived from them.

       Medal colour is carried on data-medal so the same attribute drives the
       summary chips and the rows, and so a placement outside the podium simply
       has no attribute rather than a fourth colour meaning "not a medal".
       Every one of these also states its placement in words, because a medal
       told only by hue is not told to everyone.
       ══════════════════════════════════════════════════════════════════════════ */

    .ks-result-list {
      display: flex;
      flex-direction: column;
      gap: .5rem;
      margin: .75rem 0;
    }

    .ks-result-row {
      display: flex;
      align-items: center;
      gap: .75rem;
      padding: .7rem .85rem;
      background: var(--ks-surface);
      border: 1px solid var(--ks-line);
      border-radius: var(--radius-md);
    }

    .ks-result-place {
      flex: 0 0 auto;
      min-width: 3rem;
      text-align: center;
      padding: .3rem .5rem;
      border-radius: var(--radius-full);
      background: var(--ks-surface-sunken);
      border: 1px solid var(--ks-line);
      color: var(--ks-ink-2);
      font-weight: 850;
      font-size: .72rem;
      letter-spacing: .04em;
    }

    .ks-result-copy {
      flex: 1 1 auto;
      min-width: 0;
    }

    .ks-result-name {
      font-weight: 800;
      color: var(--ks-ink);
      font-size: .86rem;
      /* Tournament names are free text, so a long one wraps instead of pushing
         the Remove control off the row. */
      overflow-wrap: anywhere;
    }

    .ks-result-meta {
      color: var(--ks-ink-3);
      font-size: .72rem;
      margin-top: .1rem;
    }

    .ks-result-remove {
      flex: 0 0 auto;
      background: transparent;
      border: 1px solid var(--ks-line);
      border-radius: var(--radius-full);
      color: var(--ks-ink-3);
      font-size: .64rem;
      font-weight: 800;
      letter-spacing: .06em;
      text-transform: uppercase;
      padding: .35rem .7rem;
      cursor: pointer;
    }

    .ks-result-remove:hover {
      border-color: var(--ks-danger);
      color: var(--ks-danger);
    }

    .ks-result-remove:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: 2px;
    }

    /* ── Podium ─────────────────────────────────────────────────────────────── */
    .ks-result-row[data-medal="1"] .ks-result-place,
    .ks-result-chip[data-medal="1"] {
      background: var(--ks-medal-1-bg);
      border-color: var(--ks-medal-1-line);
      color: var(--ks-medal-1-ink);
    }

    .ks-result-row[data-medal="2"] .ks-result-place,
    .ks-result-chip[data-medal="2"] {
      background: var(--ks-medal-2-bg);
      border-color: var(--ks-medal-2-line);
      color: var(--ks-medal-2-ink);
    }

    .ks-result-row[data-medal="3"] .ks-result-place,
    .ks-result-chip[data-medal="3"] {
      background: var(--ks-medal-3-bg);
      border-color: var(--ks-medal-3-line);
      color: var(--ks-medal-3-ink);
    }

    .ks-result-empty {
      color: var(--ks-ink-3);
      font-size: .82rem;
      padding: .75rem 0;
    }

    /* ── The coach's recording form ─────────────────────────────────────────── */
    .ks-result-form {
      margin-top: 1rem;
      padding-top: 1rem;
      border-top: 1px solid var(--ks-line-soft);
    }

    .ks-result-form-title {
      font-size: .62rem;
      font-weight: 800;
      letter-spacing: .12em;
      text-transform: uppercase;
      color: var(--ks-ink-3);
      margin-bottom: .6rem;
    }

    .ks-result-form-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: .55rem;
      margin-bottom: .7rem;
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-competitor-rank-profile.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ══════════════════════════════════════════════════════════════════════════
       RANK — the belt a competitor holds, and how they got it.

       This panel shipped with NO stylesheet at all, which is why it read as one
       run-on line: "Yellowsince 2026-08-08Rung 2 of 12 · next: Yellow Stripe".
       Every part of it is a <span>, and inline elements with no rule between
       them have no space between them. The information was all present and none
       of it was legible.

       The layout is deliberately a two-line header and a real list, because the
       panel answers two different questions and a reader is usually asking only
       one: what belt is this person NOW (the header), and how did they get there
       (the history). Squashing both into a paragraph made the current rank —
       the thing almost everyone came for — the hardest part to find.

       Filed under `profile` so the consolidator puts it in the components
       bundle beside the athlete timeline and the rest of the profile sections.
       ══════════════════════════════════════════════════════════════════════════ */

    .ks-rank-title {
      margin-top: 1.25rem;
    }

    /* ── the current rank ──────────────────────────────────────────────────── */

    .ks-rank-current {
      display: flex;
      flex-direction: column;
      gap: .2rem;
      margin: .35rem 0 1rem;
    }

    /* The belt itself, sized like an answer rather than like a label. */
    .ks-rank-current-label {
      font-size: 1.35rem;
      font-weight: 700;
      line-height: 1.2;
      color: var(--ks-text-strong, #0f172a);
      letter-spacing: -0.01em;
    }

    .ks-rank-since,
    .ks-rank-standing,
    .ks-rank-renamed {
      font-size: .82rem;
      line-height: 1.45;
    }

    /* The dojo has re-worded this rung since the award. Set apart because it is
       a caveat about the record, not another fact about the person. */
    .ks-rank-renamed {
      font-style: italic;
    }

    /* ── the history ───────────────────────────────────────────────────────── */

    .ks-rank-history {
      list-style: none;
      margin: 0 0 1rem;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: .4rem;
    }

    /* A row is a grading. Belt and date sit together at the front because that
       pairing IS the record — "Yellow, 8 Aug 2026" — and everything after it is
       supporting detail. Wraps rather than truncates: an examiner's name and a
       note are the coach's own words and are not this panel's to cut off. */
    .ks-rank-row {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: .5rem .75rem;
      padding: .55rem .7rem;
      border: 1px solid var(--ks-line, #E2E8F0);
      border-radius: 10px;
      background: var(--ks-surface, #fff);
    }

    .ks-rank-row-rank {
      font-weight: 700;
      font-size: .98rem;
      color: var(--ks-text-strong, #0f172a);
    }

    .ks-rank-row-date {
      font-size: .84rem;
      /* Never squeezed onto a second line away from its own belt: a date that
         wraps away from the rank it belongs to can read as the next row's. */
      white-space: nowrap;
    }

    .ks-rank-row-by,
    .ks-rank-row-note {
      font-size: .82rem;
    }

    /* The note is the coach's sentence, so it takes the remaining width and
       drops to its own line rather than fighting the fixed facts for space. */
    .ks-rank-row-note {
      flex: 1 1 100%;
    }

    /* ── a voided grading ──────────────────────────────────────────────────── */

    /* RETRACTED, NOT REMOVED, and it has to LOOK retracted at a glance while
       staying readable. A dojo keeps the record of what it corrected —
       firestore.rules refuses to delete a promotion for exactly that reason —
       so this is muted and marked rather than hidden. Not line-through on the
       whole row: the date and the examiner are still true, and striking them
       says they were not. */
    .ks-rank-row-voided {
      background: var(--ks-surface-muted, #F8FAFC);
      border-style: dashed;
    }

    .ks-rank-row-voided .ks-rank-row-rank {
      text-decoration: line-through;
      text-decoration-thickness: 1px;
      color: var(--ks-text-muted, #64748B);
      font-weight: 600;
    }

    .ks-rank-row-void {
      font-size: .78rem;
      font-weight: 600;
      color: var(--ks-text-muted, #64748B);
      flex: 1 1 100%;
    }

    /* ── recording a grading ───────────────────────────────────────────────── */

    .ks-rank-form {
      display: flex;
      flex-direction: column;
      gap: .5rem;
      padding: .85rem;
      border: 1px solid var(--ks-line, #E2E8F0);
      border-radius: 12px;
      background: var(--ks-surface-muted, #F8FAFC);
      margin-bottom: .5rem;
    }

    /* Current rank and next rung, stated above the choice. These are facts the
       coach is being reminded of, not a proposal — the selector deliberately
       preselects nothing, because a backdated grading legitimately needs a
       lower rung than the one they hold. */
    .ks-rank-form-context {
      margin: 0 0 .15rem;
      font-size: .84rem;
      font-weight: 600;
    }

    /* What voiding IS, said where the button is, because "Void" alone is a word
       from an audit system and not from a dojo. */
    .ks-rank-form-help,
    .ks-rank-void-help {
      margin: 0;
      font-size: .8rem;
      line-height: 1.5;
    }

    .ks-rank-void-help {
      margin: -.35rem 0 .75rem;
    }

    .ks-rank-form .fi-inp {
      width: 100%;
    }

    .ks-rank-status:empty {
      display: none;
    }

    .ks-rank-status {
      margin: .35rem 0 0;
      font-size: .84rem;
    }

    .ks-rank-no-ladder {
      margin: .25rem 0 .75rem;
      font-size: .86rem;
      line-height: 1.5;
    }

    @media (max-width: 640px) {
      .ks-rank-row {
        gap: .35rem .6rem;
      }
      .ks-rank-current-label {
        font-size: 1.2rem;
      }
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-home-tournament-action-card.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ══ NEXT TOURNAMENT — the public band ══════════════════════════════════
       The homepage's team-wide answer to "when do we compete next?", drawn
       from the same public records as the calendar. One band, tenant-token
       painted: the dojo's own band colours carry it, the accent marks the
       countdown. Nothing personal lives here — answers belong to the Team
       Hub. Absent (not empty) when nothing is upcoming.
       ═══════════════════════════════════════════════════════════════════════ */
    .ks-home-tourney-card-wrap {
      margin-bottom: clamp(1rem, 2vw, 1.25rem);
    }

    .ks-home-tourney-card-card {
      position: relative;
      overflow: hidden;
      border-radius: var(--radius-lg);
      border: 1px solid color-mix(in oklab, var(--ks-band-deep) 80%, transparent);
      background:
        radial-gradient(120% 140% at 85% 0%, color-mix(in oklab, var(--accent) 14%, transparent) 0%, transparent 55%),
        linear-gradient(120deg, var(--ks-band-deep) 0%, var(--ks-band) 70%);
      color: var(--ks-band-ink);
      padding: clamp(1.1rem, 2.5vw, 1.5rem) clamp(1.2rem, 2.5vw, 1.75rem);
      box-shadow: var(--ks-shadow-2);
    }

    .ks-home-tourney-card-head {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 1rem;
      margin-bottom: .45rem;
    }

    .ks-home-tourney-card-kicker {
      font-size: .72rem;
      font-weight: 800;
      letter-spacing: .12em;
      text-transform: uppercase;
      color: var(--ks-band-accent, var(--ks-accent));
    }

    /* The countdown is the band's one loud element. */
    .ks-home-tourney-card-days {
      font-size: .78rem;
      font-weight: 800;
      padding: .3rem .75rem;
      border-radius: var(--radius-full);
      background: var(--ks-accent);
      color: var(--ks-on-accent);
      white-space: nowrap;
    }

    .ks-home-tourney-card-title {
      margin: 0 0 .55rem;
      font-family: var(--ks-display);
      font-size: clamp(1.35rem, 1.1rem + 1.6vw, 1.9rem);
      font-weight: 700;
      line-height: 1.15;
      letter-spacing: -.005em;
      color: var(--ks-band-ink);
      text-wrap: balance;
    }

    .ks-home-tourney-card-meta {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: .35rem 1.1rem;
      font-size: .92rem;
      font-weight: 500;
      color: var(--ks-band-ink-2);
    }

    .ks-home-tourney-card-deadline {
      font-weight: 700;
      color: var(--ks-band-ink);
    }

    .ks-home-tourney-card-actions {
      margin-top: .9rem;
    }

    .ks-home-tourney-card-link {
      display: inline-flex;
      align-items: center;
      gap: .35rem;
      padding: .5rem 1rem;
      background: color-mix(in oklab, var(--ks-band-ink) 10%, transparent);
      border: 1px solid color-mix(in oklab, var(--ks-band-ink) 28%, transparent);
      border-radius: var(--radius-full);
      color: var(--ks-band-ink);
      font-size: .82rem;
      font-weight: 700;
      cursor: pointer;
      transition:
        background var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
    }

    .ks-home-tourney-card-link:hover {
      background: color-mix(in oklab, var(--ks-band-ink) 18%, transparent);
      border-color: color-mix(in oklab, var(--ks-band-ink) 45%, transparent);
    }

    .ks-home-tourney-card-link:focus-visible {
      outline: 2px solid var(--ks-focus-ring);
      outline-offset: 2px;
    }

    @media (max-width: 640px) {
      .ks-home-tourney-card-head {
        flex-wrap: wrap;
        gap: .4rem .75rem;
      }
    }


/* ══════════════════════════════════════════════════════════════════════
   dojo-videos-add-tournament-button.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* This file styled #btn-add-tournament into the old gold system with
       !important, which now fights the shared button component and left the same
       action -- add a record to this page -- looking one way on the Match Library
       and another on Team. The button carries .ks-btn .ks-btn-ghost like every
       other secondary action, so the override is gone rather than reproduced.

       Kept as a file, not deleted, because 166 link tags reference these by name
       and a 404 for each visitor is a worse trade than an empty stylesheet. */


/* ══════════════════════════════════════════════════════════════════════
   dojo-videos-reduced-motion.v1.css
   ══════════════════════════════════════════════════════════════════════ */
    /* ─── REDUCED MOTION ────────────────────────────────────────── */
    @media (prefers-reduced-motion: reduce) {
      #view-tournaments #tournaments-grid .fcard {
        transition: none !important;
      }

      #view-tournaments #tournaments-grid .fcard-foot .btn-gold {
        transition: none !important;
      }
    }



/* ══════════════════════════════════════════════════════════════════════
   ks-contact-form.v1.css
   ══════════════════════════════════════════════════════════════════════ */
/* ── The dojo contact form ─────────────────────────────────────────────────────
 * ks-contact-form.v1.js builds this form and emits six classes. The repository
 * had CSS for none of them, so it has been rendering with raw browser defaults
 * on every tenant's footer: 2px inset borders, no padding, 149px inputs, labels
 * running inline against their fields. It is the one unfinished-looking thing on
 * an otherwise finished page, and it sits at the bottom of every dojo site.
 *
 * Styled here rather than inside a page shell because the component is shared:
 * any surface that renders [data-ks-contact-form] gets the same form, and a
 * second tenant should not have to rediscover this.
 *
 * The form lives on the footer's dark band, so every colour is drawn from the
 * inverse side of the token system -- and the accent arrives through
 * --accent-on-inverse, whose lightness floor is what keeps a dojo's own colour
 * readable there whatever they chose.
 *
 * ONE TRAP, MEASURED. --ks-success and --ks-danger are scoped to
 * :root[data-theme="dark"], i.e. to a dark PAGE. This band is dark on a LIGHT
 * page, so in the default theme they resolve to their light-surface values:
 * #12784A reads 3.23:1 here and #B42318 3.05:1. Neither clears 4.5:1, and the
 * two lines they would colour are the ones that tell somebody whether their
 * message actually sent. So the band declares its own inverse-side pair below,
 * reusing the exact values the platform already chose for these hues on navy.
 * ────────────────────────────────────────────────────────────────────────── */

.ks-contact-form {
  /* Every colour below reads these three. The form is a shared component that
     happens to mount in the footer today; a surface that mounts it anywhere
     else overrides these and the rest of the file follows, with no literal
     white left behind to contradict it. */
  --ks-cf-ink: var(--ink-inverse);
  --ks-cf-accent: var(--accent-on-inverse);
  --ks-cf-field: color-mix(in oklab, var(--ks-cf-ink) 6%, transparent);
  /* The inverse-side pair the theme file already settled on for a navy
     surface -- lifted here because this band is dark whatever the page theme
     is. 9.9:1 and 8.0:1 measured against #0C1730. */
  --ks-cf-sent: #5BD98A;
  --ks-cf-error: #FF8A80;

  display: grid;
  gap: .85rem;
  max-width: 30rem;
  /* The mount is a bare div with no margin of its own, so without this the
     heading butts straight onto whatever precedes it -- in the footer, the last
     line of the dojo's own description, at a measured 0px. A form is a change of
     subject and should read as one. */
  margin: 1.25rem 0 1rem;
}

.ks-contact-heading {
  font-family: var(--ks-display);
  font-size: .8rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ks-cf-accent);
  margin: 0;
}

.ks-contact-field {
  display: grid;
  gap: .3rem;
}

.ks-contact-label {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: color-mix(in oklab, var(--ks-cf-ink) 72%, transparent);
}

/* Scoped to .ks-contact-field, not to `input`, because the form also carries a
   honeypot: an off-screen input the component hides with an inline
   height:1px. A stylesheet min-height beats an inline height, so styling every
   input would quietly inflate the one field that is supposed to have no size.
   Real fields are the ones the component wrapped in a label.

   Typed by hand on a phone more often than not, so the target is generous and
   the text is 16px: iOS zooms the whole page when a focused field is smaller,
   which throws the reader out of the layout mid-sentence. */
.ks-contact-field input,
.ks-contact-field textarea {
  width: 100%;
  min-height: 44px;
  padding: .6rem .75rem;
  font: inherit;
  font-size: 16px;
  line-height: 1.4;
  color: var(--ks-cf-ink);
  background: var(--ks-cf-field);
  /* 38%, not the 18% that looks tidiest. The border is the only thing that says
     "a field is here" -- the fill sits just 1.13:1 off the band -- so it is held
     to WCAG 1.4.11's 3:1 for non-text. 18% measured 1.64:1; this measures
     3.50:1, and still reads as a hairline rather than a box. */
  border: 1px solid color-mix(in oklab, var(--ks-cf-ink) 38%, transparent);
  border-radius: var(--ks-r-control);
  transition: border-color .15s ease, background-color .15s ease;
}

.ks-contact-field textarea {
  min-height: 7.5rem;
  resize: vertical;
}

.ks-contact-field input:hover,
.ks-contact-field textarea:hover {
  border-color: color-mix(in oklab, var(--ks-cf-ink) 55%, transparent);
}

.ks-contact-field input:focus-visible,
.ks-contact-field textarea:focus-visible {
  outline: 3px solid var(--ks-cf-accent);
  outline-offset: 2px;
  border-color: var(--ks-cf-accent);
  background: color-mix(in oklab, var(--ks-cf-ink) 10%, transparent);
}

.ks-contact-submit {
  justify-self: start;
  min-height: 44px;
}

.ks-contact-submit[disabled] {
  opacity: .6;
  cursor: not-allowed;
}

/* The status line is a live region, so it must not move the layout when it
   fills -- a reader using a screen reader hears it, and a sighted reader should
   not have the button jump out from under their finger as it appears. It holds
   its line from the start. */
.ks-contact-status {
  margin: 0;
  min-height: 1.25rem;
  font-size: .78rem;
  line-height: 1.25rem;
  color: color-mix(in oklab, var(--ks-cf-ink) 62%, transparent);
}

/* Never colour alone: each state carries a mark, so the difference between
   "sent" and "that did not work" survives a reader who cannot use hue. */
.ks-contact-status[data-state="sending"]::before { content: "… "; }
.ks-contact-status[data-state="sent"]::before { content: "✓ "; }
.ks-contact-status[data-state="error"]::before { content: "! "; }

.ks-contact-status[data-state="sent"] {
  color: var(--ks-cf-sent);
}

.ks-contact-status[data-state="error"] {
  color: var(--ks-cf-error);
}

@media (prefers-reduced-motion: reduce) {

  .ks-contact-field input,
  .ks-contact-field textarea {
    transition: none;
  }
}


/* ══════════════════════════════════════════════════════════════════════
   ks-search-palette.v1.css
   ══════════════════════════════════════════════════════════════════════ */
/* ── Search palette ───────────────────────────────────────────────────────────
 * The Cmd/Ctrl-K command surface. One overlay, one input, one listbox —
 * tokens only, readable on the tenant canvas and above the dark shell alike.
 * ─────────────────────────────────────────────────────────────────────────── */

.ks-search-overlay {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(3rem, 14vh, 9rem) 1rem 2rem;
  background: rgba(7, 12, 24, .55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.ks-search-overlay[hidden] { display: none; }

.ks-search-panel {
  width: min(37rem, 100%);
  border-radius: var(--ks-r-lg);
  background: var(--ks-white);
  box-shadow: var(--ks-e3);
  overflow: hidden;
}

.ks-search-inputwrap {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .35rem .9rem;
  border-bottom: 1px solid var(--ks-n-100);
}

.ks-search-inputwrap svg {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--ks-n-400);
}

#ks-search-input {
  flex: 1;
  min-width: 0;
  padding: .7rem 0;
  border: 0;
  outline: none;
  font: inherit;
  font-size: .98rem;
  color: var(--ks-n-900);
  background: none;
}

#ks-search-input::placeholder { color: var(--ks-n-400); }

.ks-search-hint {
  flex: none;
  padding: .15rem .45rem;
  border-radius: var(--ks-r-xs);
  border: 1px solid var(--ks-n-200);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--ks-n-500);
}

#ks-search-results {
  margin: 0;
  padding: .4rem;
  list-style: none;
  max-height: min(48vh, 22rem);
  overflow-y: auto;
}

.ks-search-option {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  padding: .55rem .7rem;
  border-radius: var(--ks-r-sm);
  cursor: pointer;
}

.ks-search-option.is-active { background: var(--ks-n-100); }

.ks-search-option-label {
  font-size: .9rem;
  font-weight: 600;
  color: var(--ks-n-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ks-search-option-sub {
  flex: 1;
  min-width: 0;
  font-size: .76rem;
  color: var(--ks-n-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ks-search-option-kind {
  flex: none;
  font-size: .62rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ks-n-400);
}

.ks-search-empty {
  padding: 1.1rem .7rem;
  font-size: .86rem;
  color: var(--ks-n-500);
}

@media (max-width: 700px) {
  .ks-search-overlay { padding-top: 1.2rem; }
}
