/* gameon.css
 *
 * Project stylesheet for GameOn. Linked from templates/baseCrispy.html, so it
 * loads on every page that extends baseCrispy.html (currently 133 templates).
 *
 * It loads after the vendored Bootstrap 4.0.0 and before {% block stylesheet %},
 * so rules here override Bootstrap, and a page's own {% block stylesheet %}
 * still overrides rules here.
 *
 * Not to be confused with app.css, which is linked from base.html, base_new.html,
 * base_Emails.html and "base with BS Datepicker.html" only.
 *
 * Contents: the load-check marker, then the Inter typeface, then the sticky
 * footer rules, then the frozen-first-column rules for the Inq results tables.
 * Contents: the load-check marker, then the design tokens, then the sticky
 * footer rules, then the frozen-first-column rules for the Inq results tables,
 * then the phone-only filter sheet used by the Inq search screens.
 */

:root {
  /* No visual effect. A custom property is inert unless something references
     it, so this renders nothing. It exists as a load check: in the console,
     getComputedStyle(document.documentElement).getPropertyValue('--gameon-css')
     returns 'loaded' only if this file was fetched AND accepted as CSS. */
  --gameon-css: loaded;
}

/* ==================================================================
   Design tokens
   ==================================================================

   Declarations only. Nothing in the codebase references any property in this
   block, and a custom property is inert until something does, so adding it
   changes no pixel on any page. This is deliberate: the tokens land in one
   reviewable change, and the rules that consume them land in a later one.

   The intent is to apply them to headings and buttons first. Headings are the
   obvious starting point, since 248 of the 373 in templates/ carry a non-empty
   inline style and 243 of those are the same declaration, color:blue.

   Naming follows the --gameon- prefix already used by the load check above and
   by the Referee's Corner work, so everything this project adds sits in one
   namespace and greps as one word.

   Ramps run 50 (lightest) to 950 (darkest), the convention Tailwind and the
   Bootstrap 5 palettes use. The semantic roles below point at ramp steps rather
   than repeating hex values, so a palette change is edited in one place. */

:root {

  /* ---- Typeface ---------------------------------------------------
     Inter is already self-hosted and applied by the typeface section
     below. These record the stacks so future rules do not restate them. */
  --gameon-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --gameon-font-mono: 'SFMono-Regular', ui-monospace, Menlo, Consolas, monospace;

  /* ---- Weights ----------------------------------------------------
     Inter ships in three weights here: 400, 600 and 700. Medium 500 is
     listed for completeness and will synthesise unless a file is added. */
  --gameon-weight-regular: 400;
  --gameon-weight-medium: 500;
  --gameon-weight-semibold: 600;
  --gameon-weight-bold: 700;

  /* ---- Type scale -------------------------------------------------
     Each step carries its size, its line height and its tracking.
     Tracking tightens as size grows, which is how Inter is designed to
     be set. Bootstrap 4.0.0 body text is 1rem, which is the md step. */
  --gameon-text-2xs-size: .6875rem;
  --gameon-text-2xs-height: 1rem;
  --gameon-text-2xs-tracking: .01em;

  --gameon-text-xs-size: .75rem;
  --gameon-text-xs-height: 1.125rem;
  --gameon-text-xs-tracking: .005em;

  --gameon-text-sm-size: .8125rem;
  --gameon-text-sm-height: 1.25rem;
  --gameon-text-sm-tracking: .003em;

  --gameon-text-base-size: .875rem;
  --gameon-text-base-height: 1.375rem;
  --gameon-text-base-tracking: 0;

  --gameon-text-md-size: 1rem;
  --gameon-text-md-height: 1.5rem;
  --gameon-text-md-tracking: 0;

  --gameon-text-lg-size: 1.125rem;
  --gameon-text-lg-height: 1.625rem;
  --gameon-text-lg-tracking: -.006em;

  --gameon-text-xl-size: 1.25rem;
  --gameon-text-xl-height: 1.75rem;
  --gameon-text-xl-tracking: -.011em;

  --gameon-text-2xl-size: 1.5rem;
  --gameon-text-2xl-height: 2rem;
  --gameon-text-2xl-tracking: -.017em;

  --gameon-text-3xl-size: 1.875rem;
  --gameon-text-3xl-height: 2.375rem;
  --gameon-text-3xl-tracking: -.021em;

  --gameon-text-4xl-size: 2.25rem;
  --gameon-text-4xl-height: 2.75rem;
  --gameon-text-4xl-tracking: -.024em;

  /* ---- Line height ------------------------------------------------
     Unitless, for cases that set a line height independently of the
     type scale above. Bootstrap 4.0.0 body is 1.5, headings are 1.2. */
  --gameon-leading-none: 1;
  --gameon-leading-tight: 1.2;
  --gameon-leading-snug: 1.35;
  --gameon-leading-normal: 1.5;
  --gameon-leading-relaxed: 1.65;

  /* ---- Cool gray --------------------------------------------------
     Slightly blue tinted rather than neutral, so it sits with the blue
     ramp below instead of reading as a separate greenish gray. */
  --gameon-gray-50: #f7f9fc;
  --gameon-gray-100: #eef2f8;
  --gameon-gray-200: #e2e8f1;
  --gameon-gray-300: #cbd4e1;
  --gameon-gray-400: #94a1b8;
  --gameon-gray-500: #64748b;
  --gameon-gray-600: #4a5768;
  --gameon-gray-700: #334155;
  --gameon-gray-800: #1e293b;
  --gameon-gray-900: #0f172a;
  --gameon-gray-950: #080e1c;

  /* ---- Primary blue -----------------------------------------------
     Replaces the ad hoc mix of the CSS keyword blue (#0000ff) and
     Bootstrap's #007bff currently spread across the templates. */
  --gameon-blue-50: #eef4ff;
  --gameon-blue-100: #dae6ff;
  --gameon-blue-200: #bcd3ff;
  --gameon-blue-300: #8eb5ff;
  --gameon-blue-400: #598cfb;
  --gameon-blue-500: #3566f4;
  --gameon-blue-600: #1b56db;
  --gameon-blue-700: #1743b0;
  --gameon-blue-800: #183a8c;
  --gameon-blue-900: #19356f;
  --gameon-blue-950: #142244;

  /* ---- Status -----------------------------------------------------
     Four steps each: surface is a tinted background, border sits on it,
     base is the readable foreground, strong is for hover or emphasis.
     Info reuses the blue ramp rather than defining a fourth hue. */
  --gameon-success-surface: #e8f7ee;
  --gameon-success-border: #a8e0bf;
  --gameon-success-base: #12794a;
  --gameon-success-strong: #0d5c38;

  --gameon-warning-surface: #fdf4e3;
  --gameon-warning-border: #f3d69a;
  --gameon-warning-base: #8a5a06;
  --gameon-warning-strong: #6b4504;

  --gameon-danger-surface: #fdeeee;
  --gameon-danger-border: #f5bfbf;
  --gameon-danger-base: #b3261e;
  --gameon-danger-strong: #8c1d17;

  --gameon-info-surface: var(--gameon-blue-50);
  --gameon-info-border: var(--gameon-blue-200);
  --gameon-info-base: var(--gameon-blue-700);
  --gameon-info-strong: var(--gameon-blue-800);

  /* ---- Semantic roles ---------------------------------------------
     What a thing is for, not what colour it is. Rules should reference
     these, not the ramps, so the palette can be retuned in one place. */
  --gameon-surface: #fff;
  --gameon-surface-sunken: var(--gameon-gray-50);
  --gameon-surface-hover: var(--gameon-gray-100);
  --gameon-surface-active: var(--gameon-gray-200);
  --gameon-surface-inverse: var(--gameon-gray-900);

  --gameon-text-primary: var(--gameon-gray-900);
  --gameon-text-secondary: var(--gameon-gray-600);
  --gameon-text-tertiary: var(--gameon-gray-500);
  --gameon-text-disabled: var(--gameon-gray-400);
  --gameon-text-inverse: #fff;
  --gameon-text-link: var(--gameon-blue-600);
  --gameon-text-link-hover: var(--gameon-blue-700);

  --gameon-border-subtle: var(--gameon-gray-200);
  --gameon-border-default: var(--gameon-gray-300);
  --gameon-border-strong: var(--gameon-gray-400);

  /* ---- Spacing ----------------------------------------------------
     4px base, named by the pixel value so the name is the measurement.
     1px and 2px are there for hairlines and tight insets. */
  --gameon-space-1: 1px;
  --gameon-space-2: 2px;
  --gameon-space-4: 4px;
  --gameon-space-6: 6px;
  --gameon-space-8: 8px;
  --gameon-space-12: 12px;
  --gameon-space-16: 16px;
  --gameon-space-20: 20px;
  --gameon-space-24: 24px;
  --gameon-space-32: 32px;
  --gameon-space-40: 40px;
  --gameon-space-48: 48px;
  --gameon-space-64: 64px;
  --gameon-space-80: 80px;
  --gameon-space-96: 96px;

  /* ---- Radius -----------------------------------------------------
     Bootstrap 4.0.0 uses .25rem (4px) almost everywhere. These are
     deliberately a touch tighter at the small end. */
  --gameon-radius-sm: 3px;
  --gameon-radius-md: 5px;
  --gameon-radius-lg: 8px;
  --gameon-radius-xl: 12px;
  --gameon-radius-2xl: 18px;
  --gameon-radius-full: 9999px;

  /* ---- Elevation --------------------------------------------------
     Two layers each: a tight contact shadow plus a wider ambient one.
     Tinted with the darkest gray (#142244) rather than pure black, so
     shadows read as part of the palette instead of as gray wash. */
  --gameon-elevation-1: 0 1px 2px rgba(20, 34, 68, .06), 0 1px 3px rgba(20, 34, 68, .10);
  --gameon-elevation-2: 0 2px 4px rgba(20, 34, 68, .06), 0 4px 8px rgba(20, 34, 68, .10);
  --gameon-elevation-3: 0 4px 8px rgba(20, 34, 68, .06), 0 8px 16px rgba(20, 34, 68, .12);
  --gameon-elevation-4: 0 8px 16px rgba(20, 34, 68, .08), 0 16px 32px rgba(20, 34, 68, .16);
  --gameon-elevation-5: 0 16px 32px rgba(20, 34, 68, .10), 0 32px 64px rgba(20, 34, 68, .20);
  --gameon-elevation-inset: inset 0 1px 2px rgba(20, 34, 68, .12);

  /* ---- Focus ------------------------------------------------------
     A 3px ring, applied as box-shadow so it follows border-radius.
     Never remove an outline without putting one of these in its place. */
  --gameon-focus-ring: 0 0 0 3px var(--gameon-blue-200);
  --gameon-focus-ring-danger: 0 0 0 3px var(--gameon-danger-border);

  /* ---- Controls ---------------------------------------------------
     target-min is the 44px minimum touch target. It is the figure the
     mobile work keeps running into, so it is recorded rather than
     rederived each time. */
  --gameon-control-height-sm: 28px;
  --gameon-control-height-md: 36px;
  --gameon-control-height-lg: 44px;
  --gameon-control-target-min: 44px;

  /* ---- Tables -----------------------------------------------------
     figures-tabular is for font-feature-settings. Inter's digits are
     proportional by default, which makes columns of numbers ragged. */
  --gameon-table-cell-padding-y: 8px;
  --gameon-table-cell-padding-x: 12px;
  --gameon-table-row-height: 40px;
  --gameon-table-header-bg: var(--gameon-gray-50);
  --gameon-table-header-text: var(--gameon-gray-700);
  --gameon-table-border: var(--gameon-border-subtle);
  --gameon-table-stripe: var(--gameon-gray-50);
  --gameon-table-hover: var(--gameon-blue-50);
  --gameon-table-figures-tabular: 'tnum' 1;

  /* ---- Motion -----------------------------------------------------
     Durations are zeroed under prefers-reduced-motion at the end of
     this section, so any rule using them honours that setting for free. */
  --gameon-duration-instant: 80ms;
  --gameon-duration-fast: 140ms;
  --gameon-duration-base: 220ms;
  --gameon-duration-slow: 320ms;
  --gameon-ease-out: cubic-bezier(.16, 1, .3, 1);
  --gameon-ease-in: cubic-bezier(.7, 0, .84, 0);
  --gameon-ease-in-out: cubic-bezier(.65, 0, .35, 1);

  /* ---- Layering ---------------------------------------------------
     Bootstrap 4.0.0 uses 1000 to 1070 for its own components, so these
     sit below that range on purpose and do not compete with it. */
  --gameon-z-base: 0;
  --gameon-z-raised: 10;
  --gameon-z-sticky: 100;
  --gameon-z-dropdown: 200;
  --gameon-z-overlay: 300;
  --gameon-z-modal: 400;
  --gameon-z-toast: 500;
  --gameon-z-tooltip: 600;
}


