/* ==========================================================================
   CableTow Design Tokens — single source of brand truth (plan 15-03).
   --------------------------------------------------------------------------
   Mirrored verbatim from .planning/features/v01/15-frontend-ui/15-mockups/_tokens.css.
   Update both files together; the mockup library and the live app must agree.

   HARD BRAND RULES (CLAUDE.md, design-color-restrictions.md):
   - NO Pantone 7659C purple #370C3E or any shade/tint (purple = Grand Lodge
     regalia; CableTow serves Blue Lodge).
   - NO pure white #FFFFFF — use #FAF7F2 (warm off-white).
   - NO pure black #000000 — use #1A1A1A (near-black).
   ========================================================================== */

:root {
  /* ----- Primary brand palette ----- */
  --ct-royal-blue: #343579;     /* PMS 2118 C  — primary brand (Blue Lodge color) */
  --ct-gold:       #FFBB1C;     /* Pantone 1235 C — primary accent */
  --ct-maroon:     #7D2248;     /* PMS 216 C   — secondary accent */

  /* ----- Neutrals ----- */
  --ct-grey-mid:   #999999;     /* 40% Black */
  --ct-off-white:  #FAF7F2;     /* warm paper — "white" substitute */
  --ct-near-black: #1A1A1A;     /* soft black — "black" substitute */

  /* ----- Derivatives (computed off the primary palette — never purple-adjacent) ----- */
  --ct-blue-dark:  #252659;     /* hover/active on royal blue */
  --ct-blue-light: #5C5DA5;     /* tinted royal blue for backgrounds */
  --ct-gold-dark:  #D99A0A;     /* hover/active on gold */
  --ct-grey-light: #E5E5E5;     /* surface / divider */
  --ct-grey-dark:  #4A4A4A;     /* secondary text */

  /* ----- Semantic states (no purples) ----- */
  --ct-success:    #2E7D5B;     /* desaturated green */
  --ct-warning:    #C77700;     /* burnt amber (gold-adjacent, not yellow) */
  --ct-danger:     #B53D3D;     /* desaturated red — NOT pink/magenta */
  --ct-info:       #2F6F8F;     /* steel blue */

  /* ----- Typography ----- */
  --ct-font-display: 'Crimson Pro', 'Crimson Text', Georgia, serif;
  --ct-font-body:    'Source Sans 3', 'Source Sans Pro', -apple-system, system-ui, sans-serif;

  --ct-font-size-xs:   0.75rem;     /* 12px */
  --ct-font-size-sm:   0.875rem;    /* 14px */
  --ct-font-size-base: 1rem;        /* 16px */
  --ct-font-size-lg:   1.125rem;    /* 18px */
  --ct-font-size-xl:   1.5rem;      /* 24px */
  --ct-font-size-2xl:  2rem;        /* 32px */
  --ct-font-size-3xl:  2.5rem;      /* 40px */

  /* ----- Spacing scale (4px base) ----- */
  --ct-space-1:  0.25rem;
  --ct-space-2:  0.5rem;
  --ct-space-3:  0.75rem;
  --ct-space-4:  1rem;
  --ct-space-5:  1.5rem;
  --ct-space-6:  2rem;
  --ct-space-8:  3rem;
  --ct-space-10: 4rem;

  /* ----- Borders / radii / shadows ----- */
  --ct-radius-sm: 4px;
  --ct-radius:    8px;
  --ct-radius-lg: 12px;
  --ct-radius-pill: 9999px;

  --ct-border:    1px solid var(--ct-grey-light);
  --ct-shadow-sm: 0 1px 2px rgba(26, 26, 26, 0.06);
  --ct-shadow:    0 2px 8px rgba(26, 26, 26, 0.10);
  --ct-shadow-lg: 0 8px 24px rgba(26, 26, 26, 0.14);

  /* ----- Layout ----- */
  --ct-header-height: 64px;
  --ct-sidebar-width: 260px;
  --ct-content-max:   1200px;

  /* ----- Component sizing (plan 20-05 F29 CLS fix) ----- */
  /* Skeleton and card share this token so skeleton→card swap is CLS = 0. */
  --ct-card-min-height: 180px;
}

/* ==========================================================================
   Syncfusion Bootstrap5 theme override block (plan 15-03).
   --------------------------------------------------------------------------
   Bootstrap5 theme exposes its palette via --bs-* CSS custom properties.
   Re-pointing these to CableTow tokens re-themes every Syncfusion component
   without forking the theme. The link order in index.html is:
     1. lib/bootstrap/dist/css/bootstrap.min.css
     2. _content/Syncfusion.Blazor/styles/bootstrap5.css
     3. css/app.css                  ← THIS FILE — overrides win.
   ========================================================================== */

