/* RoadCoach Admin -- canonical stylesheet (Docs/Design/UI-STANDARDS.md).
   Tokens live in :root; every component reads them via var(--token), never a hardcoded brand hex,
   so changing a token here (or flipping [data-accent] on <body>) reskins the whole site.

   TWO-TIER TOKENS (THEME-DESIGNER-PLAN.md Phase A1): every component FAMILY below reads its OWN
   token (e.g. --btn-bg), and with no override set anywhere every component-family token resolves to
   the exact value it read directly before this refactor -- the render is pixel-identical. The
   Phase C editor generates its per-object controls FROM the TOKEN MAP below, so keep the map's
   format machine readable: exactly one token per line, `--token-name | color|size | what it
   controls`.

   TWO KINDS OF TOKEN, TWO DECLARATION SHAPES (read this before adding a token -- a real CSS
   browser-behavior gotcha, verified against a live Chromium render while building this refactor):
   1. LITERAL-DEFAULT tokens (a fixed px size or hex with no other token behind it, e.g.
      --input-font-size, --stat-value-size) ARE declared in :root below with their literal value,
      and components read them with a plain var(--token).
   2. DERIVED tokens (their "default" IS another token, e.g. --btn-bg defaults to --accent) are
      DELIBERATELY NOT declared in :root. A CSS custom property that is only ever declared once
      (e.g. `--btn-bg: var(--accent);` at :root) gets that var() substituted ONCE, using :root's
      OWN --accent, and children then inherit the already-frozen result -- a LATER override of
      --accent on a descendant (a [data-accent] block on <body>, or a future per-school/per-theme
      override) would NOT reach it, because inheritance propagates the resolved value, not the
      formula. The fix is the standard var()-fallback idiom: the CONSUMING rule reads
      `var(--btn-bg, var(--accent))` directly -- if --btn-bg was never set anywhere, the fallback
      var(--accent) is evaluated fresh, at THIS element, walking its own live ancestor chain, so it
      correctly tracks whatever the nearest [data-accent] (or future saved-theme) override is. If a
      later Phase C control DOES set --btn-bg (at any scope), that explicit value wins over the
      fallback, exactly as a per-object override should. Do not "fix" this by pre-declaring a
      derived token in :root -- that reintroduces the freeze bug.

   TOKEN MAP -- do not hand-edit tokens without updating this map; SiteCssCatalogTests proves every
   mapped token is actually wired into the file (a :root declaration for literal tokens, or a
   var(--token, ...) fallback consumption for derived tokens) so the map and the CSS never drift.

   -- Brand semantic layer (SUP-007, SUPPORTABILITY-PLAN.md sec 6 decision D4) --
   -- ~6-10 master tokens ABOVE the family tokens below. A subset of the family tokens (the ones
   -- that make up "the school's look": buttons, info badges, active chips/sidebar links, card/
   -- input/chip surfaces and borders, card radius) fall back to ONE of these instead of falling
   -- back to a base global directly, so a full rebrand is a handful of edits instead of touching
   -- every base global (--bg/--surface/--surface-2/--text/--text-dim/--border/--accent/--accent-
   -- weak/--accent-contrast/--radius) independently. LITERAL-default like the base globals below
   -- (see "TWO KINDS OF TOKEN" above) -- NOT derived from --accent/--surface/etc, so they cannot
   -- freeze. Each [data-accent] block further down ALSO sets --brand-primary/-weak alongside
   -- --accent/-weak so per-school template switching keeps reskinning Brand-fallback components
   -- exactly as it does today; --brand-primary-contrast/--brand-surface/--brand-surface-2/
   -- --brand-text/--brand-border/--brand-radius do not vary by template, same as --accent-contrast/
   -- --surface/--surface-2/--text/--border/--radius do not today.
   --brand-primary | color | master brand accent -- btn-bg, badge-info-fg, chip-active-bg/border, sidebar-active-fg fall back to this
   --brand-primary-weak | color | tinted master brand background -- badge-info-bg, sidebar-active-bg fall back to this
   --brand-primary-contrast | color | text/icon color on brand-primary -- btn-fg, chip-active-fg fall back to this
   --brand-surface | color | master card/panel surface -- card-bg falls back to this
   --brand-surface-2 | color | master secondary surface -- input-bg, table-header-bg, table-row-hover-bg, chip-bg, badge-neutral-bg fall back to this
   --brand-text | color | master brand text tone -- chip-fg falls back to this
   --brand-border | color | master hairline border -- card-border, input-border, chip-border fall back to this
   --brand-radius | size | master corner radius -- card-radius falls back to this

   -- Base globals (Docs/Design/UI-STANDARDS.md) --
   --bg | color | page background
   --surface | color | card/panel background
   --surface-2 | color | secondary surface (hover states, input backgrounds, table headers)
   --text | color | primary text
   --text-dim | color | secondary/muted text
   --border | color | hairline borders
   --accent | color | brand accent (buttons, links, active states) -- swapped by [data-accent]
   --accent-weak | color | tinted accent background (badges, hover glow) -- swapped by [data-accent]
   --accent-contrast | color | text/icon color rendered on top of --accent
   --radius | size | default corner radius

   -- Status colors (fixed, NOT accent-themed per UI-STANDARDS.md) --
   --status-success | color | success text/icon
   --status-success-bg | color | success tinted background
   --status-warning | color | warning text/icon
   --status-warning-bg | color | warning tinted background
   --status-error | color | error text/icon
   --status-error-bg | color | error tinted background
   --status-neutral | color | neutral/muted status text
   --status-beta | color | beta status text/icon
   --status-beta-bg | color | beta tinted background

   -- Buttons --
   --btn-bg | color | primary button background
   --btn-fg | color | primary button text

   -- Inputs / select / textarea --
   --input-font-size | size | input, select, and textarea text size
   --input-border | color | input, select, and textarea border color
   --input-bg | color | input, select, and textarea background

   -- Labels --
   --label-size | size | form label text size
   --label-color | color | form label text color

   -- Cards --
   --card-bg | color | .rc-card background
   --card-border | color | .rc-card border color
   --card-radius | size | .rc-card corner radius

   -- Tables --
   --table-header-bg | color | table header row background
   --table-row-hover-bg | color | table body row hover background

   -- Badges (per-variant; status variants default to the fixed status tokens above, not accent) --
   --badge-success-bg | color | success badge background
   --badge-success-fg | color | success badge text
   --badge-warning-bg | color | warning badge background
   --badge-warning-fg | color | warning badge text
   --badge-high-bg | color | high-priority badge background
   --badge-high-fg | color | high-priority badge text
   --badge-error-bg | color | error badge background
   --badge-error-fg | color | error badge text
   --badge-info-bg | color | info badge background (accent-tinted)
   --badge-info-fg | color | info badge text (accent)
   --badge-neutral-bg | color | neutral badge background
   --badge-neutral-fg | color | neutral badge text
   --badge-beta-bg | color | beta badge background
   --badge-beta-fg | color | beta badge text

   -- Chips --
   --chip-bg | color | chip background
   --chip-fg | color | chip text
   --chip-border | color | chip border color
   --chip-active-bg | color | selected chip background (accent)
   --chip-active-fg | color | selected chip text (accent-contrast)

   -- Banners --
   --banner-success-bg | color | success banner background
   --banner-success-fg | color | success banner text
   --banner-error-fg | color | error banner text
   --banner-error-border | color | error banner border

   -- Stat tiles --
   --stat-value-size | size | stat tile headline number size

   -- Sidebar (rule + var(--token, fallback) consumption both live in sidebar.css) --
   --sidebar-active-bg | color | active sidebar link background (accent-tinted)
   --sidebar-active-fg | color | active sidebar link text (accent)
*/