/* Reduced motion. Zeroing the durations here means a rule that references
   them needs no media query of its own. Nothing references them yet, so this
   currently has no effect either. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --gameon-duration-instant: 0ms;
    --gameon-duration-fast: 0ms;
    --gameon-duration-base: 0ms;
    --gameon-duration-slow: 0ms;
  }
}


/* ==================================================================
   Typeface - Inter
   ==================================================================

   Self-hosted from static/fonts/: three weights, latin subset, woff2 only,
   about 71 KB in total. The files came from google-webfonts-helper. The paths
   below are relative to this stylesheet, which sits in static/css/, hence the
   ../fonts/.

   font-display: swap means text paints immediately in the fallback face and is
   repainted in Inter when the file arrives, rather than being invisible while
   it downloads.

   WHAT BOOTSTRAP 4.0.0 DOES WITH font-family
   ------------------------------------------
   Checked against the vendored static/css/Bootstrap4.0/bootstrap.min.css,
   which declares font-family in exactly these rules and nowhere else:

     html                              sans-serif
     body                              the system stack
     button, input, optgroup,
       select, textarea                inherit
     .h1-.h6, h1-h6                    inherit
     code, kbd, pre, samp              monospace, monospace
     code, kbd, pre, samp              the monospace stack
     .tooltip                          the system stack
     .popover                          the system stack

   Form controls, buttons and headings are already set to inherit, and .btn,
   .table, .form-control and .custom-select carry no font-family at all - so a
   single rule on body reaches all of them. Only .tooltip and .popover hardcode
   the stack and have to be named separately. The html rule is moot, since
   everything visible lives inside body, and code/kbd/pre/samp are deliberately
   left monospace.

   Bootstrap's system stack is repeated verbatim after Inter, so if the files
   fail to load or are blocked the page falls back to exactly the face it
   renders in today.

   Sizes, weights, colours, line heights and spacing are untouched. This block
   changes which typeface renders and nothing else.
   ------------------------------------------------------------------ */

@font-face {
  font-display: swap;
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  src: url('../fonts/inter-v20-latin-regular.woff2') format('woff2');
}
@font-face {
  font-display: swap;
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  src: url('../fonts/inter-v20-latin-600.woff2') format('woff2');
}
@font-face {
  font-display: swap;
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  src: url('../fonts/inter-v20-latin-700.woff2') format('woff2');
}

/* Replaces Bootstrap's own body rule. Same specificity, and gameon.css loads
   after Bootstrap, so this wins on order. Everything that inherits - which is
   everything except the two components below and the monospace elements -
   follows from here. */
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji",
               "Segoe UI Emoji", "Segoe UI Symbol";
}

/* Bootstrap hardcodes the system stack on these two rather than inheriting, so
   the body rule above cannot reach them. Neither component is used in GameOn
   today - there is no data-toggle="tooltip" or "popover" anywhere in
   templates/ - so this is here so that the first one added does not silently
   render in the old face. */
.tooltip,
.popover {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji",
               "Segoe UI Emoji", "Segoe UI Symbol";
}

/* Tabular figures in tables.
   -------------------------
   Inter's digits are proportional by default. Measured from the shipped file,
   a "1" is 0.407em wide against 0.646em for a "0", so a column of numbers does
   not line up. The "tnum" feature is present in all three weights and pads
   every digit to a common 0.648em.

   Scoped to table cells on purpose: proportional digits read better in running
   text, so this deliberately does not go on body.

   Bare td/th rather than ".table td, .table th" because several results
   listings are a plain <table> with no Bootstrap class - the Final Results
   block on Division Stats is one - and those are exactly the number columns
   this is for. The cost is that the layout tables still in the codebase get it
   too, which is harmless: they hold labels and form fields, not prose.

   font-feature-settings only overrides the features it names. Anything the
   font enables by default, such as Inter's contextual alternates, stays on. */
td,
th {
  font-feature-settings: "tnum";
}


/* ==================================================================
   Sticky footer
   ==================================================================

   Keeps the footer at the bottom of the window on short pages (the 404
   page renders one heading, and the footer used to float partway up with
   a white gap under it), while leaving it directly below the content on
   pages that scroll.

   How it works: <body> becomes a vertical flex column at least as tall as
   the window, the layout wrapper grows to fill whatever is left over, and
   the footer's automatic top margin absorbs the slack inside it. On a long
   page there is no slack, the auto margin resolves to zero, and the footer
   sits exactly where it does today.

   Scoped to "screen" on purpose. Making <body> a flex container upsets page
   breaking in print, and vh units resolve against the paper size, so a
   min-height would reserve a whole sheet. The footer carries d-print-none
   and never prints anyway, so print has nothing to gain here and something
   to lose. Templates that override {% block stylesheet %} with @page rules,
   such as Ops/gamesheet.html, are therefore untouched by this block.
   ------------------------------------------------------------------ */

@media screen {

  body {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    /* min-height rather than height. A percentage height only resolves
       against a parent with a real height, so this deliberately leaves
       html and body without one - see the note on h-100 below. */
    min-height: 100vh;
    /* Mobile browsers resolve 100vh against the tallest viewport, i.e. with
       the address bar hidden, which makes a short page scroll by roughly the
       height of the browser chrome. dvh tracks the viewport that is actually
       visible. Browsers that do not know dvh ignore this line and keep the
       vh value above. */
    min-height: 100dvh;
  }

  /* The layout wrapper in baseCrispy.html - the only element matched, since
     the containers the individual templates open are nested inside .col-12
     rather than being children of <body>. It takes up the leftover height,
     and becomes a column itself so the footer's auto margin has somewhere
     to work.

     NOTE: h-100 was removed from this element as part of this change. It was
     height: 100% !important, which never resolved because nothing above it
     had a height, so it had always been inert. It is not reinstated here:
     body has a min-height rather than a height, so a percentage height would
     still not resolve, and an !important declaration fighting flex-grow on
     this element is not something worth leaving to chance. */
  body > .container {
    -webkit-box-flex: 1;
    -ms-flex: 1 0 auto;
    flex: 1 0 auto;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
  }

  /* Absorbs the leftover space above the footer. Resolves to zero when there
     is none, which is why long pages are unaffected. */
  .gameon-footer {
    margin-top: auto;
  }
}