:root {
  --bs-primary:        var(--ct-royal-blue);
  --bs-primary-rgb:    52, 53, 121;
  --bs-secondary:      var(--ct-maroon);
  --bs-secondary-rgb:  125, 34, 72;
  --bs-warning:        var(--ct-gold);
  --bs-warning-rgb:    255, 187, 28;
  --bs-success:        var(--ct-success);
  --bs-success-rgb:    46, 125, 91;
  --bs-danger:         var(--ct-danger);
  --bs-danger-rgb:     181, 61, 61;
  --bs-info:           var(--ct-info);
  --bs-info-rgb:       47, 111, 143;
  --bs-light:          var(--ct-off-white);
  --bs-light-rgb:      250, 247, 242;
  --bs-dark:           var(--ct-near-black);
  --bs-dark-rgb:       26, 26, 26;
  --bs-body-color:     var(--ct-near-black);
  --bs-body-bg:        var(--ct-off-white);
  --bs-link-color:     var(--ct-royal-blue);
  --bs-link-hover-color: var(--ct-blue-dark);
  /* F17-03 (TD F15-M): bumped from --ct-grey-light (#E5E5E5, 1.10:1 vs --ct-off-white)
     to --ct-grey-dark (#4A4A4A, 8.34:1) for WCAG 2.1 AA SC 1.4.11 (non-text 3:1)
     compliance. Drives form-control / form-select / SfTextBox unfocused border.
     Rule P20 deviation: plan brief specified --ct-grey-mid (#999999), but the
     measured ratio of #999999 vs #FAF7F2 is 2.67:1 (the 17-RESEARCH "3.7:1"
     figure was a miscalculation; F15 a11y audit log line 100 records the correct
     2.90:1 — both fail 3:1). --ct-grey-dark is the next-darker palette-approved
     token (declared at line 30 of this file as a primary-palette derivative).
     Focused-state border remains Royal Blue (8.62:1) via .form-control:focus rule.

     TD F17-OD-A (OD audit 2026-05-13 #01 — Bucket V1.x): the declared token chain
     above pins form-input border at 8.28:1 vs #FAF7F2 (FormInputContrastAuditTests
     asserts this). OD audit flagged a potential SF-internal CSS specificity bypass
     concern; runtime DOM verification of .e-input-group computed border-color is
     deferred to V1.x when F15-L Playwright OR F15-N axe-core scaffolding lands.
     If smoke surfaces a real bypass, escalate to V01-must-fix and override at
     .e-input-group:not(.e-success):not(.e-warning):not(.e-error) specificity. */
  --bs-border-color:   var(--ct-grey-dark);

  /* Syncfusion-namespaced variables (defensive override — some components
     read --sf-* directly rather than --bs-*). */
  --sf-primary-color:    var(--ct-royal-blue);
  --sf-primary-bg-color: var(--ct-royal-blue);
  --sf-accent-color:     var(--ct-gold);

  /* F17-07 M2 (TD F17-OD-B — OD audit 2026-05-13 #02): override Syncfusion-internal
     theme tokens to eliminate purple bleed in SfMultiSelect selected-chip background,
     SfDropDownList active-row highlight, SfSwitch on-state track/thumb, and component
     focus rings. The --bs-primary override above catches button surfaces but not all
     SF-internal hardcoded class palettes; these --sf-* tokens close the gap.
     Brand rule: any new SF-internal token discovered driving a purple paint MUST be
     remapped here to a CableTow palette token (royal blue / blue-light / gold / maroon). */
  --sf-primary:          var(--ct-royal-blue);   /* SfMultiSelect chip, primary surfaces */
  --sf-list-active-bg:   var(--ct-blue-light);   /* SfDropDownList active row highlight */
  --sf-switch-on-color:  var(--ct-royal-blue);   /* SfSwitch on-state track + thumb */

  /* F20-02 (F09) — extended Syncfusion purple bleed vectors.
     These tokens cover component-level paint paths NOT caught by the three
     --sf-* tokens above. Royal Blue for primary interactive states; Gold for
     focus rings per brand spec. Sources: batch-5 §5.3, F17 OD audit DOM notes. */
  --sf-chip-bg-color:        var(--ct-royal-blue);   /* SfMultiSelect chip background */
  --sf-chip-border-color:    var(--ct-blue-dark);    /* SfMultiSelect chip border */
  --sf-chip-close-color:     var(--ct-off-white);    /* chips close (×) icon color */
  --sf-active-item-bg:       var(--ct-royal-blue);   /* generic active-row background */
  --sf-active-item-color:    var(--ct-off-white);    /* generic active-row text */
  --sf-tab-active-color:     var(--ct-royal-blue);   /* SfTab active tab text/indicator */
  --sf-grid-active-bg:       var(--ct-blue-light);   /* SfGrid selected/active row */
}

/* F20-03 (F17) — global focus-visible gold ring per WCAG 2.4.11 / 2.4.12.
   Prior plan 17-07 M2 set outline-color only; the full 3px solid gold ring
   is now canonical across every focusable surface (keyboard + switch-access
   users). Outline-offset 2px ensures the ring clears the element's own border.
   border-radius: 4px softens the ring for pill-shaped controls.
   SF form controls that use .e-input-focus (not :focus-visible) are covered
   separately in the SF selector block below. */
:focus-visible {
  outline: 3px solid var(--ct-gold);
  outline-offset: 2px;
  border-radius: 4px;
}

/* F20-02 (F09) — component-level Syncfusion selector overrides.
   Token re-pointing (above) handles most SF surfaces. The selectors below
   target hardcoded class paint that bypasses the token layer entirely.
   Brand rule: only Royal Blue / Blue-Dark / Blue-Light / Gold / Maroon /
   Off-White allowed in these declarations. */