:root {
    --bg: #f4f6f9;
    --surface: #ffffff;
    --surface-2: #eef2f7;
    --text: #0e2238;
    --text-dim: #5d6e80;
    --border: #e0e6ee;
    /* TASK-WEB-A11Y-001: darkened from #e8621c (same hue/saturation, lower lightness only -- WCAG
       AA 4.5:1 requires it). #e8621c measured 3.39:1 for accent-colored text on white/page bg and
       3.39:1 for white text on an accent button background -- both fail. #a64411 clears every
       usage this token feeds (wordmark text, plain links, sidebar-active fg on --accent-weak,
       button fg/bg, chip-active) with a >=5.2:1 margin on all of them -- picked with headroom, not
       the bare 4.5:1 minimum, after a live axe rerun showed one specific badge instance (a table's
       LAST row, near the flush card's rounded-corner overflow clip) rendering against a slightly
       different effective background than the other rows despite IDENTICAL computed CSS
       (getComputedStyle confirmed identical color/background-color/opacity on all three) -- axe's
       contrast check evidently samples more than the immediate ancestor chain in that geometry, so
       every status/accent token below now targets ~5.2-5.6:1 rather than the theoretical 4.5:1
       floor. See Docs/A11Y-BASELINE.md for the finding this fixes. */
    --accent: #a64411;
    --accent-weak: #fdeadd;
    --accent-contrast: #ffffff;
    --radius: 12px;

    /* ---- Brand semantic layer (SUP-007 D4): LITERAL-default master tokens, deliberately NOT
       derived from --accent/--surface/etc (see the TOKEN MAP note above and the "TWO KINDS OF
       TOKEN" note). Defaults match the base globals they stand in for so this refactor moves zero
       pixels on the platform default; [data-accent] blocks below keep --brand-primary/-weak in
       lockstep with --accent/--accent-weak per template. ---- */
    /* TASK-WEB-A11Y-001: kept in lockstep with --accent above (same darkened value; SUP-007's own
       rule -- see the block above [data-accent] further down). */
    --brand-primary: #a64411;
    --brand-primary-weak: #fdeadd;
    --brand-primary-contrast: #ffffff;
    --brand-surface: #ffffff;
    --brand-surface-2: #eef2f7;
    --brand-text: #0e2238;
    --brand-border: #e0e6ee;
    --brand-radius: 12px;

    /* TASK-WEB-A11Y-001: success/warning/error darkened (same hue/saturation, lower lightness
       only) -- each one is used BOTH as text on a light tint background (badge fg on its own
       *-bg tint) AND as white text on a solid background (system-health banner/pill) AND as plain
       text on the page background (verdict/summary text) -- the *-bg rgba literals below are
       updated to the SAME new RGB (alpha unchanged) so a badge's own tint stays derived from its
       fg color, not stale. Old values: success #16a34a, warning #d97706, error #e11d48 -- all
       measured serious color-contrast failures in Docs/A11Y-BASELINE.md. Targeted at >=5.2:1 (not
       the 4.5:1 floor) against the WORST-case tint background (the tint blended over --bg #f4f6f9,
       not just --surface #ffffff) -- see the --accent comment above for why the extra margin: a
       live axe rerun flagged one specific badge instance despite pixel-identical computed CSS to
       its passing siblings, and the larger margin made that instance clean too without having to
       fully root-cause axe's exact sampling geometry. */
    --status-success: #0e6930;
    --status-success-bg: rgba(14, 105, 48, .12);
    --status-warning: #884a04;
    --status-warning-bg: rgba(136, 74, 4, .14);
    --status-error: #b01738;
    --status-error-bg: rgba(176, 23, 56, .12);
    --status-neutral: #5d6e80;
    /* TASK-WEB-A11Y-001: darkened from #8b5cf6 (same hue/saturation) -- missed in the first pass of
       this ticket's fix (the seed-data admin-users scan never rendered a beta badge; a full-suite
       gate run at realistic user volume did). badge-beta-fg on its own tint background measured
       well under 4.5:1 with the old value; #5e1df2 clears >=5.2:1 everywhere the same way the other
       three status colors do. */
    --status-beta: #5e1df2;
    --status-beta-bg: rgba(94, 29, 242, .14);

    /* ---- Component-family tokens (two-tier refactor): LITERAL-default tokens only -- see the
       "TWO KINDS OF TOKEN" note above. Every DERIVED token (--btn-bg, --card-bg, --badge-*-bg/-fg,
       --chip-*, --banner-*, --sidebar-active-*, --input-border, --input-bg, --label-color,
       --card-border, --card-radius, --table-*) is deliberately NOT declared here; it is consumed
       via var(--token, var(--fallback)) directly at its component rule instead. ---- */
    --input-font-size: 14px;
    --label-size: 12.5px;
    --badge-high-bg: #ffedd5;
    --badge-high-fg: #c2410c;
    --stat-value-size: 30px;
}

/* SUP-007: each block also sets --brand-primary/-weak to the SAME value as --accent/-weak so
   template switching keeps reskinning the Brand-fallback family tokens (btn-bg, badge-info,
   chip-active, sidebar-active) exactly as it did before the Brand layer existed. */