/* ==================================================================
   Frozen first column - Inq results tables
   ==================================================================

   Opt-in. Add "gameon-freeze-first" to the class list of a results table
   whose FIRST column identifies the row. Below 992px that column is pinned
   to the left edge while the rest of the table scrolls sideways inside its
   .table-responsive-lg wrapper, so you can always see which row you are on.

   Nothing here applies at 992px and up, which is where .table-responsive-lg
   stops scrolling. Desktop is untouched.

   The media query is "screen and" rather than bare, unlike Bootstrap's own
   .table-responsive-lg rule. Same 991.98px breakpoint, but scoped to screen
   so that sticky positioning is never applied to a printed page, where it
   has no meaning and can smear cells.
   ------------------------------------------------------------------ */

@media screen and (max-width: 991.98px) {

  /* Pin the first cell of every row - header or body.
     Recent Games has no <thead>: its <th> row is a bare <tr>, which the
     browser puts inside an implicit <tbody>, hence the tbody th selector.

     The box-shadow does the work that borders cannot. Bootstrap tables are
     border-collapse: collapse, and collapsed borders are painted by the table
     rather than by the cell, so they do not travel with a sticky cell. The
     first shadow re-draws Bootstrap's 1px row border inside the cell; the
     second is the hairline down the right edge; the third is a soft shadow
     that shows the column is pinned and that content is passing under it. */
  .gameon-freeze-first > thead > tr > th:first-child,
  .gameon-freeze-first > tbody > tr > th:first-child,
  .gameon-freeze-first > tbody > tr > td:first-child {
    position: -webkit-sticky;
    position: sticky;
    left: 0;
    z-index: 2;
    box-shadow: inset 0 1px 0 0 #dee2e6,
                1px 0 0 0 #dee2e6,
                3px 0 4px -2px rgba(0, 0, 0, .15);
    /* Backstop only. TeamName and VenueName allow 50 characters and a member
       name allows 41, any of which would otherwise leave no room to scroll.
       Real data sizes well under this, so it normally has no effect. */
    max-width: 45vw;
  }

  /* Opaque backgrounds.
     ------------------
     A sticky cell is painted over the cells sliding underneath it, so it
     cannot use Bootstrap's stripe: .table-striped sets rgba(0,0,0,.05), which
     is 5% black and therefore see-through. The values below are the flat
     equivalents of what Bootstrap composites over the white page background
     (Reboot sets body background-color: #fff):

         unstriped row   #fff                                    -> #ffffff
         striped  row    rgba(0,0,0,.05) over #fff  255 x .95    -> #f2f2f2
         hovered  row    rgba(0,0,0,.075) over #fff 255 x .925   -> #ececec

     The selectors deliberately mirror Bootstrap's own
     (.table-striped tbody tr:nth-of-type(odd)) so the odd/even phase can
     never drift out of step with the stripe underneath, including on
     Recent Games where the header row occupies the first tbody row. */

  /* Header cells. .thead-inverse does not exist in Bootstrap 4 - it was
     renamed .thead-dark - so these header rows currently render with no
     background at all, i.e. page white. If that class is ever corrected,
     this colour has to change with it, to #212529. */
  .gameon-freeze-first > thead > tr > th:first-child {
    background-color: #fff;
    /* Above the pinned body cells as well as the scrolling header cells. */
    z-index: 3;
  }

  .gameon-freeze-first > tbody > tr:nth-of-type(even) > th:first-child,
  .gameon-freeze-first > tbody > tr:nth-of-type(even) > td:first-child {
    background-color: #fff;
  }

  .gameon-freeze-first > tbody > tr:nth-of-type(odd) > th:first-child,
  .gameon-freeze-first > tbody > tr:nth-of-type(odd) > td:first-child {
    background-color: #f2f2f2;
  }

  /* .table-hover replaces the stripe rather than blending with it - both set
     background-color on the same <tr> at equal specificity - so a hovered row
     is one colour whether it is odd or even. Must stay last of the four:
     it has the same specificity as the two rules above and wins on order. */
  .gameon-freeze-first > tbody > tr:hover > th:first-child,
  .gameon-freeze-first > tbody > tr:hover > td:first-child {
    background-color: #ececec;
  }
}


/* ==================================================================
   Filter pane as a phone sheet - Inq search screens
   ==================================================================

   The problem: on a phone the two-pane Inq screens stack, so the filter
   pane sits above the results. On Division Stats that is three selects, a
   seven-option radio group and two buttons - roughly a screen and a half -
   before a single result is visible. Submitting reloads the page and lands
   you back at the top, looking at the same form, with no sign anything
   happened.

   The fix: below 992px the pane is presented as a full-screen sheet behind
   one button - close on the left, "Filters" centred, Reset on the right, the
   fields scrolling between them, and a single full-width primary button
   pinned to the bottom. From 992px up the pane renders inline in its column
   exactly as before.

   This is the REAL Bootstrap 4.0.0 modal component, opened by the plugin in
   static/js/bootstrap.min.js via data-toggle="modal". Escape, the backdrop,
   the body scroll lock and the focus handling are all Bootstrap's own; there
   is no hand-rolled overlay here and nothing below re-implements any of it.

   ONE form, ONE instance, and it never moves. Bootstrap does not relocate
   modal markup that is already attached - Modal._showElement only calls
   document.body.appendChild on a DETACHED modal, and short-circuits on any
   modal whose parentNode is an element. That matters because these forms
   carry a fixed id, data-*-url attributes and auto-generated id_* field ids
   that an AJAX cascade selects on. Nothing here duplicates or relocates
   anything, so those selectors keep binding.

   REUSING THIS on Schedule Search or Player Search
   ------------------------------------------------
   Every rule below is keyed to two classes and nothing screen-specific:

       .gameon-filter-pane   on the modal wrapper, alongside
                             "modal" and "d-lg-block"
       .gameon-filter-form   on the existing <form> tag (a class only -
                             leave its id and data-* attributes alone)

   Then wrap the form in .modal-dialog > .modal-content > .modal-body, add a
   .modal-header carrying d-lg-none, and add a d-lg-none trigger button with
   data-toggle="modal". No CSS changes are needed for either screen.

   The FormActions block is addressed as ".form-group:not([id])". Crispy gives
   every real field a wrapper id of div_id_<name>, and its formactions.html
   emits a bare <div class="form-group">, so that selector picks out the
   Reset/Submit row and nothing else. It holds for all three Inq forms.

   The 991.98px / 992px pair is the same boundary used by the frozen column
   rules above and by Bootstrap's own .table-responsive-lg, so all three
   switch together.
   ------------------------------------------------------------------ */


/* --- Below 992px: the full-screen sheet ----------------------------- */