/* SfMultiSelect chips — background, border, and close-button color */
.e-multiselect .e-chips,
.e-multi-select-wrapper .e-chips {
  background: var(--ct-royal-blue);
  border-color: var(--ct-blue-dark);
  color: var(--ct-off-white);
}
.e-multiselect .e-chips .e-chips-close::before,
.e-multi-select-wrapper .e-chips-close.e-close-hooker::before {
  color: var(--ct-off-white);
}

/* SfDropDownList / SfComboBox active/selected row */
.e-dropdownbase .e-list-item.e-active,
.e-dropdownbase .e-list-item.e-active.e-hover {
  background: var(--ct-royal-blue);
  color: var(--ct-off-white);
}

/* SfSwitch on-state — track and handle */
.e-switch-wrapper.e-switch-on .e-switch-inner,
.e-switch-wrapper.e-switch-on .e-switch-handle {
  background: var(--ct-royal-blue);
}

/* SfGrid active/selected row */
.e-grid .e-rowcell.e-active,
.e-grid tr.e-active td.e-rowcell {
  background: var(--ct-blue-light);
  color: var(--ct-off-white);
}

/* SfTab active tab text + indicator */
.e-tab .e-tab-header .e-toolbar-item.e-active .e-tab-text,
.e-tab .e-tab-header .e-toolbar-item.e-active .e-tab-wrap {
  color: var(--ct-royal-blue);
}
.e-tab .e-tab-header .e-indicator {
  background: var(--ct-royal-blue);
}

/* F20-02 (F09) — SF input focus rings → Gold per brand spec (3px, 2px offset).
   SF inputs use .e-input-focus class rather than :focus-visible so they need
   explicit selector coverage here in addition to the global :focus-visible rule. */
.e-input-group.e-input-focus,
.e-input-group.e-control-wrapper.e-input-focus {
  outline: 3px solid var(--ct-gold);
  outline-offset: 2px;
}

/* F20-02 (F12) — Wordmark lockup.
   Single source of truth for every "CableTow" brand text surface.
   Applied via <Wordmark /> component (CableTow.Web/Components/Wordmark.razor).
   clamp() keeps the lockup readable at 320px while not overwhelming at 1440px. */
.ct-wordmark {
  font-family: var(--ct-font-display);
  font-weight: 700;
  letter-spacing: -0.015em;
  font-size: clamp(22px, 2vw, 28px);
  color: var(--ct-off-white);
}

/* Brand-rich variant — gold underline at 80% width, centered under the mark.
   Use on hero / marketing surfaces where extra brand presence is appropriate. */
.ct-wordmark--rich {
  text-decoration: underline;
  text-decoration-color: var(--ct-gold);
  text-decoration-thickness: 3px;
  text-underline-offset: 4px;
}

/*
  TODO(F10): The .ct-admin-sidebar, .admin-nav, .admin-nav-list, .admin-nav-link
  blocks formerly here used !important to work around a Blazor scoped-CSS
  data-attribute mismatch (AdminLayout.razor.css not reaching the DOM as of
  Blazor WASM 10.0.6, observed 2026-05-07). Per plan 20-02 F10 those rules
  have been moved to wwwroot/css/cabletow-overrides.css — an explicit override
  file auditable by name. Re-test cadence: after any Blazor SDK upgrade, verify
  AdminLayout.razor.css scoped rules reach the DOM; if confirmed, the corresponding
  cabletow-overrides.css declarations can be retired. */

/* ==========================================================================
   Base typography — applied globally, inherited by Syncfusion components.
   ========================================================================== */

html, body {
  font-family: var(--ct-font-body);
  color: var(--ct-near-black);
  background: var(--ct-off-white);
  margin: 0;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--ct-font-display);
  color: var(--ct-near-black);
}

h1:focus {
  outline: none;
}

a, .btn-link {
  color: var(--ct-royal-blue);
}

a:hover {
  color: var(--ct-blue-dark);
}

.btn-primary {
  color: var(--ct-off-white);
  background-color: var(--ct-royal-blue);
  border-color: var(--ct-blue-dark);
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem var(--ct-off-white), 0 0 0 0.25rem var(--ct-blue-light);
}

.content {
  padding-top: 1.1rem;
}

.valid.modified:not([type=checkbox]) {
  outline: 1px solid var(--ct-success);
}

.invalid {
  outline: 1px solid var(--ct-maroon);
}

.validation-message {
  color: var(--ct-maroon);
}

#blazor-error-ui {
  color-scheme: light only;
  background: #fff3cd;
  bottom: 0;
  box-shadow: 0 -1px 2px rgba(26, 26, 26, 0.2);
  box-sizing: border-box;
  display: none;
  left: 0;
  padding: 0.6rem 1.25rem 0.7rem 1.25rem;
  position: fixed;
  width: 100%;
  z-index: 1000;
}

#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: 0.75rem;
  top: 0.5rem;
}

.blazor-error-boundary {
  background: var(--ct-maroon);
  padding: 1rem 1rem 1rem 3.7rem;
  color: var(--ct-off-white);
}

.blazor-error-boundary::after {
  content: "An error has occurred."
}

.loading-progress {
  position: absolute;
  display: block;
  width: 8rem;
  height: 8rem;
  inset: 20vh 0 auto 0;
  margin: 0 auto 0 auto;
}

.loading-progress circle {
  fill: none;
  stroke: var(--ct-grey-light);
  stroke-width: 0.6rem;
  transform-origin: 50% 50%;
  transform: rotate(-90deg);
}