[data-accent="orange"] { --accent: #a64411; --accent-weak: #fdeadd; --brand-primary: #a64411; --brand-primary-weak: #fdeadd; }
[data-accent="navy"] { --accent: #02284a; --accent-weak: #dde6f1; --brand-primary: #02284a; --brand-primary-weak: #dde6f1; }
[data-accent="sky"] { --accent: #1893c4; --accent-weak: #e0f3fb; --brand-primary: #1893c4; --brand-primary-weak: #e0f3fb; }
[data-accent="green"] { --accent: #6b9d1f; --accent-weak: #eef5dd; --brand-primary: #6b9d1f; --brand-primary-weak: #eef5dd; }

/* ---- Reset / base ---- */

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
    font-family: 'Inter', system-ui, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
}

h1, h2, h3 { letter-spacing: -0.02em; font-weight: 800; }
h1 { font-size: 22px; margin-bottom: 16px; }
h2 { font-size: 18px; margin-bottom: 12px; }
h3 { font-size: 15px; margin-bottom: 8px; }
a { color: var(--accent); }

/* TASK-WEB-A11Y-001 (page-has-heading-one): lessons-create and feedback-submit used a bare <h2> as
   their ONLY heading, skipping level 1 (axe: moderate). Standard visually-hidden/"sr-only" clip
   technique -- the element stays in the accessibility tree (screen readers announce it, axe counts
   it as a real level-one heading) but is clipped to 1x1px and off the visual flow, so sighted users
   see no change at all. Used to add a real <h1> next to an existing, unchanged, visible <h2> instead
   of re-leveling the visible heading (see the comment in Pages/Lessons/Create.cshtml for why:
   dozens of existing Playwright specs wait on/assert "h2" for these exact pages). */
.rc-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---- Header / nav ---- */

.rc-header {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    padding: 0 28px;
    height: 64px;
    display: flex;
    align-items: center;
    gap: 16px;
}

.rc-emblem { height: 38px; width: auto; flex: none; }

.rc-wordmark { font-weight: 800; font-size: 17px; letter-spacing: -0.02em; }
.rc-wordmark__road { color: #02284a; }
.rc-wordmark__coach { color: var(--accent); }

.rc-nav { display: flex; align-items: center; gap: 4px; margin-left: 12px; }

.rc-nav-link {
    color: var(--text-dim);
    text-decoration: none;
    padding: 8px 12px;
    border-radius: 9px;
    font-size: 13.5px;
    font-weight: 600;
    font-family: inherit;
    border: none;
    background: none;
    cursor: pointer;
}

.rc-nav-link:hover { background: var(--surface-2); color: var(--text); }

.rc-spacer { flex: 1; }

.rc-nav-dropdown { display: inline-block; position: relative; }
.rc-nav-dropdown > summary { list-style: none; cursor: pointer; }
.rc-nav-dropdown > summary::-webkit-details-marker { display: none; }
.rc-nav-dropdown[open] > summary::after { content: " \25B2"; font-size: 9px; }
.rc-nav-dropdown > summary::after { content: " \25BC"; font-size: 9px; }

.rc-nav-dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(20, 30, 50, .10);
    min-width: 180px;
    z-index: 50;
    padding: 6px;
}

/* Items sit on a surface-colored menu regardless of accent -- force the readable text color so a
   themed accent never makes a menu item blend into its own background. */
.rc-nav-dropdown-menu .rc-nav-link { display: block; color: var(--text); padding: 8px 10px; white-space: nowrap; }
.rc-nav-dropdown-menu .rc-nav-link:hover { background: var(--surface-2); color: var(--text); }

/* PORTAL-SPLIT Phase 1: the personal accent-switcher styles are REMOVED with the feature -- the
   template is server truth now (platform default -> school override); see /system/templates.
   TemplateParityTests scans this file so the swatch rules cannot creep back in a merge. */

/* ---- UI Templates gallery (/system/templates, TPL-100) ---- */

.rc-template-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 90px; /* room for the fixed apply bar so it never covers the last row */
}

/* Each card carries its own data-accent="<key>" -- the [data-accent] blocks above re-scope
   --accent/--accent-weak for everything inside it, so the mini-mock renders the template's REAL
   tokens (no duplicated hex values here; duplicating them would violate the parity rule). */
.rc-template-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px;
    cursor: pointer;
    text-align: left;
    font-family: inherit;
}

.rc-template-card:hover { border-color: var(--accent); }
.rc-template-card--previewing { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-weak); }

.rc-mini-mock {
    display: flex;
    gap: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px;
    height: 96px;
    pointer-events: none;
}

.rc-mini-mock__sidebar {
    width: 34%;
    background: var(--accent);
    border-radius: 6px;
    padding: 7px 6px;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.rc-mini-mock__navline { height: 5px; border-radius: 3px; background: rgba(255, 255, 255, .45); }
.rc-mini-mock__navline--active { background: var(--accent-contrast); }

.rc-mini-mock__body { flex: 1; display: flex; flex-direction: column; gap: 6px; padding-top: 2px; }
.rc-mini-mock__title { height: 7px; width: 70%; border-radius: 3px; background: var(--text-dim); opacity: .55; }
.rc-mini-mock__chip { height: 12px; width: 46%; border-radius: 6px; background: var(--accent-weak); }
.rc-mini-mock__btn { height: 14px; width: 58%; border-radius: 6px; background: var(--accent); margin-top: auto; }

.rc-template-card__meta { display: flex; flex-direction: column; gap: 3px; margin-top: 10px; }
.rc-template-card__name { font-weight: 700; font-size: 14px; }
.rc-template-card__usage { font-size: 12.5px; color: var(--text-dim); }

/* Fixed apply/discard bar -- appears while previewing; the preview is PAGE-ONLY by design
   (operator decision 2026-07-03): nothing is stored client-side, navigating away abandons it. */
.rc-template-applybar {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: 18px;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 10px 30px rgba(20, 30, 50, .18);
    padding: 12px 16px;
    max-width: calc(100vw - 32px);
}

/* ---- Page container ---- */

.rc-container {
    max-width: 1100px;
    margin: 24px auto;
    padding: 0 24px;
}

/* ---- Card ---- */

.rc-card {
    background: var(--card-bg, var(--brand-surface));
    border: 1px solid var(--card-border, var(--brand-border));
    border-radius: var(--card-radius, var(--brand-radius));
    padding: 20px;
    margin-bottom: 16px;
}

.rc-card--flush { padding: 0; overflow: hidden; }
.rc-card--center { text-align: center; padding: 40px; }
.rc-card--dashed { border-style: dashed; }

/* ---- Stat tiles (mockup 1.2: platform dashboard) ---- */

.rc-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px; }

.rc-stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
}

.rc-stat-value { font-size: var(--stat-value-size); font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; }
.rc-stat-label { font-size: 13px; color: var(--text-dim); margin-top: 4px; }
.rc-stat-sub { font-size: 12px; color: var(--text-dim); margin-top: 6px; }

/* ---- Buttons ---- */

.rc-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    height: 40px;
    padding: 0 16px;
    border-radius: 9px;
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    border: none;
    cursor: pointer;
    text-decoration: none;
}

.rc-btn--block { width: 100%; }
.rc-btn--primary, .rc-feedback-submit-btn { background: var(--btn-bg, var(--brand-primary)); color: var(--btn-fg, var(--brand-primary-contrast)); }
/* SUP-008: .rc-state-hover/.rc-state-force-hover are STATIC aliases of the real :hover rule so
   the catalog can render a frozen hover sample (edit mode swallows real hovers) and a test can
   force the real state for a computed-style parity assertion. Keep alias and :hover in the SAME
   selector list -- one rule, never a second diverging copy. Same pattern for focus/disabled. */
.rc-btn--primary:hover, .rc-feedback-submit-btn:hover,
.rc-btn--primary.rc-state-hover, .rc-btn--primary.rc-state-force-hover { filter: brightness(0.92); }
.rc-btn--secondary { background: var(--surface-2); color: var(--text); border: 1px solid var(--border); }
.rc-btn--secondary:hover, .rc-btn--secondary.rc-state-hover { background: var(--border); }
.rc-btn--outline { background: transparent; color: var(--accent); border: 1px solid var(--accent); }
.rc-btn--ghost { background: transparent; color: var(--text-dim); }
.rc-btn--destructive { background: var(--status-error); color: #fff; }

/* ---- Badges ---- */

.rc-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 20px;
}

.rc-badge__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

.rc-badge--success { background: var(--badge-success-bg, var(--status-success-bg)); color: var(--badge-success-fg, var(--status-success)); }
.rc-badge--warning { background: var(--badge-warning-bg, var(--status-warning-bg)); color: var(--badge-warning-fg, var(--status-warning)); }
.rc-badge--high { background: var(--badge-high-bg); color: var(--badge-high-fg); }
.rc-badge--error { background: var(--badge-error-bg, var(--status-error-bg)); color: var(--badge-error-fg, var(--status-error)); }
.rc-badge--info { background: var(--badge-info-bg, var(--brand-primary-weak)); color: var(--badge-info-fg, var(--brand-primary)); }
.rc-badge--neutral { background: var(--badge-neutral-bg, var(--brand-surface-2)); color: var(--badge-neutral-fg, var(--status-neutral)); }
.rc-badge--beta { background: var(--badge-beta-bg, var(--status-beta-bg)); color: var(--badge-beta-fg, var(--status-beta)); }