@media screen and (max-width: 991.98px) {

  /* The sheet itself must not scroll - the field area inside it does, so the
     header and the submit bar stay put. Bootstrap's ".modal-open .modal" sets
     overflow-y: auto, hence the matching three-class selector to outrank it. */
  .gameon-filter-pane.modal,
  .modal-open .gameon-filter-pane.modal {
    overflow: hidden;
  }

  /* Edge to edge. Bootstrap gives .modal-dialog margin: .5rem, and from 576px
     up max-width: 500px with margin: 1.75rem auto - the centred-card geometry,
     which is what we are replacing.

     Height is 100% against .modal, which is position: fixed with top and
     bottom pinned to 0 and therefore has a definite height. Deliberately no
     vh units: on mobile 100vh resolves against the viewport with the address
     bar hidden, which would push the submit bar below the fold. */
  .gameon-filter-pane .modal-dialog {
    width: auto;
    max-width: none;
    margin: 0;
    height: 100%;
  }

  /* .modal-content is already display: flex / flex-direction: column in
     Bootstrap, so the header, the scrolling body and the submit bar stack
     without any extra layout here. min-height: 0 is what actually allows the
     body to shrink below its content height and scroll - without it a flex
     item's automatic minimum size keeps it at full content height. */
  .gameon-filter-pane .modal-content {
    height: 100%;
    min-height: 0;
    border: 0;
    border-radius: 0;
  }

  /* Header row: [X]  Filters  [Reset]. The two side items are given the same
     min-width so the title lands optically centred rather than centred in the
     space left over. */
  .gameon-filter-pane .modal-header {
    -ms-flex-negative: 0;
    flex-shrink: 0;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    padding: .5rem .75rem;
  }

  /* Bootstrap's ".modal-header .close" sets padding: 1rem and
     margin: -1rem -1rem -1rem auto, the auto being what normally pushes the X
     to the right. Both are replaced here. */
  .gameon-filter-pane .modal-header .close {
    min-width: 4.5rem;
    margin: 0;
    padding: .25rem .25rem;
    font-size: 1.75rem;
    line-height: 1;
    text-align: left;
    color: #212529;
    text-shadow: none;
    opacity: 1;
  }

  .gameon-filter-pane .modal-title {
    -webkit-box-flex: 1;
    -ms-flex: 1 1 auto;
    flex: 1 1 auto;
    text-align: center;
  }

  .gameon-filter-pane .gameon-filter-reset {
    -ms-flex-negative: 0;
    flex-shrink: 0;
    min-width: 4.5rem;
    text-align: right;
    font-size: .9375rem;
  }

  /* The only scrolling region.

     Its 1rem padding is moved onto the form below. A sticky bottom offset is
     measured against the scrollport, and whether that scrollport includes the
     container's own bottom padding is exactly the sort of thing browsers have
     historically disagreed on. With the padding on the form instead, the
     submit bar's "bottom: 0" is unambiguous: flush with the bottom of the
     sheet, everywhere. */
  .gameon-filter-pane .modal-body {
    -webkit-box-flex: 1;
    -ms-flex: 1 1 auto;
    flex: 1 1 auto;
    min-height: 0;
    padding: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* The form becomes a column so the submit row can be pushed to the bottom
     of a short form by margin-top: auto - the same technique the sticky
     footer above uses. flex: 1 0 auto so it fills the body but still grows
     past it when the fields are taller than the screen.

     It also carries the inset the modal body gave up, with no padding at the
     foot so the submit bar can sit flush against the bottom edge. */
  .gameon-filter-pane .gameon-filter-form {
    padding: 1rem 1rem 0;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-flex: 1;
    -ms-flex: 1 0 auto;
    flex: 1 0 auto;
  }

  /* The crispy FormActions row, turned into the pinned submit bar.

     margin-top: auto and position: sticky do two different jobs and both are
     needed: the auto margin drops the bar to the bottom when the form is
     shorter than the sheet, and the sticky bottom pins it there while the
     fields scroll underneath when the form is taller. On this screen the form
     is always taller; on a shorter Inq form it would not be.

     The negative side margins take the bar full-bleed to the edges of the
     sheet, back out past the form's own 1rem inset. */
  .gameon-filter-pane .gameon-filter-form .form-group:not([id]) {
    margin: auto -1rem 0 -1rem;
    padding: .75rem 1rem;
    position: -webkit-sticky;
    position: sticky;
    bottom: 0;
    background-color: #fff;
    border-top: 1px solid #e9ecef;
  }

  /* FormActions renders the Reset link, a bare &nbsp; text node, and the
     submit. Reset moves to the sheet header, and font-size: 0 collapses the
     orphaned &nbsp; so it cannot leave a blank line above the button. The
     button restores its own font-size below. */
  .gameon-filter-pane .gameon-filter-form .form-group:not([id]) > div {
    font-size: 0;
  }

  .gameon-filter-pane .gameon-filter-form .form-group:not([id]) a {
    display: none;
  }

  /* One full-width primary action. The width and the font-size undo the
     btn-sm sizing crispy applies, without touching forms.py. */
  .gameon-filter-pane .gameon-filter-form .form-group:not([id]) input[type="submit"] {
    display: block;
    width: 100%;
    padding: .5rem .75rem;
    font-size: 1rem;
    line-height: 1.5;
  }
}


/* --- 992px and up: turn the modal styling back off ------------------

   Desktop is unchanged by construction. Everything in the block above is
   inside a max-width query and cannot reach here, the display flip is done
   by Bootstrap's own d-lg-block in the template rather than by a rule here,
   and .modal-header carries d-lg-none - so the only work left is undoing the
   four cosmetic decisions .modal makes about position and chrome.

   Selectors are two classes deep so they win over Bootstrap's single-class
   rules on specificity rather than on file order. */

@media screen and (min-width: 992px) {

  /* .modal is position: fixed with all four offsets at 0, which would cover
     the viewport. Static restores it to an ordinary block in the column and
     makes those offsets and its z-index: 1050 inert. */
  .gameon-filter-pane.modal {
    position: static;
    overflow: visible;
  }

  /* margin: .5rem / 1.75rem auto and max-width: 500px are the centred-card
     geometry, which has no meaning inline. pointer-events is restored here as
     well: .modal-content already sets it back to auto, so this only covers
     the dialog's own box. */
  .gameon-filter-pane .modal-dialog {
    width: auto;
    max-width: none;
    margin: 0;
    pointer-events: auto;
  }

  /* The card chrome. Left as the page background rather than #fff so this
     cannot introduce a white panel on any screen that reuses the pattern. */
  .gameon-filter-pane .modal-content {
    background-color: transparent;
    border: 0;
    border-radius: 0;
  }

  /* .modal-body's 1rem padding would indent the form inside its column. */
  .gameon-filter-pane .modal-body {
    padding: 0;
  }
}


/* ==================================================================
   Referee's Corner - game schedule table
   ==================================================================

   Used by templates/Ops/Includes/RCGameSchedule.html only, which is the
   SCHED mode of templates/Ops/RefereesCorner.html. Every class here is
   prefixed gameon-rc- so nothing can reach another screen.

   The table this styles went from six columns to four. The two identical
   "Referee" columns were merged into one "Referees" cell holding, in order,
   a chip per booked referee, a Book button while a slot is free, and a
   status pill pushed to the right edge.

   COLOURS
   -------
   Declared as custom properties in the :root block below rather than written
   into the rules, so the palette can be changed in one place. This is a
   SECOND :root block: the existing one at the top of this file holds the
   load-check marker and is deliberately left untouched. Multiple :root rules
   are additive in CSS, so both apply.

   The values are Bootstrap 4.0.0's own $gray-200 / $gray-300 / $gray-800,
   $warning and $success, copied so this section does not depend on Bootstrap
   variables that are not exposed at runtime in a compiled stylesheet.

   NO !important anywhere in this section, and no existing rule above is
   modified.
   ------------------------------------------------------------------ */

:root {
  --gameon-rc-chip-bg: #e9ecef;          /* Bootstrap $gray-200 */
  --gameon-rc-chip-border: #dee2e6;      /* Bootstrap $gray-300, matches table rules */
  --gameon-rc-chip-text: #343a40;        /* Bootstrap $gray-800 */
  --gameon-rc-edge-amber: #ffc107;       /* Bootstrap $warning */
  --gameon-rc-pill-bg: #e9ecef;
  --gameon-rc-pill-text: #495057;        /* Bootstrap $gray-700 */
  --gameon-rc-pill-full-bg: #28a745;     /* Bootstrap $success */
  --gameon-rc-pill-full-text: #fff;
  --gameon-rc-daterow-bg: #f8f9fa;       /* Bootstrap $gray-100 */
  --gameon-rc-daterow-text: #212529;     /* Bootstrap $gray-900 */
  --gameon-rc-heading-text: #212529;     /* Matches the app-wide heading colour set in the heading colour section, so the two do not drift apart */
}


/* The heading above the table. Replaces style="color:blue;" on the H5, which
   was the only inline colour on this screen. */
.gameon-rc-heading {
  color: var(--gameon-rc-heading-text);
}


/* The "3 of 8 games need referees" line between the heading and the table. */
.gameon-rc-summary {
  margin-bottom: .5rem;
  color: var(--gameon-rc-pill-text);
}


/* ---- Date subheading rows -----------------------------------------

   The Date column was removed from the table. Instead the loop emits one of
   these rows before the first game of each date, via {% ifchanged %}. It is a
   real <tr> with a single <td colspan="4">, so it participates in the table
   layout, but it is styled as a subheading rather than as data.

   It sits inside <tbody>, so .table-striped counts it in its nth-of-type
   phase. That is why the background is set explicitly here rather than left
   to inherit: without it, a date row landing on an odd row would pick up the
   stripe and read as data. ------------------------------------------------ */

.gameon-rc-daterow > td {
  background-color: var(--gameon-rc-daterow-bg);
  color: var(--gameon-rc-daterow-text);
  font-weight: 600;
  border-top: 2px solid var(--gameon-rc-chip-border);
}


/* ---- Short-staffed row marker -------------------------------------

   A thin amber edge down the left of any row with fewer than two referees
   booked.

   On the FIRST CELL, not the row. Bootstrap's .table is border-collapse:
   collapse, and a box-shadow on a <tr> is not painted reliably in a collapsed
   table, so the shadow goes on the td.

   inset box-shadow rather than border-left for two reasons: a border would
   add 3px to the cell box and shift the Time column out of line with the date
   rows above it, and collapsed borders are painted by the table rather than
   the cell, so they can be overridden by a neighbouring cell's border.

   An inset shadow paints inside the existing padding box and composites over
   whatever background is already there, so .table-striped and .table-hover
   both keep working underneath and the row is NOT repainted - only the 3px
   strip is drawn. -------------------------------------------------------- */

.gameon-rc-row-short > td:first-child {
  box-shadow: inset 3px 0 0 0 var(--gameon-rc-edge-amber);
}


/* ---- The Referees cell wrapper ------------------------------------

   Holds the chips, the Book button(s) and the status pill on one line at
   desktop width, with the pill pushed to the far right so the pills line up
   in a column down the right edge of the table.

   Vendor prefixes match the house style used by the sticky footer and filter
   sheet sections above: -webkit-box and -ms-flexbox alongside the standard
   property.

   No flexbox "gap" here. Safari did not support gap in flex containers until
   14.1, and the Bootstrap 4.0.0 baseline this project targets predates that,
   so spacing is done with margins instead. ---------------------------- */

.gameon-rc-refs {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  /* Below 992px the cell is narrow, so items are allowed to wrap onto more
     than one line. The pill is still last in source order and still carries
     margin-left: auto, so it stays at the end. */
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

/* From 992px up - the same breakpoint as .table-responsive-lg and the frozen
   column rules above - everything stays on one line. */
@media screen and (min-width: 992px) {
  .gameon-rc-refs {
    -ms-flex-wrap: nowrap;
    flex-wrap: nowrap;
  }
}


/* ---- Referee chip -------------------------------------------------

   A rounded pill carrying "First Last" and, for those allowed to remove the
   assignment, a times control.

   inline-flex so the name and the control sit on one baseline, and
   white-space: nowrap so a two-word name never breaks inside the chip. */

.gameon-rc-chip {
  display: -webkit-inline-box;
  display: -ms-inline-flexbox;
  display: inline-flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  padding: .25rem .5rem;
  border: 1px solid var(--gameon-rc-chip-border);
  border-radius: 1rem;
  background-color: var(--gameon-rc-chip-bg);
  color: var(--gameon-rc-chip-text);
  /* Bootstrap 4.0.0 body font-size is 1rem / 16px. .875rem keeps the chip
     readable while letting two of them share a cell at tablet width. */
  font-size: .875rem;
  line-height: 1.25;
  white-space: nowrap;
}

/* 14px between adjacent chips. Adjacent-sibling selector rather than a
   container gap, per the note on flex gap support above. */
.gameon-rc-chip + .gameon-rc-chip {
  margin-left: 14px;
}


/* ---- Chip remove control ------------------------------------------

   The visible glyph stays small, but the touch target is 44px by 44px, which
   is the minimum in WCAG 2.2 Target Size (Minimum) and the figure Apple's HIG
   uses.

   The arithmetic: the box is 44x44. The glyph occupies roughly 16px square at
   this font size. Negative margins of -(44-16)/2 = -14px on the top, bottom
   and right pull the box back to the glyph's own footprint, so the chip does
   not visually inflate in any direction while the hit area still extends the
   full 44px. The left margin is -8px rather than -14px, leaving 6px of visual
   separation between the name and the glyph.

   The target overflows the chip's rounded edge on three sides. That is the
   point - it is invisible, it sits on the chip's own right-hand end where
   there is no adjacent control, and the 14px chip gap keeps it clear of the
   next chip. ------------------------------------------------------------- */

.gameon-rc-chip-remove {
  display: -webkit-inline-box;
  display: -ms-inline-flexbox;
  display: inline-flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: -14px -14px -14px -8px;
  color: var(--gameon-rc-chip-text);
  font-size: 1rem;
  line-height: 1;
  text-decoration: none;
}

.gameon-rc-chip-remove:hover,
.gameon-rc-chip-remove:focus {
  color: var(--gameon-rc-chip-text);
  text-decoration: none;
}


/* ---- Chips group and actions group --------------------------------

   The cell has two children: the chips on the left, and the Book buttons plus
   the status pill grouped together on the right.

   Previously every item was a direct flex child of .gameon-rc-refs and only
   the pill carried margin-left: auto, so the buttons started at a different
   x position on each row depending on how many chips preceded them. Grouping
   the buttons with the pill and pushing the whole group right means the
   buttons line up down the table as well as the pills.

   The chips container is emitted by the template even when it holds no chips,
   so the actions group starts from a consistent place. ------------------- */

.gameon-rc-chips {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  /* Chips may wrap onto a second line in a narrow cell; the actions group
     stays on the first. */
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

.gameon-rc-actions {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  /* Pushes the whole group to the right edge of the cell, whatever precedes
     it. This replaces the auto margin that used to sit on the pill alone. */
  margin-left: auto;
  /* Never squeezed by long referee names to its left. */
  -ms-flex-negative: 0;
  flex-shrink: 0;
}

/* The same 14px rhythm used between chips, applied between the buttons and
   between the last button and the pill. */
.gameon-rc-actions > * + * {
  margin-left: 14px;
}


/* ---- Status pill --------------------------------------------------

   Last inside the actions group, so it sits hard right in the cell and the
   pills form a column down the right of the table.

   min-width is what keeps the BUTTONS aligned as well. Without it the pill
   sizes to its own label, so a row showing the shorter full-state pill would
   let its button sit further right than a row showing "0 of 2". Both variants
   therefore get the same min-width, and the text is centred within it.
   ------------------------------------------------------------------ */

.gameon-rc-pill {
  display: -webkit-inline-box;
  display: -ms-inline-flexbox;
  display: inline-flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  /* Sized to the widest label, "0 of 2" / "1 of 2". See the note in the
     commit for the arithmetic; briefly, six characters at .8125rem with
     tabular digits plus 1rem of horizontal padding measures about 52px, and
     4.5rem leaves headroom for the fallback face if Inter does not load. */
  min-width: 4.5rem;
  padding: .125rem .5rem;
  border-radius: 1rem;
  background-color: var(--gameon-rc-pill-bg);
  color: var(--gameon-rc-pill-text);
  font-size: .8125rem;
  line-height: 1.25;
  white-space: nowrap;
}

/* The both-booked variant. Same geometry, green ground. */
.gameon-rc-pill-full {
  background-color: var(--gameon-rc-pill-full-bg);
  color: var(--gameon-rc-pill-full-text);
}


/* ==================================================================
   Referee's Corner schedule - stacked rows below 992px
   ==================================================================

   The four column table overflows a phone. The Referees cell alone is wider
   than 375px once two buttons and a pill sit in it, and Arena and Teams wrap
   badly long before that.

   Below 992px each game row becomes a card of three lines:

       line 1   time . arena . teams        (one running summary line)
       line 2   referee chips               (collapses to nothing when empty)
       line 3   Book buttons, status pill   (buttons left, pill hard right)

   991.98px / 992px is the same boundary used by the frozen column rules, the
   filter sheet and Bootstrap's own .table-responsive-lg, so everything on the
   screen switches together. It is the exact complement of col-lg-*, which is
   what RefereesCorner.html uses for the two pane split.

   SCOPING. Every rule is keyed to .gameon-rc-table, a class added to this one
   table. gameon.css loads on 133 templates, so an unscoped "table { display:
   block }" inside a media query would restructure every table in the project.

   DESKTOP IS UNTOUCHED BY CONSTRUCTION. Everything below sits inside the
   max-width query and cannot reach 992px and up. The only additions outside
   it are the two custom properties, which are inert until referenced, and
   they are referenced only in here.
   ------------------------------------------------------------------ */

:root {
  --gameon-rc-card-border: #dee2e6;      /* Bootstrap $gray-300, the table border colour */
  --gameon-rc-summary-sep: #6c757d;      /* Bootstrap $gray-600 */

  /* Stacked card spacing, three levels, tuned from one place.

     The hierarchy is what makes the grouping read, so keep the order:

         line gap  10px   inside a card, between its three lines
         card gap  14px   between two adjacent game cards
         day  gap  28px   above a date row, starting a new day

     14px is the horizontal rhythm this section already uses between chips
     and between buttons, so the vertical gap between cards matches it. The
     day gap is exactly double the card gap. The line gap is deliberately the
     smallest of the three: space inside a card must stay tighter than the
     space around it, or the card stops reading as one object.

     Only referenced inside the max-width query below, so none of this
     reaches desktop. */
  --gameon-rc-line-gap: .625rem;         /* 10px */
  --gameon-rc-card-gap: .875rem;         /* 14px */
  --gameon-rc-day-gap:  1.75rem;         /* 28px */
}

@media screen and (max-width: 991.98px) {

  /* 5. The four header labels describe columns that no longer exist. */
  .gameon-rc-table > thead {
    display: none;
  }

  /* 1. Drop the table box model so nothing is forced onto one line.
        tbody is included because leaving it as table-row-group around block
        level rows is exactly the case browsers handle by generating anonymous
        table boxes, which would put the old column layout back. */
  .gameon-rc-table,
  .gameon-rc-table > tbody,
  .gameon-rc-table > tbody > tr,
  .gameon-rc-table > tbody > tr > td {
    display: block;
  }

  .gameon-rc-table {
    width: 100%;
  }

  /* 8. Each game row reads as a discrete card: its own padding and a rule
        above it. The padding moves off the cells and onto the row so the
        three summary values are not each separately inset.

        .table-striped keeps working untouched. It sets background-color on
        tbody tr:nth-of-type(odd), and a block level tr still paints its own
        background, so adjacent cards keep alternating. Nothing here sets a
        background, precisely so that alternation is not overpainted. */
  .gameon-rc-table > tbody > tr:not(.gameon-rc-daterow) {
    padding: .5rem .75rem;
    border-top: 1px solid var(--gameon-rc-card-border);
  }

  /* Bootstrap puts padding and a border-top on every td. Stacked, that would
     draw a rule between the time, the arena and the teams. */
  .gameon-rc-table > tbody > tr:not(.gameon-rc-daterow) > td {
    padding: 0;
    border-top: 0;
  }

  /* ---- Vertical rhythm between rows -------------------------------

     Two levels: cards are separated by the card gap, and a new day is
     separated by the day gap, which is double it.

     EVERY gap here is a margin-TOP and nothing sets a margin-bottom. tbody is
     a block box, so adjacent siblings' vertical margins collapse; with only
     one margin in play at each junction the collapsed value is simply that
     margin (0 collapsed with X gives X), which keeps the arithmetic
     predictable. Setting both a bottom and a top margin would silently give
     max(bottom, top) rather than the sum, which is the usual way this goes
     wrong.

     The gaps show the page background rather than the row's own background,
     because .table-striped paints the tr box only. That is what turns the
     alternating stripe into discrete cards instead of a continuous ribbon.

     "tr + tr" is the whole first-row exception: it matches only a row that
     HAS a preceding sibling, so the first row in the tbody never gets a top
     gap. It is deliberately not :first-child and not :nth-of-type(1), and it
     does not assume the first row is a date row. If the markup ever led with
     games before the first date row, that first game would correctly get no
     gap and the date row after it would correctly get the day gap. */

  /* Between two adjacent cards. */
  .gameon-rc-table > tbody > tr + tr {
    margin-top: var(--gameon-rc-card-gap);
  }

  /* A new day starts a new block. Specificity 0-2-3 against 0-1-3 above. */
  .gameon-rc-table > tbody > tr + tr.gameon-rc-daterow {
    margin-top: var(--gameon-rc-day-gap);
  }

  /* No extra space BELOW a date row: it belongs with its own first game.
     :not() keeps this off a date row, so it can never cancel the day gap. */
  .gameon-rc-table > tbody > tr.gameon-rc-daterow + tr:not(.gameon-rc-daterow) {
    margin-top: 0;
  }

  /* 2. Line 1. The first three cells go inline so they form ONE running text
        line rather than three stacked blocks - which is the point of the
        requirement - and so that a long arena name wraps as text instead of
        pushing the card wider than the viewport. This is the deliberate
        exception to the display: block rule above.

        The date row is excluded from all of this by :not(), because its single
        cell must stay full width. Its colspan="4" becomes inert once the table
        box model is gone, so the colspan neither helps nor breaks anything. */
  .gameon-rc-table > tbody > tr:not(.gameon-rc-daterow) > td:nth-child(-n+3) {
    display: inline;
  }

  /* Time is the value someone scans for first. */
  .gameon-rc-table > tbody > tr:not(.gameon-rc-daterow) > td:nth-child(1) {
    font-weight: 600;
  }

  /* A middot between the three values, so they read as one summary line.
     Generated content rather than markup, so the template keeps its four
     cells and the desktop table is unaffected. */
  .gameon-rc-table > tbody > tr:not(.gameon-rc-daterow) > td:nth-child(1)::after,
  .gameon-rc-table > tbody > tr:not(.gameon-rc-daterow) > td:nth-child(2)::after {
    content: "\00B7";
    margin: 0 .375rem;
    color: var(--gameon-rc-summary-sep);
    font-weight: 400;
  }

  /* 3 and 4. The Referees cell stops being a flex row and becomes two
     stacked blocks: chips, then actions. */
  .gameon-rc-refs {
    display: block;
  }

  /* 3. The chips container is emitted even when it holds no chips. As a flex
        container whose only content is whitespace it has zero height, and it
        carries no margin or padding of its own, so the line collapses to
        nothing rather than leaving a gap.

        The separation therefore lives on the chips themselves. Flex item
        margins never collapse, so this is deterministic: no chips means no
        margin at all, and chips wrapping to a second line get the same
        spacing between the lines for free. */
  .gameon-rc-chips > .gameon-rc-chip {
    margin-top: var(--gameon-rc-line-gap);
  }

  /* 4. margin-left: auto is what right aligns the whole group on desktop.
        Stacked, the group is a full width block and the auto margin has to
        go, or the buttons would be pushed off to the right with the pill. */
  .gameon-rc-actions {
    margin-left: 0;
    margin-top: var(--gameon-rc-line-gap);
    /* Two buttons plus the pill measure close to the inner width of a 375px
       card. Allowing a wrap means the worst case degrades to a second line
       instead of overflowing the viewport. */
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
  }

  /* The pill keeps its column down the right edge of the card. This outranks
     the 14px rhythm rule on specificity, 0-2-0 against 0-1-0. */
  .gameon-rc-actions > .gameon-rc-pill {
    margin-left: auto;
  }

  /* 7. The amber edge moves from the first cell to the left edge of the whole
        card. It can move because a block level tr paints its own box shadow,
        which a tr in a border-collapse table does not.

        Same selector as the desktop rule, so it matches on specificity and
        wins on order, switching the strip off the time cell. */
  .gameon-rc-table > tbody > tr.gameon-rc-row-short {
    box-shadow: inset 3px 0 0 0 var(--gameon-rc-edge-amber);
  }

  .gameon-rc-row-short > td:first-child {
    box-shadow: none;
  }
}


/* ==================================================================
   Referee's Corner schedule - day spacing above 992px
   ==================================================================

   Mobile separates days with margin-top on the date row. Desktop cannot do
   that: above 992px these are real table rows again, and margin on a <tr> is
   ignored, so the space has to come from padding on the date row's <td>.

   The problem with padding alone is that the cell's background grows with it,
   turning a 28px gap into a 28px taller shaded band. What is wanted is empty
   space with the label and its shading sitting at the bottom of it.

   THE APPROACH: padding-top for the space, and a two stop linear-gradient as
   the cell background so only the lower part is painted.

       [ 0 .. day gap ]   transparent, reads as empty
       [ day gap .. ]     the date row shading, with the label on it

   WHY THIS ONE, and what was rejected:

   - background-clip: content-box would have unshaded the LEFT and RIGHT
     padding too, so the band would stop short of the cell edges and hug the
     text. A gradient is directional, so it only cuts the top.

   - A transparent top border plus background-clip: padding-box has the same
     directional advantage, but .table is border-collapse: collapse, where
     borders are painted by the table rather than the cell and the interaction
     with cell backgrounds is exactly the sort of thing browsers have
     historically disagreed on. The gradient touches no border at all.

   - Selecting the last game row of a day and giving it bottom padding would
     need :has(), which is far outside the Bootstrap 4.0.0 browser baseline.

   SURVIVING table-striped AND table-hover. Both set background-color on the
   <tr>, which paints BEHIND the cell's gradient, so a striped or hovered date
   row would show 5% or 7.5% grey through the transparent part instead of
   empty space. The rule below therefore clears the row background for date
   rows only. That is invisible in the current design, because the single
   colspan="4" cell already covers the whole row opaquely; it only matters
   once part of that cell stops painting.

   The 2px rule above the band is dropped on gapped date rows. It would
   otherwise float at the top of the empty space, which contradicts the space
   reading as empty. The first date row keeps it, because it has no space
   above it to do that job.

   No new custom property. --gameon-rc-day-gap is reused exactly as the mobile
   rules use it, so both breakpoints move together from one value.
   ------------------------------------------------------------------ */

@media screen and (min-width: 992px) {

  /* Only a date row that HAS a row above it. Same adjacent sibling approach
     as mobile, and deliberately not :first-child: it asks "is anything above
     me?" rather than assuming the table opens with a date row. */
  .gameon-rc-table > tbody > tr + tr.gameon-rc-daterow > td {
    /* The gap, plus .3rem to restore the internal inset the band would
       otherwise lose. .3rem is Bootstrap 4.0.0's own .table-sm cell padding,
       which this table uses. */
    padding-top: calc(var(--gameon-rc-day-gap) + .3rem);
    /* The rule would sit at the very top of the empty space. */
    border-top: 0;
    /* Cleared so it cannot paint behind the transparent part of the
       gradient. The gradient below does all of the painting. */
    background-color: transparent;
    background-image: linear-gradient(to bottom,
                        transparent var(--gameon-rc-day-gap),
                        var(--gameon-rc-daterow-bg) var(--gameon-rc-day-gap));
  }

  /* .table-striped sets background-color on tbody tr:nth-of-type(odd) and
     .table-hover on tbody tr:hover, both at 0-2-2. The first selector here
     ties at 0-2-2 and wins on order, since gameon.css loads after Bootstrap;
     the second is 0-3-2 and wins outright. */
  .gameon-rc-table > tbody > tr.gameon-rc-daterow,
  .gameon-rc-table > tbody > tr.gameon-rc-daterow:hover {
    background-color: transparent;
  }
}


/* ==================================================================
   Home page launcher cards
   ==================================================================

   The problem: the home page launcher was two <table>s in the left
   column, one button per <tr><td>. On a phone that is a single column of
   up to twelve small buttons, each one a bare verb with no indication of
   what it leads to, and the whole stack has to be scrolled past before
   the activities pane is reachable.

   The fix: the same anchors, in the same order, under the same
   conditions, rendered as cards carrying an icon, the original button
   text as a label, and one line saying what the destination is for.

   TWO LAYOUTS, EACH FULLY SCOPED TO ITS OWN QUERY. Below 720px the
   container is a horizontal snap scroller, so the launcher costs one
   row of vertical space instead of twelve and the activities pane moves
   up the page. From 720px the container is a grid that fills its column
   with as many 220px tracks as fit. Neither layout leaks into the other:
   the layout properties live only inside the two media queries, and the
   rules outside them are appearance only.

   WHAT 720px DOES AND DOES NOT MEAN. It is a container-width guess made
   against a viewport query, which is the usual compromise without
   container queries. The guess is a safe one here because the launcher
   sits in a col-12 at every breakpoint, so its container is the full
   content width and tracks the viewport rather than diverging from it at
   some breakpoint. Nothing below depends on the column class, so moving
   the launcher between columns changes the track count and nothing else.

   ICONS ARE INLINE SVG, NOT FONT AWESOME. The project loads FA 6.7.2 but
   the templates use FA 4 class names, so some glyphs render as nothing
   at all. An inline <svg> cannot fail that way. Each one is stroke-only
   and inherits its colour through stroke="currentColor" in the rule
   below, so the teal/green split the btn-info and btn-success buttons
   carried is preserved by setting "color" on the icon alone.

   NO CUSTOM PROPERTIES. The --gameon- token block is on an unmerged
   branch, so every value here is a literal. The greys are Bootstrap
   4.0.0's own $gray-300 / $gray-600 / $gray-900, and the two accents are
   its $info and $success, so nothing new is introduced to the palette.

   NO !important anywhere in this section, and no existing rule above is
   modified. ------------------------------------------------------ */


/* Separation between the launcher and the section heading below it. The
   two <table>s this replaced each carried Bootstrap's own .table
   margin-bottom of 1rem (bootstrap.css:1672), so without a margin here
   the launcher ends flush against that heading.

   32px is from the mockup and is deliberately NOT a Bootstrap spacer
   step: the scale goes 1rem, 1.5rem, 3rem (bootstrap.css .mb-3/.mb-4/
   .mb-5), so there is no mb-* utility that produces it and it has to be
   set here. Written in px for that reason - reading 2rem invites someone
   to swap in .mb-4 and lose 8px.

   Outside both media queries on purpose: the gap is needed in the grid
   and in the scroller alike. Note that in scroller mode the container
   also carries padding-bottom: .5rem for the scrollbar, so the space
   below the cards there is 40px rather than 32px. That padding is a
   separate concern and is left alone. */
.gameon-launcher {
  margin-bottom: 32px;
}


/* The card itself. The anchor IS the card - there is no wrapper and no
   button inside it, so the whole box is the hit target rather than the
   short line of text the old <button> occupied. */
.gameon-launch-card {
  display: block;
  /* 16px on all four sides, matching the mockup. Deliberately uniform:
     the earlier asymmetric .5rem/.75rem was tighter than the mockup, not
     looser. */
  padding: 1rem;
  border: 1px solid #dee2e6;
  /* 8px, not Bootstrap's .25rem. Written in px so it sits alongside the
     icon square's 5px and the two can be compared by eye - the icon keeps
     the tighter radius on purpose. */
  border-radius: 8px;
  background-color: #fff;
  color: #17a2b8;                        /* Bootstrap $info, the old btn-info */
  text-decoration: none;
  /* Two layers, not one: the 1px layer is the contact shadow that seats
     the card on the surface, and the 6px layer is the soft ambient one.
     A single shadow has to choose between the two and ends up either
     hard-edged or vague.

     Tinted rgb(13, 31, 58), a dark navy, rather than black. Black at low
     alpha over a cool grey surface desaturates towards brown and reads as
     dirt on the page; a blue-black stays in the same temperature family as
     the #f8f9fa and #dee2e6 already used here. */
  box-shadow: 0 1px 1px rgba(13, 31, 58, .05),
              0 2px 6px rgba(13, 31, 58, .05);
}

/* Bootstrap's a:hover sets text-decoration: underline, which would
   underline both lines of the card. The colour change and the border
   below carry the hover instead. */
.gameon-launch-card:hover,
.gameon-launch-card:focus {
  text-decoration: none;
  border-color: currentColor;
  background-color: #f8f9fa;             /* Bootstrap $gray-100 */
  /* Same two layers, same tint, deeper: the contact layer gains a pixel
     and the ambient layer roughly doubles its spread. It reads as the
     card lifting, which a different shadow shape would not. */
  box-shadow: 0 1px 2px rgba(13, 31, 58, .07),
              0 4px 10px rgba(13, 31, 58, .09);
}

/* Keyboard focus has to stay visible: the rule above changes only the
   border, which is not enough on its own to show which card is focused
   when the pointer is not involved. */
.gameon-launch-card:focus {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* The registration, corner, profile and timekeeper cards. These were the
   btn-success buttons; only the accent moves, so the grouping a member
   already recognises by colour survives the change. */
.gameon-launch-personal {
  color: #28a745;                        /* Bootstrap $success */
}

/* The two timekeeper cards that render when the member cannot enter
   stats. In the table version these were a live anchor wrapping a
   disabled <button>, so the link still worked and only the button looked
   inactive. That behaviour is deliberately unchanged here - this rule is
   appearance only, and there is no pointer-events declaration. */
.gameon-launch-off {
  opacity: .55;
}

/* stroke rather than fill, because every icon in the template is drawn
   as open paths. currentColor is what ties them to the two accent rules
   above: the icon picks up the card's colour, while the label and the
   description set their own. */
.gameon-launch-icon {
  display: block;
  /* A 32px tinted square with the glyph at 18px centred inside it, done
     with padding rather than a wrapper element, because the template is
     not being changed: 32px box minus 7px padding on each side leaves an
     18px content box, and an <svg> with a viewBox scales its drawing to
     the content box while the background paints out to the border box.
     This relies on the global border-box rule at bootstrap.css:41. */
  width: 32px;
  height: 32px;
  padding: 7px;
  border-radius: 5px;
  background-color: #e3f4f6;             /* #17a2b8 at about 12% over white */
  /* Icon to label. One value is used for both internal gaps - see the
     matching margin-top on .gameon-launch-desc below - so the three
     stacked items sit on an even 8px rhythm. */
  margin-bottom: .5rem;
  fill: none;
  stroke: currentColor;
  /* 2.25 rather than 1.75. The viewBox is 24 units wide but the glyph now
     renders at 18px, so a stroke is drawn at three quarters of its
     authored width: 2.25 x 18/24 is 1.69px, which is about the 1.75px the
     icons had before they were scaled down. */
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The tint has to be set per accent, because a custom property is not
   available on this branch and CSS has no way to derive a translucent
   version of currentColor. Two classes deep, so it wins over the rule
   above on specificity rather than on file order. */
.gameon-launch-personal .gameon-launch-icon {
  background-color: #e5f4e9;             /* #28a745 at about 12% over white */
}

.gameon-launch-label {
  display: block;
  font-weight: 700;
  line-height: 1.3;
  color: #212529;                        /* Bootstrap $gray-900 */
}

.gameon-launch-desc {
  display: block;
  /* Label to description. The same .5rem as the icon-to-label gap above.
     These are adjoining sibling margins against elements that carry none
     of their own, so each gap resolves to 8px rather than doubling. */
  margin-top: .5rem;
  font-size: .8125rem;
  line-height: 1.3;
  color: #6c757d;                        /* Bootstrap $gray-600 */
}

/* Was <th>Time Keepers</th> on the second table. It is kept so the group
   still announces itself, but it is no longer a table header, so it
   needs its own type treatment. */
.gameon-launch-groupheading {
  margin: 0;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #6c757d;                        /* Bootstrap $gray-600 */
}


/* --- Below 720px: one row, scrolled sideways ----------------------

   The launcher stops being a column of twelve and becomes a single row
   the member swipes, so the activities pane below it starts within the
   first screen.

   Spacing is done with margin-right rather than the flexbox "gap"
   property, matching the sticky footer section above: Safari did not
   support gap in flex containers until 14.1, and the Bootstrap 4.0.0
   baseline this project targets predates that. The negative margin on
   the last card cancels the trailing gap so the row does not scroll to a
   blank strip. */

@media screen and (max-width: 719.98px) {

  .gameon-launcher {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: nowrap;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    -ms-scroll-snap-type: x mandatory;
    scroll-snap-type: x mandatory;
    /* Room for the scrollbar on platforms that reserve space for one, so
       it cannot sit on top of the bottom edge of the cards. */
    padding-bottom: .5rem;
  }

  .gameon-launcher > * {
    -webkit-box-flex: 0;
    -ms-flex: 0 0 auto;
    flex: 0 0 auto;
    margin-right: .75rem;
  }

  .gameon-launcher > :last-child {
    margin-right: 0;
  }

  .gameon-launch-card {
    width: 168px;
    scroll-snap-align: start;
  }

  /* Mid-stream in a scrolling row a full-width heading has nowhere to
     go, so it becomes a divider standing immediately before the cards it
     introduces, reading down the row rather than across it. */
  .gameon-launch-groupheading {
    -ms-flex-item-align: stretch;
    align-self: stretch;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    padding-left: .75rem;
    border-left: 1px solid #dee2e6;
  }
}


/* --- 720px and up: fill the column with 220px tracks ---------------

   auto-fill rather than auto-fit. auto-fit collapses the empty tracks
   and stretches the remaining cards across the full width, so a member
   with three cards would get three very wide ones. auto-fill keeps the
   empty tracks, so a card is the same size whoever is looking at it.

   WHY 220px AND NOT 168px. 168px fitted six cards across the desktop row,
   narrow enough that one description wrapped to three lines while another
   fitted on one. 220px is a threshold, not a rendered width: the 1fr
   maximum still stretches the tracks to fill the row, so what actually
   renders is four cards of about 261px.

   The arithmetic, which is worth keeping because the answer depends on it.
   HomePage.html opens its own .container inside the one in
   baseCrispy.html, and a nested container costs 2 x 15px of padding, so
   the grid has about 1080px at desktop rather than 1140px. With a 12px
   gap, four 220px tracks need 916px and five need 1148px, so 1080px
   resolves to exactly four. The band that still gives four runs from
   916px to 1147px of container width. The upper end is the one to watch:
   1110px is the widest this container can get, which is 38px short of
   fitting a fifth track.

   This is arithmetic from the container chain and the gap, NOT a
   measurement - verify in devtools. */

@media screen and (min-width: 720px) {

  .gameon-launcher {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    grid-gap: .75rem;
    gap: .75rem;
  }

  /* Spans every track, however many the column resolved to, so the
     heading sits on its own line above the cards it introduces. */
  .gameon-launch-groupheading {
    grid-column: 1 / -1;
    margin-top: .25rem;
  }
}


/* ==================================================================
   Home page notice
   ==================================================================

   The problem: the referee recruitment notice at the top of the home
   page was a .table of two single-cell rows - a heading row and a body
   row - with the heading coloured by an inline style="color:blue;". A
   table for a block of prose gives no surface, no border and no way to
   separate it from the launcher below it, so on a phone it read as the
   first paragraph of the page rather than as an announcement.

   The fix: the same copy, word for word and in the same order, in an
   announcement component - pale blue surface, blue hairline border, a
   circular icon chip beside the heading, and a mailto button under the
   body so the email address in the last line is actionable rather than
   something to copy out by hand.

   THE COPY IS UNCHANGED. Every line, the <strong> on the first one, the
   <br> between them and the H5 tag on the heading are all carried over
   as they were. The H5 lost its inline color:blue, because the heading
   colour is set here instead. NOTE: another open branch removes that
   same attribute from that same line as part of a page-wide sweep of
   the 243 headings carrying it, so expect a conflict on that one line
   and resolve it by keeping the attribute removed.

   THE BUTTON IS THE ONE ADDITION. The last line still reads exactly as
   before, email address included; the button is added below it rather
   than replacing the address, so nothing is lost for anyone reading the
   text rather than clicking.

   COLOURS ARE SPECIFIED, NOT BOOTSTRAP'S. An earlier version of this
   section reused Bootstrap's .alert-primary and .btn-primary values, which
   were too saturated. These replace them and are deliberately outside the
   Bootstrap palette:

       #eef4ff   surface
       #bcd3ff   border
       #183a8c   heading and body text, and the focus outline
       #1b56db   icon chip fill and button background
       #fff      chip glyph and button label

   Only the two button states are derived rather than given: #1749ba is
   #1b56db darkened for hover, and #1442a8 is its border. If the given
   values change, those two follow.

   THE SHADOW IS DELIBERATELY THE LAUNCHER CARD'S. Same two layers, same
   rgba(13, 31, 58) navy, so the two components sit on the same surface
   convention. That literal is duplicated rather than shared because the
   token block is on an unmerged branch and so is the launcher section
   itself - when both land, these are the values to reconcile.

   NO !important anywhere in this section, and no existing rule above is
   modified. ------------------------------------------------------ */


.gameon-notice {
  /* Two columns: the chip at its own width on the left, everything else in
     the right column. The heading, the body copy and the button are all
     children of .gameon-notice-main, so they share one left edge rather
     than the text running under the chip. */
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  /* flex-start so the chip stays at the top of a multi-line block. */
  -webkit-box-align: start;
  -ms-flex-align: start;
  align-items: flex-start;
  padding: 16px;
  border: 1px solid #bcd3ff;
  border-radius: 12px;
  background-color: #eef4ff;
  /* Two layers and the navy tint, matching .gameon-launch-card exactly:
     a 1px contact shadow to seat the block, a 6px ambient one to soften
     it. Black at low alpha over a blue surface goes muddy; a blue-black
     stays in the same temperature family. */
  box-shadow: 0 1px 1px rgba(13, 31, 58, .05),
              0 2px 6px rgba(13, 31, 58, .05);
  /* 32px below, matching the gap above. See the home page rhythm rule at
     the end of this section. */
  margin-bottom: 32px;
}


/* The right column. min-width: 0 is what stops a long unbroken string in
   the copy from forcing the flex item wider than its share and pushing the
   component past its container - a flex item's automatic minimum size is
   its content, not zero. */
.gameon-notice-main {
  -webkit-box-flex: 1;
  -ms-flex: 1 1 auto;
  flex: 1 1 auto;
  min-width: 0;
}

/* 38px circle, solid blue, white glyph. The bottom margin only shows
   when the heading has wrapped beneath it. */
.gameon-notice-chip {
  -webkit-box-flex: 0;
  -ms-flex: 0 0 auto;
  flex: 0 0 auto;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -ms-flex-pack: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-right: .75rem;
  border-radius: 50%;
  background-color: #1b56db;
}

/* stroke rather than fill, matching the launcher icons. #fff literally
   rather than currentColor, because the chip sets no colour of its own
   and the glyph must stay white whatever inherits into it. */
.gameon-notice-chip > svg {
  display: block;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: #fff;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Still an H5, so it keeps Bootstrap's 1.25rem. The colour replaces the
   inline color:blue the tag used to carry.

   margin: 0 0 .5rem, not margin: 0. Bootstrap's reboot already gives every
   heading margin-bottom: 0.5rem (bootstrap.css:82-85), which is the 8px
   wanted between the heading and the paragraph - but a flat "margin: 0"
   here outranks it on specificity, one class against one element, and the
   gap collapsed to nothing. The top margin still has to be zeroed, because
   the heading is the first thing in its column. */
.gameon-notice-title {
  -webkit-box-flex: 1;
  margin: 0 0 .5rem;
  color: #183a8c;
}

/* The four lines of copy, separated by <br> inside one <p>, so this one
   line-height governs all four. 1.6 rather than the 1.5 inherited from
   body (bootstrap.css:66) - at 16px that is 25.6px a line instead of 24px,
   which is what stops four <br>-separated lines reading as a squeezed
   block.

   margin-bottom: 1rem is Bootstrap's own <p> value (bootstrap.css:87-90)
   and the 16px wanted above the button. The .75rem that was here overrode
   it down to 12px for no reason worth keeping. */
.gameon-notice-body {
  margin-bottom: 1rem;
  line-height: 1.6;
  color: #183a8c;
}

/* The mailto button. Styled here rather than with .btn .btn-primary so
   it cannot pick up Bootstrap's own focus box-shadow, which is a 3px
   spread halo that would fight the component's two-layer shadow. */
.gameon-notice-action {
  display: inline-block;
  padding: .375rem .75rem;
  border: 1px solid #1b56db;
  border-radius: .25rem;
  background-color: #1b56db;
  color: #fff;
  font-size: .9375rem;
  line-height: 1.5;
  text-decoration: none;
}

/* Bootstrap's a:hover would underline the label. A darker fill carries the
   hover instead: #1749ba is #1b56db at about 85% brightness, which is the
   one pair of values in this section derived rather than specified. */
.gameon-notice-action:hover,
.gameon-notice-action:focus {
  background-color: #1749ba;
  border-color: #1442a8;
  color: #fff;
  text-decoration: none;
}

/* Keyboard focus needs to be visible without the box-shadow halo that
   was the reason for not using .btn-primary. An outline sits outside the
   border box and does not disturb the component's shadow. */
.gameon-notice-action:focus {
  outline: 2px solid #183a8c;
  outline-offset: 2px;
}


/* --- Below 720px: the two columns stack ----------------------------

   display: block rather than a flex-direction change, because the chip is
   already a block-level flex container and .gameon-notice-main is a div,
   so both fall into normal flow on their own. The chip keeps its right
   margin, which is harmless once it is on its own line, and gains a bottom
   one here. */

@media screen and (max-width: 719.98px) {

  .gameon-notice {
    display: block;
  }

  .gameon-notice-chip {
    margin-bottom: .75rem;
  }
}


/* --- Home page vertical rhythm -------------------------------------

   32px between the blocks at the top of the home page: above and below
   the welcome heading, and above and below the notice.

   Three declarations cover four gaps, because "below the heading" and
   "above the notice" are the same gap, and the heading's margin-bottom is
   what produces it.

   HomePage.html used to open its own .container between the two and no
   longer does, so what now sits between them is the .row the heading
   precedes (margin-right and margin-left only, bootstrap.css:596-604) and
   the .col-12 inside it (padding-right and padding-left only,
   bootstrap.css:626-627). Neither carries any vertical padding or margin,
   so nothing in that nesting adds to the gap or interrupts it.

   The heading's margin-top replaces the 4px the breadcrumb's .my-1 leaves
   above it. Adjoining margins collapse to the larger of the two, so this
   sets the gap to 32px rather than adding to it.

   Scoped to the two classes on purpose. Nothing here reaches the
   activities pane or anything below it.

   THE TYPE TREATMENT, and where the size comes from.

   The size is derived from the notice rather than chosen. The notice
   heading is an H5 at 1.25rem (bootstrap.css:386-388) sitting above body
   copy that inherits 1rem from body (bootstrap.css:64), so that component
   uses a 1.25 ratio between a heading and its text. The page title is one
   step further up the same scale: 1.25rem x 1.25 = 1.5625rem, or 25px.
   That puts a legible 5px between the page title and a section heading
   without introducing a second ratio to the page.

   Worth knowing: that is only 1px above the 1.5rem Bootstrap gives an h4
   (bootstrap.css:382-384), so the size was close to right already and
   almost all of the visible change here is weight, colour and alignment.

   font-weight 600 is not just a design preference. Bootstrap sets every
   heading to font-weight 500 (bootstrap.css:361-368), and Inter is
   self-hosted here at 400, 600 and 700 only - see the @font-face blocks at
   the top of this file. So 500 has no file behind it and the browser has
   been synthesising it. 600 is a real Inter weight, so this replaces a
   faux-bold with the actual semibold cut.

   text-align: left is set here rather than left to inherit, because the
   point of removing text-center from the tag was to move the decision into
   the component. Bootstrap's body already sets text-align: left, so this
   changes nothing on its own - it just stops the alignment depending on an
   ancestor.

   line-height is deliberately not set, so the heading keeps Bootstrap's
   1.2 for headings. */

.gameon-home-heading {
  margin-top: 32px;
  margin-bottom: 32px;
  /* 1.25rem x 1.25 - the notice heading's ratio to its body copy, applied
     one step up. See the note above. */
  font-size: 1.5625rem;
  font-weight: 600;
  color: #212529;                        /* Bootstrap $gray-900 */
  text-align: left;
}


/* ==================================================================
   Heading colour
   ==================================================================

   Sets one colour for every heading in the app.

   Why this exists: 241 headings across 113 templates carried an inline
   style="color:blue;" attribute, and 113 more carried no colour at all, so
   heading colour varied from screen to screen with no rule behind which was
   which. Those 241 attributes have been removed and the colour set here
   instead, in one place, so a future change is one edit rather than 241.

   #212529 rather than blue on purpose. That is Bootstrap's body colour
   (bootstrap.css:56), which is exactly what the 113 uncoloured headings
   already inherited. Setting it here makes the two groups agree, instead of
   spreading blue to headings that never had it.

   Bootstrap 4.0.0 sets "color: inherit" on h1-h6 (bootstrap.css:356), which
   is why those 113 took the body colour in the first place. This rule
   replaces that inherit, so a heading no longer picks up a coloured
   ancestor. Nothing in templates/ has one today - checked - but that is the
   one behaviour this changes beyond the colour itself.

   A literal value rather than a var(). The --gameon- token block is on an
   unmerged branch, so a custom property referenced here would resolve to
   nothing until that lands.

   Two headings keep their inline style deliberately and are not reached by
   this rule: Ops/PoolBillEmail.html and Ops/PlayerAppSelfDone.html both
   render outside baseCrispy.html, the only template that links this file, so
   stripping their attribute would have lost the colour with nothing to
   replace it.

   Element selectors only. Bootstrap's .h1-.h6 classes are left alone, since
   they exist to give a non-heading element a heading's appearance and no
   template uses them for colour.
   ------------------------------------------------------------------ */

h1, h2, h3, h4, h5, h6 {
  color: #212529;
}