.loading-progress circle:last-child {
  stroke: var(--ct-royal-blue);
  stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
  transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
  position: absolute;
  text-align: center;
  font-weight: bold;
  inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

.loading-progress-text:after {
  content: var(--blazor-load-percentage-text, "Loading");
}

code {
  color: var(--ct-maroon);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}

/* ==========================================================================
   App shell — header, content, footer chrome (plan 15-03).
   Used by MainLayout.razor; per-page scoped CSS still works on top.
   ========================================================================== */

.ct-app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.ct-header {
  background: var(--ct-royal-blue);
  color: var(--ct-off-white);
  height: var(--ct-header-height);
  display: flex;
  align-items: center;
  padding: 0 var(--ct-space-5);
  box-shadow: var(--ct-shadow-sm);
}
.ct-header__brand {
  font-family: var(--ct-font-display);
  font-size: var(--ct-font-size-xl);
  font-weight: 700;
  color: var(--ct-off-white);
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: var(--ct-space-3);
}
.ct-header__brand:hover,
.ct-header__brand:focus-visible {
  color: var(--ct-off-white);
  text-decoration: none;
  opacity: 0.92;
}
/* F17-04-05: button-as-nav-link — sign-out and other action verbs in the
   header chrome. Matches the visual treatment of <NavLink> nav items so
   Sign out reads as part of the same control group. */
.ct-header__nav-link--button {
  background: transparent;
  border: 0;
  cursor: pointer;
  font: inherit;
  color: inherit;
  padding: var(--ct-space-2) var(--ct-space-3);
}
.ct-header__nav-link--button:hover,
.ct-header__nav-link--button:focus-visible {
  text-decoration: underline;
}

/* F17-04-07 / F17-04-09 / F20-02 (F10): AdminLayout sidebar gradient + nav links.
   Non-!important fallback declarations. The !important overrides that were
   required to beat a Blazor scoped-CSS data-attribute mismatch (Blazor WASM
   10.0.6, observed 2026-05-07) have been moved to
   wwwroot/css/cabletow-overrides.css per plan 20-02 F10.
   These declarations serve as the plain-specificity fallback for environments
   where the override file wins by load-order rather than !important weight.

   F27 27-08 retest (2026-05-26) — workaround still load-bearing; see the
   .ct-admin-sidebar block in cabletow-overrides.css for the updated
   diagnostic. */
.ct-admin-sidebar {
  background-image: linear-gradient(180deg, var(--ct-royal-blue) 0%, var(--ct-blue-dark) 70%);
}

.admin-nav {
  padding: 1rem 0.5rem;
}
.admin-nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.admin-nav-link {
  display: block;
  padding: 0.7rem 1rem;
  background: var(--ct-royal-blue);
  color: var(--ct-off-white);
  text-decoration: none;
  font-family: var(--ct-font-body);
  font-size: 0.975rem;
  font-weight: 600;
  border: 1px solid rgba(250, 247, 242, 0.18);
  border-radius: var(--ct-radius-sm);
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.admin-nav-link:hover,
.admin-nav-link:focus-visible {
  background-color: var(--ct-blue-dark);
  border-color: var(--ct-gold);
  color: var(--ct-off-white);
}
.admin-nav-link.active {
  background-color: var(--ct-blue-dark);
  color: var(--ct-gold);
  border-color: var(--ct-gold);
}

.admin-back-link {
  color: var(--ct-off-white);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.95rem;
  padding: var(--ct-space-2) var(--ct-space-3);
  border: 1px solid rgba(250, 247, 242, 0.4);
  border-radius: var(--ct-radius-sm);
  white-space: nowrap;
}
.admin-back-link:hover,
.admin-back-link:focus-visible {
  color: var(--ct-off-white);
  background-color: rgba(255, 187, 28, 0.15);
  border-color: var(--ct-gold);
  text-decoration: none;
}

.admin-hero-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
}
.ct-header__logo {
  width: 36px;
  height: 36px;
  border-radius: var(--ct-radius-sm);
  background: var(--ct-gold);
  color: var(--ct-royal-blue);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-family: var(--ct-font-display);
}
.ct-header__nav {
  margin-left: auto;
  display: flex;
  gap: var(--ct-space-4);
  align-items: center;
}
.ct-header__nav a {
  color: var(--ct-off-white);
  font-weight: 600;
  padding: var(--ct-space-2) var(--ct-space-3);
  border-radius: var(--ct-radius-sm);
  text-decoration: none;
}
.ct-header__nav a:hover {
  background: var(--ct-blue-dark);
  text-decoration: none;
  color: var(--ct-off-white);
}
.ct-header__nav a.active {
  background: var(--ct-blue-dark);
  border-bottom: 2px solid var(--ct-gold);
}

.ct-main {
  flex: 1;
  padding: var(--ct-space-6) var(--ct-space-5);
  max-width: var(--ct-content-max);
  width: 100%;
  margin: 0 auto;
}

.ct-footer {
  background: var(--ct-near-black);
  color: var(--ct-off-white);
  padding: var(--ct-space-4) var(--ct-space-5);
  font-size: var(--ct-font-size-sm);
  text-align: center;
}
.ct-footer a { color: var(--ct-gold); }

/* ==========================================================================
   F16 FOLD-IN — Unified-nav infrastructure (plan 15-03 Task 3.1).
   --------------------------------------------------------------------------
   Vertical divider between volunteer / organizer / account nav sections at
   desktop. Renders empty in F15 (no organizer items yet); F16 adds them
   inside an <AuthorizeView Policy="LodgeOfficer"> block.
   ========================================================================== */

.nav-divider {
  width: 1px;
  height: 28px;
  background: var(--ct-blue-light);
  margin: 0 var(--ct-space-3);
  align-self: center;
  display: inline-block;
}

/* Mobile: hamburger surface — section headers (Volunteer / Organizer / Account).
   F15 renders only Volunteer + Account; F16 adds Organizer. The header
   primitive ships now so F16 inherits the styling without touching the shell. */
.ct-mobile-nav {
  display: none;
}
.ct-mobile-nav__section-heading {
  font-family: var(--ct-font-display);
  font-size: var(--ct-font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ct-gold);
  padding: var(--ct-space-3) var(--ct-space-4) var(--ct-space-1);
  margin: 0;
  font-weight: 700;
}
.ct-mobile-nav__divider {
  border: none;
  border-top: 1px solid var(--ct-blue-dark);
  margin: var(--ct-space-2) 0;
}

/* ==========================================================================
   F16 FOLD-IN — Reserved .lodge-affiliation header slot (plan 15-03 Task 3.2).
   --------------------------------------------------------------------------
   Positioned right of the wordmark, left of nav. Renders empty in F15;
   F16 populates with badges like "WM · South Bend No. 294".
   ========================================================================== */

.lodge-affiliation {
  display: inline-flex;
  align-items: center;
  gap: var(--ct-space-2);
  padding: var(--ct-space-1) var(--ct-space-3);
  background: var(--ct-blue-dark);
  border: 1px solid var(--ct-gold);
  border-radius: var(--ct-radius-pill);
  font-size: var(--ct-font-size-xs);
  font-weight: 600;
  color: var(--ct-off-white);
  margin-left: var(--ct-space-3);
}
.lodge-affiliation:empty {
  display: none; /* hide the slot entirely when F15 leaves it empty */
}

/* ==========================================================================
   F16 FOLD-IN — Avatar primitive (plan 15-03 Task 3.3).
   --------------------------------------------------------------------------
   <Avatar UserId="@id" Size="Sm|Md|Lg" /> renders initials in a coloured
   disc. F15 uses it in the header user menu; F16 uses it heavily in the
   parts-roster table. CSS lives in app.css so the Razor file stays minimal.
   ========================================================================== */

.ct-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--ct-blue-light);
  color: var(--ct-off-white);
  font-family: var(--ct-font-body);
  font-weight: 700;
  text-transform: uppercase;
  flex-shrink: 0;
  user-select: none;
}
.ct-avatar--sm { width: 24px; height: 24px; font-size: 10px; }
.ct-avatar--md { width: 32px; height: 32px; font-size: 12px; }
.ct-avatar--lg { width: 48px; height: 48px; font-size: 18px; }