/* ---- Table ---- */

.rc-table { width: 100%; border-collapse: collapse; }
.rc-table th, .rc-table td { text-align: left; padding: 13px 18px; border-bottom: 1px solid var(--border); font-size: 13.5px; }
.rc-table th {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-dim);
    background: var(--table-header-bg, var(--brand-surface-2));
}
.rc-table tbody tr:hover, .rc-table tbody tr.rc-state-hover { background: var(--table-row-hover-bg, var(--brand-surface-2)); }
.rc-table--clickable tbody tr { cursor: pointer; }

/* ---- Form fields ---- */

.rc-form-group { margin-bottom: 12px; }

.rc-label {
    display: block;
    font-size: var(--label-size);
    font-weight: 600;
    color: var(--label-color, var(--text-dim));
    text-transform: uppercase;
    letter-spacing: .05em;
    margin-bottom: 6px;
}

/* TASK-SRV-PLAN-002 (REV-1 LOW): visible required-field marker (a red asterisk in a label). */
.rc-required { color: var(--status-error); font-weight: 700; margin-left: 2px; }

/* TASK-WEB-PLAN-003: a table cell can only POST via a <form>, not a plain <a> -- these two rules
   let a Cancel <form><button> sit inline among <a> links in the same cell and look like one of
   them (an unstyled button, not a boxed .rc-btn), matching the surrounding "Details | Edit | Cancel"
   text-link row. */
.rc-inline-form { display: inline; }
.rc-link-btn {
    background: none; border: none; padding: 0; margin: 0; font: inherit;
    color: var(--accent); text-decoration: underline; cursor: pointer;
}
.rc-link-btn:hover { opacity: 0.8; }
.rc-link-btn--danger { color: var(--status-error); }

.rc-input, .rc-select, .rc-textarea {
    width: 100%;
    height: 42px;
    padding: 0 13px;
    border: 1px solid var(--input-border, var(--brand-border));
    background: var(--input-bg, var(--brand-surface-2));
    border-radius: 9px;
    font-family: inherit;
    font-size: var(--input-font-size);
    color: var(--text);
}

.rc-textarea { height: auto; padding: 11px 13px; resize: vertical; }

.rc-input:focus, .rc-select:focus, .rc-textarea:focus,
.rc-input.rc-state-focus, .rc-select.rc-state-focus, .rc-textarea.rc-state-focus {
    outline: none;
    border: 2px solid var(--accent);
    box-shadow: 0 0 0 4px var(--accent-weak);
}

.rc-input--error, .rc-textarea--error {
    border: 1.5px solid var(--status-error);
    background: #fff5f7;
}

.rc-field-error { font-size: 11.5px; color: var(--status-error); margin-top: 6px; }

/* 64px, not 50: Chromium reserves spinner width inside number inputs, which clipped the
   "max" placeholder to "ma" at 50px. */
.rc-input--xs { width: 64px; height: 30px; padding: 0 6px; font-size: 12px; }
.rc-input--sm { width: 90px; }
/* State (two-letter) boxes: WIDTH-only narrowing -- rc-input--xs also shrinks height/font, which
   made the ST inputs visibly shorter than their row siblings (operator 2026-07-03). */
.rc-input--st { width: 64px; text-transform: uppercase; }
.rc-input--md { width: 130px; }
.rc-input--lg { width: 170px; }
.rc-input--xl { width: 260px; }
/* TASK-WEB-SEC-002: replaces a page-authored style="max-width: 220px;" on the route-code search
   box (Pages/RcSystem/Routes/Index.cshtml, Detail.cshtml) -- CSP's style-src can drop
   'unsafe-inline' only if no page carries an inline style="" attribute. */
.rc-input--route-code { max-width: 220px; }

.rc-check-row { display: flex; align-items: center; gap: 6px; font-size: 13.5px; padding: 2px 0; }
.rc-check-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin-bottom: 12px; }
.rc-check-list { display: flex; flex-direction: column; gap: 6px; }
.rc-fieldset { border: none; padding: 0; margin: 0; }
.rc-legend { font-weight: 500; margin-bottom: 4px; font-size: 13.5px; }

/* ---- Skill Mapping accordion ---- */

.rc-mapping-success { border-left: 4px solid var(--status-success); }
.rc-mapping-details { margin-bottom: 16px; }
.rc-mapping-summary {
    cursor: pointer;
    padding: 14px 18px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    list-style: none;
}
.rc-mapping-body { margin-top: 4px; padding: 20px; }
.rc-mapping-span-2 { grid-column: span 2; }

/* ---- Login ---- */

.rc-login { max-width: 400px; margin: 80px auto; padding: 0 24px; }
.rc-login__title { text-align: center; margin-bottom: 24px; }
.rc-login__error { color: var(--status-error); margin-bottom: 12px; }

/* ---- Misc shared bits ---- */

.rc-muted { color: var(--text-dim); }
.rc-mono { font-family: 'JetBrains Mono', monospace; }
.rc-text-sm { font-size: 12.8px; }
.rc-text-xs { font-size: 11.5px; }
.rc-success-banner, .rc-feedback-success-banner { background: var(--banner-success-bg, var(--status-success-bg)); color: var(--banner-success-fg, var(--status-success)); padding: 12px; border-radius: 6px; margin-bottom: 16px; }
.rc-screenshot-preview { max-width: 600px; max-height: 400px; border: 1px solid var(--border); border-radius: 9px; margin-top: 4px; }
.rc-branding-logo-preview { max-width: 240px; max-height: 96px; border: 1px solid var(--border); border-radius: 9px; padding: 8px; background: var(--surface); }
.rc-description-block { white-space: pre-wrap; background: var(--bg); padding: 12px; border-radius: 9px; margin-top: 4px; }
.rc-loading-text { color: var(--text-dim); font-size: 14px; }
.rc-hidden { display: none; }
.rc-error-banner, .rc-feedback-error-banner {
    color: var(--banner-error-fg, var(--status-error));
    margin-bottom: 12px;
    padding: 10px 14px;
    border: 1px solid var(--banner-error-border, var(--status-error));
    border-radius: 9px;
    font-size: 14px;
}
.rc-skill-result {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
}
.rc-skill-result__name { font-weight: 500; }

.rc-skill-row { padding: 2px 0; }
/* flex:1 pushes the min/max/count cluster to the column's right edge so the number
   boxes align vertically across every row (operator request 2026-07-02). */
.rc-skill-row__label { font-weight: 400; cursor: pointer; min-width: 168px; flex: 1 1 auto; }
.rc-skill-row__count { color: var(--text); font-weight: 700; min-width: 28px; display: inline-block; }

.rc-skill-col { display: flex; flex-direction: column; gap: 4px; min-width: 340px; }

/* Skill editor: category groups with drag-and-drop re-filing (2026-07-02). */
.rc-skill-cat-group { margin-bottom: 20px; padding: 8px; border: 1px dashed transparent; border-radius: var(--radius); }
.rc-skill-cat-group__head { font-size: 16px; margin: 0 0 8px 2px; }
.rc-skill-cat-group.rc-drop-target { border-color: var(--accent); background: var(--surface-2, rgba(0,0,0,0.03)); }
.rc-drag-grip { cursor: grab; color: var(--text-dim); font-weight: 700; letter-spacing: 1px; user-select: none; }
.rc-dragging { opacity: 0.45; }