/* ==========================================================================
   F16 FOLD-IN — Shared brand panels (plan 15-03 Task 3.5).
   --------------------------------------------------------------------------
   .ct-panel--brand   = Royal-Blue bg, off-white text. Hero/summary panels.
   .ct-panel--inverse = Near-black bg, off-white text. Emphasis panels
                        (e.g., F16 broadcast composer match-preview).
   F15 ships them; F16 consumes them.
   ========================================================================== */

.ct-panel {
  border-radius: var(--ct-radius);
  padding: var(--ct-space-5);
}
.ct-panel--brand {
  background: var(--ct-royal-blue);
  color: var(--ct-off-white);
}
.ct-panel--brand h1,
.ct-panel--brand h2,
.ct-panel--brand h3,
.ct-panel--brand h4 {
  color: var(--ct-off-white);
}
.ct-panel--inverse {
  background: var(--ct-near-black);
  color: var(--ct-off-white);
}
.ct-panel--inverse h1,
.ct-panel--inverse h2,
.ct-panel--inverse h3,
.ct-panel--inverse h4 {
  color: var(--ct-off-white);
}
.ct-panel--inverse a { color: var(--ct-gold); }

/* ==========================================================================
   F16 FOLD-IN — Status pill system (plan 15-03 Task 3.6).
   --------------------------------------------------------------------------
   <StatusPill State="@state" /> renders a pill with .status-pill--{state}.
   Palette restricted to: Royal Blue, Gold, Maroon, Grey-mid + token tints.
   NO reds, NO oranges, NO purples. Cancelled = Maroon (destructive accent).

   State → color mapping (audit-friendly, brand-faithful):
     Pending        → Gold   bg, Near-black text   (awaiting action)
     Approved       → Success bg, off-white text   (positive terminal)
     Rejected       → Maroon bg, off-white text    (negative terminal)
     Draft          → Grey-light bg, Grey-dark text (pre-publish)
     Published      → Royal-Blue bg, off-white text (active broadcast)
     InProgress     → Gold-dark bg, off-white text  (work underway)
     Completed      → Royal-Blue bg, off-white text (positive terminal)
     Cancelled      → Maroon bg, off-white text     (destructive terminal)
     Confirmed      → Success bg, off-white text    (volunteer locked in)
     OpenToNetwork  → Gold bg, Near-black text      (visible in feed)
   ========================================================================== */

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--ct-space-1);
  padding: 2px var(--ct-space-3);
  border-radius: var(--ct-radius-pill);
  background: var(--ct-grey-light);
  color: var(--ct-near-black);
  font-size: var(--ct-font-size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.6;
}

/* F20-03 (F18) — icon alignment within each pill. The icon is inline SVG
   rendered at 12×12px; flex + flex-shrink:0 keeps it from collapsing. */
.status-pill__icon {
  flex-shrink: 0;
  vertical-align: middle;
}
.status-pill--pending       { background: var(--ct-gold);       color: var(--ct-near-black); }
.status-pill--approved      { background: var(--ct-success);    color: var(--ct-off-white); }
.status-pill--rejected      { background: var(--ct-maroon);     color: var(--ct-off-white); }
.status-pill--draft         { background: var(--ct-grey-light); color: var(--ct-grey-dark); }
.status-pill--published     { background: var(--ct-royal-blue); color: var(--ct-off-white); }
.status-pill--inprogress    { background: var(--ct-gold-dark);  color: var(--ct-off-white); }
.status-pill--completed     { background: var(--ct-royal-blue); color: var(--ct-off-white); }
.status-pill--cancelled     { background: var(--ct-maroon);     color: var(--ct-off-white); }
.status-pill--confirmed     { background: var(--ct-success);    color: var(--ct-off-white); }
.status-pill--opentonetwork { background: var(--ct-gold);       color: var(--ct-near-black); }

/* ==========================================================================
   Badges — small numeric counters (e.g. unread Messages count).
   ========================================================================== */

.ct-badge {
  display: inline-block;
  min-width: 20px;
  padding: 0 6px;
  border-radius: var(--ct-radius-pill);
  background: var(--ct-maroon);
  color: var(--ct-off-white);
  font-size: var(--ct-font-size-xs);
  font-weight: 700;
  text-align: center;
  line-height: 20px;
  margin-left: var(--ct-space-1);
}

/* ==========================================================================
   F17-07 M3 (TD F17-OD-C — OD audit 2026-05-13 #03): mobile nav touch targets.
   WCAG 2.1 AA SC 2.5.5 — interactive targets ≥ 44×44px at mobile breakpoint.
   Applies at ≤md (Bootstrap5 md = 768px). Targets: hamburger toggle (always
   mobile-only via d-md-none) plus every NavLink / button inside the mobile
   drawer (.ct-mobile-nav__link). The .ct-mobile-touch-target marker class is
   carried by the elements; tests assert presence via class-list inspection.
   Hit area is intentionally generous (padding 10px 16px) so the focus ring
   has room to render around the hit target without clipping.
   ========================================================================== */

.ct-nav-toggle,
.ct-mobile-nav__link {
  min-height: 44px;
  min-width: 44px;
  padding: 10px 16px;
  display: inline-flex;
  align-items: center;
}

/* Desktop nav (.d-md-flex) stays untouched — desktop touch targets already
   comfortably exceed 44×44px (header chrome height + nav padding). M3 scope
   is surgical mobile-only per plan Anti-Goals. */

/* ==========================================================================
   F17-07 M5 (TD F17-OD-H — OD audit 2026-05-13 #09): AvailabilityTab grid
   keyboard focus ring. WCAG 2.4.7 (Focus Visible) + 2.1.1 (Keyboard).
   Gold focus ring per a11y spec — 2px solid #FFBB1C with 2px offset so the
   ring sits clear of the cell's existing 1px border. Outline-style: solid
   so reduced-motion + high-contrast modes render the affordance identically.
   Scoped to [role="gridcell"] under the AvailabilityTab grid to avoid
   blanket-overriding the global :focus-visible blue ring on other surfaces.
   ========================================================================== */

.ct-day-pattern[role="grid"] [role="gridcell"]:focus-visible {
  outline: 2px solid var(--ct-gold);
  outline-offset: 2px;
}

/* ==========================================================================
   Plan 17-08 (OD audit #07 / TD F17-OD-F) — ToastStack + Toast entries.
   --------------------------------------------------------------------------
   BRAND AUDIT CONSTRAINTS (pinned by ToastStackTests brand audit assertion):
     - NO pure white #FFFFFF — use #FAF7F2 (--ct-off-white) for light-bg text
     - NO pure black #000000 — use #1A1A1A (--ct-near-black) for info bg
     - NO purple/violet — forbidden by CLAUDE.md brand rules
   Severity palette:
     info    → background: --ct-near-black (#1A1A1A)
     success → background: --ct-royal-blue (#343579)
     warning → background: --ct-gold       (#FFBB1C), text: --ct-near-black
     error   → background: --ct-maroon     (#7D2248), NEVER red, NEVER purple
   ========================================================================== */

.ct-toast-stack {
  position: fixed;
  top: calc(var(--ct-header-height, 64px) + var(--ct-space-3));
  right: var(--ct-space-4);
  width: 320px;
  z-index: 9000;
  display: flex;
  flex-direction: column;
  gap: var(--ct-space-2);
  pointer-events: none;
}

.ct-toast {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--ct-space-3);
  padding: var(--ct-space-2) var(--ct-space-4);
  border-radius: var(--ct-radius-sm);
  box-shadow: var(--ct-shadow);
  pointer-events: all;
  font-size: var(--ct-font-size-sm);
}