/* Route generator: featured Milestones & Major section -- the skills the engine routes around. */
.rc-skill-featured { border-left: 4px solid var(--accent); padding-left: 12px; margin-bottom: 14px; }
.rc-skill-featured__head { font-size: 14px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; margin: 0 0 6px; }
.rc-skill-col__head {
    font-weight: 700;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-dim);
    border-bottom: 1px solid var(--border);
    padding-bottom: 3px;
    margin-bottom: 2px;
}

/* ---- Address autocomplete (Route Generator, GEO-004) ---- */

.rc-geo-box { position: relative; }
.rc-geo-suggest {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1000;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, .12);
    max-height: 220px;
    overflow-y: auto;
    margin-top: 2px;
}
.rc-geo-suggest__item { padding: 6px 10px; cursor: pointer; font-size: 13px; }
.rc-geo-suggest__item:hover, .rc-geo-suggest__item.active { background: var(--surface-2); }
.rc-geo-suggest__empty { padding: 8px 10px; font-size: 13px; color: var(--text-dim); font-style: italic; }

.rc-details-summary { cursor: pointer; font-weight: 600; font-size: 13px; color: var(--text-dim); }

/* ---- Layout utilities (a small, deliberately constrained set -- new one-off pixel values get a
   named class here, not an inline style, per UI-STANDARDS.md rule 2) ---- */

.rc-flex { display: flex; }
.rc-flex--col { flex-direction: column; }
.rc-flex--wrap { flex-wrap: wrap; }
.rc-items-center { align-items: center; }
.rc-items-end { align-items: flex-end; }
.rc-items-start { align-items: flex-start; }
.rc-justify-between { justify-content: space-between; }
.rc-justify-end { justify-content: flex-end; }
.rc-flex-1 { flex: 1; }

.rc-gap-1 { gap: 4px; }
.rc-gap-2 { gap: 8px; }
.rc-gap-3 { gap: 12px; }
.rc-gap-4 { gap: 16px; }
.rc-gap-5 { gap: 20px; }
.rc-gap-6 { gap: 24px; }

.rc-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.rc-grid-2--narrow-right { display: grid; grid-template-columns: 1fr 320px; gap: 16px; }
.rc-grid-2--sidebar { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 16px; }

/* TASK-WEB-GEN-004: a grid item's default cross-axis behavior in a CSS grid row is `stretch` --
   without this, a short grid item (e.g. the Route Generator's Legend-only side card, now that the
   turn-by-turn list that used to fill it is gone) silently stretches to match the tallest item in
   its row (the 560px map), leaving a large dead blank area below its own content. Generic, reusable
   utility -- opt-in per grid item, does not change `.rc-grid-2--narrow-right`'s (or any other grid
   utility's) default stretch behavior for existing consumers. */
.rc-self-start { align-self: start; }