/* Severity backgrounds — approved palette tokens only */
.ct-toast--info    { background: var(--ct-near-black); }
.ct-toast--success { background: var(--ct-royal-blue); }
.ct-toast--warning { background: var(--ct-gold); }
.ct-toast--error   { background: var(--ct-maroon); }

/* Text color variants */
.ct-toast__text--light { color: var(--ct-off-white); }
.ct-toast__text--dark  { color: var(--ct-near-black); }

.ct-toast__message {
  flex: 1;
}

.ct-toast__actions {
  display: flex;
  align-items: center;
  gap: var(--ct-space-2);
  flex-shrink: 0;
}

.ct-toast__undo {
  background: transparent;
  border: 1px solid currentColor;
  padding: var(--ct-space-1) var(--ct-space-3);
  border-radius: var(--ct-radius-sm);
  font-size: var(--ct-font-size-xs);
  cursor: pointer;
  line-height: 1.4;
}

.ct-toast__dismiss {
  background: transparent;
  border: none;
  font-size: var(--ct-font-size-lg);
  cursor: pointer;
  line-height: 1;
  padding: 0 var(--ct-space-1);
  opacity: 0.8;
}

.ct-toast__dismiss:hover,
.ct-toast__undo:hover {
  opacity: 1;
}

/* ==========================================================================
   Plan 17-08 (OD audit #08 / TD F17-OD-G) — LoadingSpinner + SkeletonBlock.
   --------------------------------------------------------------------------
   Spinner: SVG arc rotates via ct-spin keyframe. Stroke uses --ct-royal-blue.
   ARIA contract: role="status" aria-live="polite" always present.
   ========================================================================== */

@keyframes ct-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

.ct-spinner {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ct-spinner--small  { width: 16px;  height: 16px; }
.ct-spinner--medium { width: 32px;  height: 32px; display: flex; }
.ct-spinner--large  { width: 48px;  height: 48px; display: flex; }

/* Medium and Large are block-centered */
.ct-spinner--medium,
.ct-spinner--large {
  margin: var(--ct-space-4) auto;
}

.ct-spinner__svg {
  width: 100%;
  height: 100%;
  animation: ct-spin 0.9s linear infinite;
}

/* Skeleton block */
.ct-skeleton-block {
  display: flex;
  flex-direction: column;
}

.ct-skeleton-block__row {
  background: var(--ct-grey-light);
  border-radius: var(--ct-radius-sm);
}

/* ==========================================================================
   Plan 17-09 (OD audit #10 / TD F17-OD-I) — EmptyState shared shell.
   --------------------------------------------------------------------------
   BRAND AUDIT CONSTRAINTS (pinned by BroadcastFeedEmptyStateTests /
   MyClaimsEmptyStateTests / PlanListEmptyStateTests brand assertion):
     - Illustration color: var(--ct-royal-blue) (#343579) — monochrome SVG
     - Heading: Crimson Pro 24px, --ct-royal-blue
     - Body: Source Sans 3 16px, --ct-grey-dark
     - NO purple, NO pure white (#FFFFFF), NO pure black (#000000)
   ========================================================================== */

.ct-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--ct-space-8) var(--ct-space-4);
  max-width: 480px;
  margin: 0 auto;
  color: var(--ct-royal-blue);
}

.ct-empty-state__illustration {
  width: 120px;
  height: 120px;
  margin-bottom: var(--ct-space-5);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ct-empty-state__illustration img,
.ct-empty-state__illustration svg {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.ct-empty-state__heading {
  font-family: var(--ct-font-display);
  font-size: var(--ct-font-size-xl);  /* 24px */
  color: var(--ct-royal-blue);
  margin: 0 0 var(--ct-space-3) 0;
  line-height: 1.25;
}

.ct-empty-state__body {
  font-family: var(--ct-font-body);
  font-size: var(--ct-font-size-base);  /* 16px */
  color: var(--ct-grey-dark);
  margin: 0 0 var(--ct-space-5) 0;
  line-height: 1.55;
}

/* ==========================================================================
   F20-03 (F23) — SfDialog responsive sizing (plain-specificity fallback).
   --------------------------------------------------------------------------
   Hard-coded Width="420px" on SfDialog components overflows the viewport on
   390px iPhone viewports. Plain-specificity rule here; !important version in
   cabletow-overrides.css beats any SF-internal inline style.
   Below 480px the dialog anchors to the bottom as a bottom-sheet pattern.
   See cabletow-overrides.css for the !important counterparts.
   ========================================================================== */

.e-dialog {
  max-width: min(560px, calc(100vw - 32px));
  width: auto;
}

@media (max-width: 479px) {
  .e-dialog {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    top: auto;
    max-width: 100%;
    width: 100%;
    border-radius: var(--ct-radius-lg) var(--ct-radius-lg) 0 0;
    transform: none;
  }
  .e-dlg-overlay {
    align-items: flex-end;
  }
}

/* ==========================================================================
   F20-03 (F25) — Reduced-motion preference (plain-specificity fallback).
   --------------------------------------------------------------------------
   WCAG 2.3.3 / widely supported best-practice. Sets transition and animation
   durations to 0.01ms when the user has requested reduced motion. The
   !important counterparts live in cabletow-overrides.css so user-preference
   overrides component-scoped CSS as intended. The plain declarations here
   are the fallback for elements that don't receive scoped CSS.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    transition-duration: 0.01ms;
    scroll-behavior: auto;
  }
}

/* ==========================================================================
   F20-04 (F26) — LoginPage inline auth links in error banners.
   --------------------------------------------------------------------------
   auth-banner-error uses dark bg tint; links need visible color.
   ========================================================================== */

.auth-link {
  color: var(--ct-royal-blue);
  font-weight: 600;
  text-decoration: underline;
}

/* ==========================================================================
   F20-04 (F20) — PlanLifecycleShell unified template.
   --------------------------------------------------------------------------
   Shared lifecycle-page chrome. Notification preview strip.
   ========================================================================== */

.ct-lifecycle-explainer {
  margin: var(--ct-space-4) 0;
}

.ct-lifecycle-notify-preview {
  font-size: var(--ct-font-size-sm);
  color: var(--ct-grey-dark);
  margin: var(--ct-space-3) 0 var(--ct-space-4) 0;
  padding: var(--ct-space-2) var(--ct-space-3);
  background: rgba(52, 53, 121, 0.05);
  border-radius: var(--ct-radius-sm);
}

/* ==========================================================================
   F20-04 (F32) — PrivacyStrip shared component.
   --------------------------------------------------------------------------
   Trust-surface notice. Appears at: signup form, profile wizard Step 4,
   MessageThread header. Lock icon + copy pattern.
   Colors: royal-blue border-left, near-black copy, no purple.
   ========================================================================== */

.ct-privacy-strip {
  display: flex;
  align-items: flex-start;
  gap: var(--ct-space-2);
  padding: var(--ct-space-2) var(--ct-space-3);
  background: rgba(52, 53, 121, 0.05);
  border-left: 3px solid var(--ct-royal-blue);
  border-radius: 0 var(--ct-radius-sm) var(--ct-radius-sm) 0;
  margin: var(--ct-space-3) 0;
  font-size: var(--ct-font-size-sm);
  color: var(--ct-near-black);
}

.ct-privacy-strip__icon {
  color: var(--ct-royal-blue);
  flex-shrink: 0;
  margin-top: 2px;
}

.ct-privacy-strip__copy {
  line-height: 1.45;
}

/* ==========================================================================
   F20-04 (F33) — Role chips on sender names.
   --------------------------------------------------------------------------
   Small inline chips that identify officers (gold) and admins (maroon).
   Used in MessageThread header next to sender names.
   Sizes: compact pill shape; never purple; uses approved palette only.
   ========================================================================== */

.ct-role-chip {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  border-radius: 999px;
  font-family: var(--ct-font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1.6;
  vertical-align: middle;
}

/* Gold chip for current lodge officers */
.ct-role-chip--officer {
  background: rgba(255, 187, 28, 0.2);
  color: var(--ct-near-black);
  border: 1px solid var(--ct-gold);
}

/* Maroon chip for admins */
.ct-role-chip--admin {
  background: rgba(125, 34, 72, 0.1);
  color: var(--ct-maroon);
  border: 1px solid rgba(125, 34, 72, 0.3);
}

/* Royal-blue-light chip for regular members */
.ct-role-chip--member {
  background: rgba(92, 93, 165, 0.1);
  color: var(--ct-royal-blue);
  border: 1px solid rgba(92, 93, 165, 0.3);
}

/* ==========================================================================
   F20-04 (F34) — InstallBanner soft PWA install prompt.
   --------------------------------------------------------------------------
   Visible install banner for post-approval landing. Royal-blue left accent,
   gold CTA. Never purple. Dismissable. 14-day throttle via localStorage.
   ========================================================================== */

.ct-install-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ct-space-3);
  padding: var(--ct-space-3) var(--ct-space-4);
  background: var(--ct-royal-blue);
  color: var(--ct-off-white);
  border-radius: var(--ct-radius);
  margin: var(--ct-space-4) 0;
  flex-wrap: wrap;
}

.ct-install-banner__content {
  display: flex;
  align-items: center;
  gap: var(--ct-space-3);
  flex: 1;
  min-width: 0;
}

.ct-install-banner__icon {
  flex-shrink: 0;
  color: var(--ct-gold);
}

.ct-install-banner__copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--ct-font-size-sm);
}

.ct-install-banner__copy strong {
  font-size: var(--ct-font-size-base);
}

.ct-install-banner__actions {
  display: flex;
  align-items: center;
  gap: var(--ct-space-2);
  flex-shrink: 0;
}

.ct-install-banner__btn--primary {
  /* !important counterpart lives in cabletow-overrides.css to beat SF Blazor inline styles. */
  font-weight: 600;
}

.ct-install-banner__dismiss {
  background: transparent;
  border: none;
  color: var(--ct-off-white);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: var(--ct-space-1);
  opacity: 0.7;
}

.ct-install-banner__dismiss:hover { opacity: 1; }

/* Avatar role dot — small dot overlay for Avatar component */
.ct-avatar--role-dot {
  position: relative;
}
.ct-avatar--role-dot::after {
  content: '';
  position: absolute;
  bottom: 0;
  right: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--ct-off-white);
  background: var(--ct-gold);
}