.rc-mb-0 { margin-bottom: 0; }
.rc-filter-label { font-size: 13.5px; font-weight: 600; color: var(--text-dim); }
.rc-table__description-cell { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.rc-mt-1 { margin-top: 8px; }
.rc-mt-2 { margin-top: 12px; }
.rc-mt-3 { margin-top: 16px; }
.rc-mt-4 { margin-top: 20px; }
.rc-mb-1 { margin-bottom: 8px; }
.rc-mb-2 { margin-bottom: 12px; }
.rc-mb-3 { margin-bottom: 16px; }
.rc-ml-1 { margin-left: 8px; }

.rc-w-full { width: 100%; }
.rc-min-w-0 { min-width: 0; }
.rc-inline { display: inline; }

/* TASK-WEB-RESP-001: reusable scroll container for a wide table -- the PAGE must never scroll
   sideways, but a table with many columns legitimately can, WITHIN its own box. Wrap the
   <table>, not the surrounding .rc-card (rc-card--flush already clips corners via overflow:
   hidden; nesting this overflow-x:auto div inside it does not fight that -- the card only clips
   ITS OWN box, this div manages its own independent scroll region). Applied at every width (not
   just the phone media query) since a wide table can also want to scroll on a narrow desktop
   window -- it is simply a no-op when the table already fits. */
.rc-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.rc-cc-progress { font-weight: 600; }
.rc-mapping-rcs-id { font-weight: 400; }

/* ---- Fixed (non-themed) map / status colors -- used by the Route Generator's Leaflet map and
   legend. Map-pin colors are cartographic conventions (left/right/roundabout/start/end), not brand
   accents, so they stay fixed per UI-STANDARDS.md ("status colors NOT themed"). ---- */

.rc-dot { width: 13px; height: 13px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px #cbd5e1; display: inline-block; }
.rc-dot--left { background: #2563eb; }
.rc-dot--right { background: #16a34a; }
.rc-dot--roundabout { background: #ea580c; }
.rc-dot--start { background: #111827; }
.rc-dot--end { background: #b91c1c; }
/* TASK-WEB-GEN-005: Milestone/Major skill-pin tiers (distinct from the retained-but-dormant
   left/right/roundabout turn-kind colors above, so a re-enable of the maneuver pins never collides
   visually with the current skill-tier pins). */
.rc-dot--milestone { background: #ca8a04; }
.rc-dot--major { background: #7c3aed; }

.rc-map-legend { display: flex; flex-direction: column; gap: 2px; }
.rc-map-legend__row { display: flex; align-items: center; gap: 8px; padding: 2px 0; }

.rc-pin {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 11px;
    border: 2px solid #fff;
    border-radius: 50%;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .25);
}
.rc-pin--turn { width: 22px; height: 22px; } /* DORMANT (TASK-WEB-GEN-005) -- retained for re-enable, see renderMap's comment */
.rc-pin--endpoint { width: 26px; height: 26px; }
.rc-pin--left { background: #2563eb; } /* DORMANT (TASK-WEB-GEN-005) */
.rc-pin--right { background: #16a34a; } /* DORMANT (TASK-WEB-GEN-005) */
.rc-pin--roundabout { background: #ea580c; } /* DORMANT (TASK-WEB-GEN-005) */
.rc-pin--start { background: #111827; }
.rc-pin--end { background: #b91c1c; }
.rc-pin--skill { width: 22px; height: 22px; } /* TASK-WEB-GEN-005: Milestone/Major realized-location pins */
.rc-pin--milestone { background: #ca8a04; }
.rc-pin--major { background: #7c3aed; }

.rc-turnlist { padding-left: 20px; margin: 6px 0; }
.rc-turnlist li { padding: 2px 0; line-height: 1.35; }
.rc-verdict--pass { color: var(--status-success); font-weight: 800; }
.rc-verdict--fail { color: var(--status-error); font-weight: 800; }
.rc-turn-num--left { color: #2563eb; }
.rc-turn-num--right { color: #16a34a; }
.rc-turn-num--roundabout { color: #ea580c; }

.rc-map { border: 1px solid var(--border); border-radius: var(--radius); }
.rc-map--lg { height: 560px; }
.rc-map--md { height: 420px; }

.rc-side-card { padding: 16px; }
.rc-side-card__title { font-size: 13px; margin: 0 0 6px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-dim); }

/* ---- Route Generator: three-variant chooser (TASK-WEB-GEN-001) -----------------------------
   Same auto-fit/minmax pattern as .rc-stat-grid/.rc-template-grid, which TASK-WEB-RESP-001 already
   confirmed reflows to fewer columns at narrow widths with no extra media query needed. */

.rc-chooser-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }

.rc-chooser-card {
    border: 1px solid var(--card-border, var(--brand-border));
    border-radius: var(--card-radius, var(--brand-radius));
    padding: 14px;
    background: var(--surface);
}

/* TASK-WEB-GEN-003: once a card has loaded data, the whole panel is a click target (parity with
   the "Use this route" button inside it) -- this affordance makes that discoverable without
   requiring the user to find the small button first. */
.rc-chooser-card--loaded {
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(20, 30, 50, .08);
    transition: box-shadow .15s ease, border-color .15s ease;
}
.rc-chooser-card--loaded:hover { border-color: var(--brand-primary); box-shadow: 0 4px 12px rgba(20, 30, 50, .16); }

.rc-chooser-card--active { border-color: var(--brand-primary); box-shadow: 0 0 0 2px var(--brand-primary-weak, rgba(29, 78, 216, .18)); }
.rc-chooser-card--error { border-color: var(--status-error); }

.rc-chooser-card__head { display: flex; align-items: baseline; gap: 6px; margin-bottom: 2px; }
.rc-chooser-card__note { margin: 0 0 8px; }
.rc-chooser-card__body { display: flex; flex-direction: column; gap: 4px; }
.rc-chooser-card__stats { font-weight: 700; }

/* ---- System Health page (data-status / data-tier driven, no inline color styles) ---- */

.rcs-banner { padding: 16px 20px; border-radius: var(--radius); color: #fff; margin-bottom: 20px; }
.rcs-banner[data-status="healthy"] { background: var(--status-success); }
.rcs-banner[data-status="degraded"] { background: var(--status-warning); }
.rcs-banner[data-status="unhealthy"] { background: var(--status-error); }
.rcs-banner__title { font-size: 18px; font-weight: 800; }
.rcs-banner__meta { opacity: .85; font-size: 13px; }

.rcs-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.rcs-card { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; background: var(--surface); }

.rcs-pill { display: inline-block; padding: 3px 10px; border-radius: 20px; color: #fff; font-size: 12px; font-weight: 700; }
.rcs-pill[data-status="healthy"] { background: var(--status-success); }
.rcs-pill[data-status="degraded"] { background: var(--status-warning); }
.rcs-pill[data-status="unhealthy"] { background: var(--status-error); }
.rcs-pill--action { background: var(--accent); border: none; cursor: pointer; padding: 8px 16px; font-size: 14px; font-family: inherit; }

.rcs-meta { color: var(--text-dim); font-size: 13px; margin-top: 6px; }
.rcs-meta div { margin: 1px 0; }
.rcs-meta__error { color: var(--status-error); }
/* W1-HEALTH: error div is always rendered (server AND JS auto-refresh both just set its text) so
   it can be updated in place without reload -- hide it entirely when there is no error text. */
.rcs-meta__error:empty { display: none; margin: 0; }
.rcs-section { margin-top: 28px; }

.rcs-conf { width: auto; }
.rcs-conf td { padding: 4px 12px 4px 0; font-size: 14px; border: none; }
.rcs-conf td.k { color: var(--text-dim); }

.cc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 6px; }
.cc-tile { border-radius: 6px; padding: 6px 8px; color: #fff; font-size: 12px; position: relative; transition: background .15s, opacity .15s; }
.cc-tile[data-status="pass"] { background: var(--status-success); }
.cc-tile[data-status="fail"] { background: var(--status-error); }
.cc-tile[data-status="red"] { background: var(--status-neutral); }
.cc-tile[data-status="pending"] { background: #bdbdbd; opacity: .6; }
.cc-tile[data-running="true"] { outline: 2px solid var(--accent); opacity: 1; }
.cc-tile .id { font-weight: 700; }
.cc-tile .ttl { opacity: .9; font-size: 11px; line-height: 1.2; }
.cc-stripe { height: 4px; border-radius: 3px; margin-top: 5px; display: flex; gap: 2px; }
.cc-stripe__seg { flex: 1; border-radius: 3px; }
.cc-stripe__seg[data-tier="milestone"] { background: #6a1b9a; }
.cc-stripe__seg[data-tier="major"] { background: #1565c0; }
.cc-stripe__seg[data-tier="minor"] { background: #00838f; }
.cc-stripe__seg[data-tier="general"] { background: var(--status-neutral); }
.cc-badge { display: inline-block; background: rgba(0, 0, 0, .25); border-radius: 4px; padding: 0 4px; font-size: 10px; margin: 2px 2px 0 0; }
.cc-summary { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.cc-summary__pass { color: var(--status-success); font-weight: 600; }
.cc-summary__fail { color: var(--status-error); font-weight: 600; }
.cc-summary__red { color: var(--status-neutral); font-weight: 600; }
.cc-tier-key span[data-tier="milestone"] { color: #6a1b9a; }
.cc-tier-key span[data-tier="major"] { color: #1565c0; }
/* TASK-WEB-A11Y-001: darkened from #00838f (4.52:1 on white, but system-health's tier key sits on
   --bg #f4f6f9 where it measured a serious color-contrast failure) -- same teal hue, lower
   lightness only. #007b87 clears >=4.6:1 against both --bg and white. Fixed in place rather than
   tokenized: this is a fixed pedagogical tier color (milestone/major/minor/general), the same
   "not brand-themed" family as the map pin colors a few rules below -- not part of the
   school-brandable token surface, so a CSS custom property here would be new surface with no
   consumer (see DONE summary for the tokenize-vs-fix-in-place note). */
.cc-tier-key span[data-tier="minor"] { color: #007580; }

/* ---- Feedback widget (floating capture launcher + overlay, every page via _Layout) ---- */

.rc-feedback-launcher {
    position: fixed;
    right: 24px;
    bottom: 24px;
    /* Must sit above every other overlay in this file (Leaflet panes top out around z-index 1000;
       the highest local overlay is .rc-geo-suggest at 1000) so the launcher is never covered by a
       map or dropdown on any page. Operator feedback: the widget was "partially hidden by the map". */
    z-index: 10000;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-contrast);
    border: none;
    box-shadow: 0 6px 18px rgba(20, 30, 50, .28);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}
.rc-feedback-launcher:hover { filter: brightness(0.92); }
.rc-feedback-launcher__icon { font-family: 'JetBrains Mono', monospace; font-weight: 700; font-size: 20px; }

.rc-feedback-overlay {
    position: fixed;
    inset: 0;
    /* Backdrop + dialog both live in this stacking context; one level above the launcher (also
       raised, above) so the modal always wins over Leaflet panes (~1000) and every other overlay
       in this file (.rc-geo-suggest at 1000, .rc-nav-dropdown-menu at 50). */
    z-index: 10001;
    background: rgba(14, 34, 56, .45);
    align-items: center;
    justify-content: center;
    padding: 24px;
}
/* :not(.rc-hidden) instead of a bare "display: flex" above -- .rc-hidden { display: none } sits
   earlier in this file at equal specificity, so a bare rule here would win by source order and the
   overlay would never actually hide. */
.rc-feedback-overlay:not(.rc-hidden) { display: flex; }

.rc-feedback-panel {
    background: var(--surface);
    border-radius: var(--radius);
    padding: 20px;
    width: 100%;
    max-width: 440px;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
}

.rc-feedback-panel__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
}

.rc-feedback-preview {
    max-width: 100%;
    max-height: 160px;
    border: 1px solid var(--border);
    border-radius: 9px;
    margin-top: 4px;
}
/* Same rc-hidden specificity-vs-source-order issue as .rc-feedback-overlay above. */
.rc-feedback-preview:not(.rc-hidden) { display: block; }

/* ---- What's New ---- */

.wn-release { border-left: 3px solid var(--accent); padding: 4px 0 4px 16px; margin: 18px 0; }
.wn-ver { font-size: 18px; font-weight: 700; }
.wn-date { color: var(--text-dim); font-size: 13px; margin-left: 8px; }
.wn-summary { color: var(--text); margin: 6px 0; }
.wn-release ul { margin: 6px 0 0 18px; }
.wn-release li { margin: 4px 0; color: var(--text-dim); font-size: 14px; }

/* ---- TICKET H: Route Generator time-limit chips + stepper (Docs/UI-OPERATION-CHECKLIST.md) ----
   Operator: "time picker needs to be more simple." Chips are one-tap presets; the stepper nudges
   by 5 minutes between presets. Both write into the SAME hidden #time input the existing
   Generate-route JS already reads (document.getElementById('time').value) -- this section adds
   presentation only, no behavior-contract change. Scope: this control only. */

.rc-time-limit { display: flex; flex-direction: column; gap: 8px; }

.rc-chip-row { display: flex; gap: 6px; flex-wrap: wrap; }

.rc-chip {
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--chip-fg, var(--brand-text));
    background: var(--chip-bg, var(--brand-surface-2));
    border: 1px solid var(--chip-border, var(--brand-border));
    border-radius: 20px;
    padding: 5px 12px;
    cursor: pointer;
}

.rc-chip:hover, .rc-chip.rc-state-hover { background: var(--border); }

.rc-chip--active {
    background: var(--chip-active-bg, var(--brand-primary));
    border-color: var(--chip-active-bg, var(--brand-primary));
    color: var(--chip-active-fg, var(--brand-primary-contrast));
}

.rc-stepper {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.rc-stepper__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}

.rc-stepper__btn:hover, .rc-stepper__btn.rc-state-hover { background: var(--surface-2); }

.rc-stepper__value {
    min-width: 34px;
    text-align: center;
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
}

/* ---- TICKET I: UI-OPERATION-CHECKLIST item 14 (loading/busy state) ----
   A button disabled while a request is in flight (roadcoach.js double-submit guard, per-page
   fetch handlers) must LOOK disabled -- .rc-btn's own background/color rules otherwise leave a
   disabled primary/secondary/destructive button visually identical to an enabled one. */
.rc-btn:disabled,
.rc-btn[disabled],
.rc-btn.rc-state-disabled {
    opacity: 0.6;
    cursor: not-allowed;
    filter: none;
}

/* ---- W3-PAGED: reusable server-pagination pager (Pages/Shared/_Pager.cshtml) ----
   Flex + flex-wrap so it reflows (never overlaps) at narrow widths -- stays in normal document
   flow (no position:fixed), unlike the floating feedback launcher (TD-021), so this component
   cannot add a second instance of that overlap class. */
.rc-pager {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 16px;
}
.rc-pager__status { font-size: 13px; white-space: nowrap; }

/* ---- TICKET M: skill-mapping tier sections grouped by category (Pages/Skills/Mapping.cshtml) ----
   Reuses .rc-skill-col / .rc-skill-col__head (defined above for the Route Generator side-options
   picker) so the "group cards by category" treatment is the SAME everywhere (one component per
   concept). On the mapping page the columns are NOT placed inside a flex row -- unlike the picker's
   side-options, each card here is a <details> that expands into a full editing form, so a column
   renders as a full-width, top-to-bottom stack instead of a narrow side-by-side column. Spacing
   between stacked columns within one tier section: */
.rc-skill-cat-group .rc-skill-col + .rc-skill-col { margin-top: 14px; }

/* ---- THEME DESIGNER Phase C2: /system/templates token editor layout (Pages/RcSystem/Templates.cshtml) ----
   Purely structural -- every color/size VALUE these rows show still comes from the token itself
   (var(--token, ...)), never a hardcoded hex here. Grouped-by-family grid so 57+ tokens stay
   scannable instead of one long list. */
.rc-theme-editor-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 18px; }

.rc-theme-family__title { text-transform: capitalize; font-size: 14px; margin-bottom: 8px; }

.rc-theme-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}
.rc-theme-row:last-child { border-bottom: none; }

.rc-theme-row__meta { display: flex; flex-direction: column; gap: 1px; }
.rc-theme-row__desc { font-size: 13px; }

.rc-theme-row__control { display: flex; align-items: center; gap: 6px; }

.rc-theme-color { width: 32px; height: 32px; padding: 0; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; }
.rc-theme-hex { width: 90px; }

.rc-theme-stepper { margin-right: 4px; }

.rc-theme-row__error { margin-top: 0; }

/* ---- SUP-008: visual click-to-edit theme editor (TPL-100, SUPPORTABILITY-PLAN.md sec 6) ----
   Purely structural/affordance styles; every color still reads a token (never a hardcoded brand
   hex). Three pieces: (1) the All-tokens/Visual-editor tabs, (2) edit-mode hover outline + name
   badge on catalog exemplars (outline + a pointer-events:none ::after badge, so nothing here can
   ever intercept a click), (3) the fixed right-hand inspector, which is the SAME
   .rc-theme-editor-grid the flat editor renders (same DOM, filtered by JS -- the parity rule),
   restyled as a panel when .rc-inspector-mode is set. */

.rc-theme-tabs { display: flex; gap: 8px; margin-bottom: 12px; }

.rc-theme-tab {
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    padding: 8px 14px;
    border-radius: 9px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    cursor: pointer;
}

.rc-theme-tab--active {
    background: var(--surface);
    color: var(--text);
    border-color: var(--accent);
    box-shadow: inset 0 -2px 0 var(--accent);
}

.rc-theme-row__layer { margin-left: 6px; }
.rc-theme-row__modified-badge { margin-left: 6px; vertical-align: middle; }

/* Edit mode: catalog exemplars become selection targets. Children go pointer-events:none (the
   property inherits, so the whole sample subtree is inert -- a select cannot even open its native
   dropdown on mousedown, which a click-capture guard alone cannot stop) and the wrapper takes the
   hover/focus outline + floating name badge. */
body.rc-edit-mode .rc-exemplar { position: relative; cursor: pointer; border-radius: 6px; }
body.rc-edit-mode .rc-exemplar > * { pointer-events: none; }

body.rc-edit-mode .rc-exemplar:hover,
body.rc-edit-mode .rc-exemplar:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
}

body.rc-edit-mode .rc-exemplar--selected,
body.rc-edit-mode .rc-exemplar--selected:hover {
    outline: 3px solid var(--accent);
    outline-offset: 4px;
}

body.rc-edit-mode .rc-exemplar:hover::after,
body.rc-edit-mode .rc-exemplar:focus-visible::after,
body.rc-edit-mode .rc-exemplar--selected::after {
    content: attr(data-name);
    position: absolute;
    top: -12px;
    left: 10px;
    z-index: 55;
    background: var(--accent);
    color: var(--accent-contrast);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .04em;
    padding: 2px 10px;
    border-radius: 12px;
    pointer-events: none;
}

/* In edit mode the flat grid hides until a selection opens it as the inspector panel. */
body.rc-edit-mode .rc-theme-editor-grid:not(.rc-inspector-mode) { display: none; }

/* The inspector IS the flat editor grid, fixed to the right edge. z-index 70: above the template
   applybar (60), below the feedback overlay stack (10000+). */
.rc-theme-editor-grid.rc-inspector-mode {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 70;
    width: 380px;
    max-width: 92vw;
    display: flex;
    flex-direction: column;
    gap: 14px;
    background: var(--surface);
    border-left: 1px solid var(--border);
    box-shadow: -10px 0 28px rgba(14, 34, 56, 0.14);
    padding: 0 18px 24px;
    overflow-y: auto;
}

/* Same specificity-vs-source-order gotcha as .rc-feedback-overlay: .rc-hidden { display: none }
   is declared EARLIER in this file, so a bare display: flex here would defeat it.
   STICKY: the chrome (title/Undo/Close) must stay pinned while the operator scrolls a long token
   list -- and a scrolled-away Undo button is also exactly what made the Playwright click flake
   (the panel auto-scroll raced the click's hit test). */
.rc-inspector-chrome:not(.rc-hidden) {
    display: flex;
    align-items: center;
    gap: 8px;
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--surface);
    padding-top: 16px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border);
}

.rc-inspector-chrome strong { flex: 1; font-size: 14px; }

/* Catalog exemplar for the sidebar family (SUP-008 rework: every token family must be reachable
   via click-to-edit). Purely structural -- the items inside reuse the REAL .rc-sidebar__link
   rules from sidebar.css, so their colors come from the same tokens as the live sidebar. */
.rc-sidebar-exemplar {
    max-width: 260px;
    display: flex;
    flex-direction: column;
}

.rc-theme-violation-list { margin: 6px 0 0; padding-left: 20px; }

/* SUP-006: Log Hub tab nav -- plain links styled as a tab strip (no JS tab framework; each tab is
   its own full page load carrying the filter query string, matching the "filters live in the URL"
   design). */
.rc-loghub-tabs { display: flex; gap: 4px; border-bottom: 2px solid var(--border); }
.rc-loghub-tab {
    display: inline-block;
    padding: 8px 16px;
    font-weight: 600;
    color: var(--text-dim);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
}
.rc-loghub-tab:hover { color: var(--text); }
.rc-loghub-tab--active { color: var(--brand-primary, var(--accent)); border-bottom-color: var(--brand-primary, var(--accent)); }

.rc-loghub-filters .rc-filter-label { display: flex; flex-direction: column; gap: 2px; font-size: 12px; font-weight: 600; color: var(--text-dim); }
.rc-loghub-drill-link { font-size: 12px; }

/* ---- TASK-WEB-RESP-001: app-wide responsive layer (phone widths, ~<768px) ----
   Additive only -- every rule above this block is the pre-existing desktop stylesheet, untouched,
   so >=768px renders exactly as before this ticket. The sidebar's own off-canvas drawer rules live
   in sidebar.css (next to the sidebar rules they override); this block covers the SHARED container
   + the fixed-column utility grids that would otherwise squeeze into unreadably narrow columns (a
   260px sidebar-width column, or two 1fr columns, both fit fine at a 1100px desktop container but
   not inside a ~340px phone content area). */
@media (max-width: 767.98px) {
    .rc-container {
        max-width: 100%;
        margin: 16px auto;
        padding: 0 16px;
    }

    /* Fixed-ratio/fixed-px two-column grids collapse to one column -- at phone width there is not
       enough room for a 260px (or even a 320px) side column next to anything else. rc-stat-grid /
       rc-template-grid are left alone: their auto-fit + minmax already reflow to fewer columns
       without overflowing (minmax(160px,1fr) etc. never demands more than the available track). */
    .rc-grid-2,
    .rc-grid-2--narrow-right,
    .rc-grid-2--sidebar,
    .rc-check-grid,
    .rc-theme-editor-grid {
        grid-template-columns: 1fr;
    }

    /* REWORK (Tester finding 1, 2026-07-22): a grid ITEM defaults to min-width:auto, which refuses
       to shrink below its own content's min-content width -- a plain <div> grid item (no overflow
       of its own) bubbles up the min-content width of ANY descendant, including a `.rc-table-wrap`-
       wrapped table several levels down, regardless of that wrapper's own overflow-x:auto. Proven
       live: the Dashboard's "Recent feedback" grid item forced the page to scrollWidth=758 at a
       390px viewport once a real feedback row carried a long unbreakable ActiveScreen value (a
       table's min-content is its narrowest UNBREAKABLE token per column, not each cell's wrapped
       height -- so ordinary multi-word content wraps and stays narrow, but one long token does not).
       min-width:0 on the grid item overrides that default, letting it shrink to its track's actual
       width -- the descendant `.rc-table-wrap` then does its OWN job of scrolling internally. Scoped
       to `> *` (immediate children only) so it reaches every current/future consumer of these grid
       classes without requiring each call site to remember a utility class. */
    .rc-grid-2 > *,
    .rc-grid-2--narrow-right > *,
    .rc-grid-2--sidebar > *,
    .rc-check-grid > * {
        min-width: 0;
    }

    /* The theme editor's fixed right-hand inspector panel (desktop: 380px docked to the edge)
       would itself force page-width overflow at phone width -- make it a full-width panel instead
       of a narrow sliver pinned off the right edge. */
    .rc-theme-editor-grid.rc-inspector-mode {
        width: 100%;
        max-width: 100%;
    }

    /* REWORK (Tester finding 2, 2026-07-22): the shared skill picker's per-skill row
       (`_SkillPicker.cshtml`, `.rc-flex rc-items-center rc-gap-2 rc-skill-row`) is a nowrap flex row
       by default (`.rc-flex` sets no wrap) -- fine at desktop, where `.rc-card` is wide, but this
       ticket's shell reflow narrows `.rc-card` at phone width for the first time, and the row's
       fixed-width min/max number inputs (`.rc-input--xs`) plus the label's own 168px min-width no
       longer fit on one line, pushing the min/max inputs' right edge past the card (previously
       masked because the WHOLE PAGE scrolled instead of the card alone). Nothing here changes
       desktop rendering: flex-wrap only has an effect once a line's content actually exceeds the
       row's width (never true at >=768px), and .rc-skill-row__break only has a non-zero
       flex-basis inside this same media query. */
    .rc-skill-row {
        flex-wrap: wrap;
    }

    /* First attempt (flex-wrap alone) left a 3px residual overflow on the min-input -- the
       browser's own line-packing decision (based on each skill NAME's rendered width, which
       varies per skill) is not deterministic enough to guarantee the numeric cluster always lands
       on a fresh line. `.rc-skill-row__break` (an always-empty span the partial renders right
       before the min-input) is the standard flex "line break" technique: forcing IT to claim a
       full line's width deterministically pushes every item after it (min/dash/max/count) onto a
       new line together, regardless of how wide the checkbox+label content happens to be. */
    .rc-skill-row__break {
        flex-basis: 100%;
    }
}
