/* Open Sans is loaded via <link rel="preconnect"> + <link rel="stylesheet"> in index.html
   so the request goes out in parallel with this CSS instead of being blocked behind it. */

/* ROC design tokens — the single source of truth for color, radius, spacing and the focus
   ring, aligned to the official BGV brand color sheet (Dark Blue / Dark Grey primary,
   Blue / Grey secondary, Light Grey / Orange tertiary) and to the ROC design system
   spec (AB#8101); the --roc-severity-* group below is Bootstrap's alert palette, adopted rather
   than derived from either — see its own note.
   Defined on :root here (a global stylesheet) so the tokens cascade into every
   scoped component stylesheet (*.razor.css). Add new shared values here rather
   than hardcoding them in component CSS. Severity colour lives here too — the four levels any
   surface can raise. A feature's own status colour does not: the Bonus Time green in
   DayUseCalendar.razor.css and the TSW-transcription amber in RateCalculator.razor.css stay with
   their components. AB#8174 records that split and the reasoning for it. */
:root {
    /* Brand — BGV palette */
    --roc-color-primary: #1F3956; /* BGV Dark Blue — headings, brand bar, primary text/icons */
    --roc-color-primary-active: #17293D; /* BGV Dark Blue, darkened — pressed state on a primary fill */
    /* Accent is 3.70:1 on white, below the 4.5:1 text threshold — use it for borders, fills and
       the focus ring (3:1 non-text), and --roc-color-link for anything that carries text. */
    --roc-color-accent: #5B89B4; /* BGV Blue — borders, fills, active nav states */
    /* Channels of --roc-color-accent, so the translucent derivatives below compose from one source
       instead of each restating the hex. Keep in step with --roc-color-accent: nothing enforces it,
       and the pair drifting apart is what left the old tint on 88,137,180 against a #5889B4 accent. */
    --roc-color-accent-rgb: 91, 137, 180;
    --roc-color-link: #3D6E97; /* BGV Blue darkened to 5.42:1 on white — links, accent-colored text */
    /* Accent-fill hover. Darkened past the obvious #4A7499 because the text on this fill is
       --roc-text-light (#F2F3F4), not #fff: #4A7499 is 4.94:1 against white but only 4.45:1
       against the off-white, which is the ratio that actually ships. #46708F clears AA at
       4.76:1 on --roc-text-light (5.28:1 on white). */
    --roc-color-accent-hover: #46708F;
    --roc-color-accent-tint: rgba(var(--roc-color-accent-rgb), 0.25); /* nav link hover background */
    --roc-color-secondary: #717171; /* BGV Grey — secondary buttons / secondary UI */
    --roc-color-secondary-hover: #5A5A5A; /* BGV Dark Grey — secondary hover / darker border */
    --roc-color-orange: #E67D37; /* BGV Orange — tertiary accent, use sparingly (1–5%) */
    --roc-color-orange-tint: rgba(230, 125, 55, 0.25); /* BGV Orange @ 25% — warm subtle highlight */
    /* Text — BGV greys */
    --roc-text: #5A5A5A; /* BGV Dark Grey — default body text */
    /* Channels of the two text greys. Only reason these exist: Bootstrap's .text-body and
       .text-secondary utilities set colour with !important, so the only way to re-point them at the
       BGV palette without !important of our own is to feed their rgba() the ROC channels — see the
       .text-body / .text-secondary rules below. Keep in step with the hex above, as with
       --roc-color-accent-rgb. */
    --roc-text-rgb: 90, 90, 90;
    --roc-text-muted: #717171; /* BGV Grey — secondary / muted text */
    --roc-text-muted-rgb: 113, 113, 113;
    --roc-text-light: #F2F3F4; /* BGV off-white — primary body text against a dark background */
    --roc-text-disabled: #B4B4B4; /* disabled control / label text — 2.07:1, AA-exempt per WCAG 1.4.3 */
    /* Placeholders are NOT AA-exempt. The spec's #9B9B9B is 2.8:1; #767676 is the lightest grey
       that still clears 4.5:1 on white, so it reads as a hint without failing contrast. */
    --roc-text-placeholder: #767676;
    /* Surfaces */
    --roc-surface: #FFFFFF; /* page background and card/table body fill — see html, body below */
    --roc-surface-muted: #F5F5F5; /* BGV Light Grey — card / table header bands, hover chrome */
    --roc-surface-hover: #F0F0F0; /* neutral light grey — hovered / selected row & tile */
    /* Its one consumer is .badge below. It also held the Theater available slot until AB#8203 gave
       that a solid --roc-color-accent-hover fill; .roc-time-slot (AB#8158) is where an available-slot
       role would come back, so keep the name rather than folding it into a badge-only token. */
    --roc-surface-tint: #EAF2F9; /* palest BGV Blue — badges */
    /* The palest neutral fill — reads as barely-not-white. Zebra banding is its most visible use,
       so --roc-row-alt stays the name table rules reach for, but it is an alias rather than a second
       hex: anything that is not a table row (the Day Use calendar's non-rule day, for one) should
       reference --roc-surface-subtle, so re-tuning table banding later cannot silently restyle
       surfaces that merely happened to want the same off-white. */
    --roc-surface-subtle: #FAFAFA;
    --roc-row-alt: var(--roc-surface-subtle); /* zebra-striped even row */
    /* Borders — neutral greys from the BGV grey family */
    --roc-border: #E4E4E4; /* card / panel borders */
    --roc-border-muted: #C8C8C8; /* muted / disabled icon, disabled stub */
    /* Danger — validation errors and the occupied time slot */
    /* Named for border/fill, and 3.93:1 on white puts it under the 4.5:1 normal-text floor — but it is
       also sanctioned as a text colour on LARGE text only, where the bar is 3:1. The Day Use Parking
       cards use it on their 22.75px/700 headline number for exactly that reason (both sheets pin the
       size, so the number cannot shrink under 18.67px while keeping this token). Normal-size danger
       text takes --roc-danger-border below. */
    --roc-danger: #E24B4A; /* error border / fill; text only at >= 18.67px bold / 24px regular */
    --roc-danger-rgb: 226, 75, 74; /* channels of --roc-danger — see --roc-color-accent-rgb above */
    --roc-danger-bg: #F7C1C1; /* error fill behind --roc-danger-text */
    --roc-danger-text: #791F1F; /* text on --roc-danger-bg */
    /* The spec uses #A32D2D for two things: the occupied slot's hover border AND validation-message
       text on white (7.07:1). The name reads as the former; the ratio is why it works as the latter. */
    --roc-danger-border: #A32D2D;
    /* Severity — the band behind a notification, one triplet per level (AB#8174).
       Deliberately separate from the --roc-danger-* group above, and the discriminator is the
       border, not the fill: both fills are pale (--roc-danger-bg is #F7C1C1), but
       --roc-danger-border is 4.5:1 on its own fill — a visible edge, and the same value doubles as
       validation text on white at 7.07:1 — where --roc-severity-danger-border is 1.17:1, a hairline
       tint. Same -border suffix, opposite roles. .theater-booked is the worked example: a pale
       --roc-danger-bg fill outlined in the dark --roc-danger-border, pinned by
       TheaterAvailabilitySlotColourTests. So collapsing the two groups would be visible — a toast
       would gain a dark rule where it now has a tint.
       Values are Bootstrap 5.0-5.2's alert palette, which is what ToastContainer already rendered;
       this group gave those literals a name, it did not restyle them, so there is no visual change
       to diff against. Deliberately NOT the vendored 5.3.3's alert values: bootstrap.min.css is
       5.3.3, whose *-bg-subtle match these four fills but whose *-border-subtle differ on all four
       and whose *-text-emphasis differ on success and danger. Adopting 5.3.3 would be a restyle of
       the only consumer, which is not this card's to make — so a .toast-danger and a real
       .alert-danger differ in text and border colour, and CONTRIBUTING.md's severity bullet scopes
       the rule to notification surfaces for that reason.
       Contrast: the bg/text pairs are 7:1 or better on their own fill (success 7.21, info 7.65,
       warning 7.21, danger 7.08 — AAA for normal text). The borders are tints, not boundaries:
       1.06-1.17:1 on their fills, and the fills are themselves <= 1.34:1 on white, so a band is
       delimited by its text and its own controls rather than by its edge. Anything that needs the
       3:1 boundary of CONTRIBUTING.md's non-text rule has to supply it — which is also why the
       severity bullet carries "never colour alone" forward.
       Not a token for a feature's own status colour: those stay with their component (the Bonus
       Time green in DayUseCalendar.razor.css, the amber in RateCalculator.razor.css). */
    --roc-severity-success-bg: #D1E7DD;
    --roc-severity-success-text: #0F5132;
    --roc-severity-success-border: #BADBCC;
    --roc-severity-info-bg: #CFF4FC;
    --roc-severity-info-text: #055160;
    --roc-severity-info-border: #B6EFFB;
    --roc-severity-warning-bg: #FFF3CD;
    --roc-severity-warning-text: #664D03;
    --roc-severity-warning-border: #FFECB5;
    --roc-severity-danger-bg: #F8D7DA;
    --roc-severity-danger-text: #842029;
    --roc-severity-danger-border: #F5C2C7;
    /* The legacy dark table-header greys (#CCCCCC / #B5B5B5 / #C0C0C0) are gone. Every grid header
       is now the --roc-surface-muted band, bordered with --roc-border and hovered with
       --roc-surface-hover; the six consumers moved in the same change so no grid was left half
       reskinned. */
    /* Radii — controls (buttons, inputs, tabs, pills) vs containers (cards, tables). */
    --roc-radius-control: 4px;
    --roc-radius-container: 8px;
    /* Spacing scale — defined ahead of the sweeps that consume it, so the per-surface PRs argue
       about markup rather than re-deriving the scale. --roc-space-5 has no consumer yet; the rest
       are in use, so do not read this group as unconsumed. */
    --roc-space-1: 4px;
    --roc-space-2: 8px;
    --roc-space-3: 12px;
    --roc-space-4: 16px;
    --roc-space-5: 24px;
    /* Control sizing — a capped action button, so a long label wraps instead of stretching the
       button across its column. Not on the spacing scale: it is a control's own width, not a gap. */
    --roc-size-button-cap: 160px;
    /* Focus — one ring for every focusable surface, wired up in the :focus-visible block below */
    --roc-focus-ring: 0 0 0 3px rgba(var(--roc-color-accent-rgb), 0.4);
    --roc-focus-ring-danger: 0 0 0 3px rgba(var(--roc-danger-rgb), 0.4); /* same ring on an errored input */
    /* Overlays */
    --roc-modal-backdrop: rgba(0, 0, 0, 0.5); /* dim behind a statically-shown modal */
    /* Elevation — a panel lifted off the page rather than a dim laid over it, which is why this is
       its own group and not an "overlay". A whole box-shadow rather than just its colour, for the
       same reason --roc-focus-ring is one: the offsets and blur are as much a part of the treatment
       as the tint, and splitting them leaves the rgba() stranded in component CSS with nothing to
       reference. One consumer today, the mobile sections dropdown. */
    --roc-shadow-raised: 0 6px 12px rgba(0, 0, 0, 0.15);
}

/* Bootstrap dims what is behind a modal with a SEPARATE .modal-backdrop element that only its
   JS renders. ROC shows modals statically (.modal.show.d-block, no Bootstrap JS), so each one
   has to supply its own dim — this is the one place it comes from. Use it on the .modal element
   rather than hand-rolling an inline background-color, which also sidesteps the palette above.
   AB#8058 retires the remaining hand-rolled copies. Their count is not tracked here — a
   comment goes stale the moment a page converts, which is what happened when Theater took
   two of them (AB#8150). RocDesignSystemMarkupTests enumerates them instead and fails if an
   entry in its list stops offending, so the list can only shrink. */
.roc-modal-backdrop {
    background-color: var(--roc-modal-backdrop);
}

/* On-brand highlight (BGV Orange @ 25% tint) for calling out a field row such as the
   rental Level. Applied to the row's label + value cells so it reads as one continuous
   bar, replacing raw Bootstrap bg-warning (off-palette). */
.roc-highlight {
    background-color: var(--roc-color-orange-tint);
    color: var(--roc-color-primary);
}

/* Bootstrap's .table > :not(caption) > * > * paints every cell, so the role needs table scope
   to reach a grid cell. */
.table > tbody > tr > td.roc-highlight {
    background-color: var(--roc-color-orange-tint);
    color: var(--roc-color-primary);
}

/* Right-align the labels in the rental-detail field lists so each label sits next to its
   value instead of at the far edge of its column. */
.detail-fields dt {
    text-align: right;
}

/* Bootstrap's default dd bottom-margin makes the flex row taller than the dd's own box,
   stretching the dt (label) cell taller than the dd (value) cell — which left the Level
   highlight uneven. Zeroing it keeps the bar the same height across both cells. */
.detail-fields dd {
    margin-bottom: 0;
}

/* The page is white and the #F5F5F5 bands (card headers, table headers, hover rows) read as chrome
   on top of it — the reverse of the grey-page/white-card arrangement this replaces. The layout's
   own .page / .main-content also paint --roc-surface-muted, so they move with this or they cover
   the body and nothing changes; they are the actual page background.
   The 14px → 13px base is the spec's body size, and it rescales every rem-based Bootstrap value
   (heading sizes, card padding, gutters) by the same 7% — that is app-wide and intended, not a
   side effect to undo per page. */
html, body {
    font-family: 'Open Sans', Arial, Helvetica, sans-serif;
    font-size: 13px;
    color: var(--roc-text);
    background-color: var(--roc-surface);
    -webkit-font-smoothing: antialiased;
}

/* Type roles (spec §2). The element selector carries each role so a page writes <h1>/<h2>/<h3> and
   gets the right treatment without decorating every heading with a class; the paired .text-* class
   is the same role on an element that is not a heading. Sizes stay literal px: they are absolute by
   design (a 13px body against a 22px title), and putting them behind rem would re-couple them to the
   root size the line above just changed. */
h1, .text-page-title {
    color: var(--roc-color-primary);
    font-weight: 700;
    font-size: 22px;
    text-transform: uppercase;
    letter-spacing: 0.04em; /* not in the spec — kept from the previous h1 so titles keep their set width */
}

h2, .text-section-heading {
    color: var(--roc-color-primary);
    font-weight: 600;
    font-size: 15px;
}

/* The card/table-header band and a field label are byte-identical treatments. Both names are kept
   because they mark different intent — a header over many values vs. the label on one — and a later
   change to either should not silently move the other. */
h3, .text-card-header, .text-field-label {
    color: var(--roc-color-primary);
    font-weight: 600;
    font-size: 13px;
}

/* A modal title sits a step above the card-header band: it titles the whole dialog, the way an h1
   titles a page. Bootstrap's .modal-title carries no size of its own, so a title marked up as <h3>
   used to land on the rule above and read byte-identically to a sub-heading inside the same dialog.
   Sizing the class rather than a heading level roles every <hN class="modal-title"> at once and
   leaves each page free to pick the level its own document outline needs — the same decoupling
   .card-header already relies on further down. */
.modal-title {
    color: var(--roc-color-primary);
    font-weight: 600;
    font-size: 15px;
}

/* An alert rendered as the whole page body — MainLayout's error boundary, NotYetPorted,
   LegacyBackofficeNotice, PendingPortNotice, and TourReferralResults' empty state. Every one of them
   wants <h1>, because the notice is the only heading on the page and the outline has to open
   somewhere; none of them is a page title. That is a problem here and nowhere else, because h1 is the
   only type role carrying text-transform and letter-spacing (.roc-nav-pill carries both, but no
   heading wears it), so a notice left on the level renders "SOMETHING WENT WRONG" in 22px caps
   (AB#8274). MainLayout is the app's global failure screen, though not the only screen that reads in
   caps: App.razor and NotFound.razor are <h1 class="display-5">, and .display-5 sets no
   text-transform, so both keep the uppercase this rule removes here.
   Like .modal-title above, sizing the class frees the level to follow the outline. Unlike it, this
   role has to *replace* the page-title role rather than sit beside it: whatever property it leaves
   undeclared keeps leaking down from h1. Three of the five notices used to carry Bootstrap's .h5,
   which bought the size alone — exactly how the caps survived a fix aimed at them — while MainLayout
   was already a bare <h1> and TourReferralResults was an <h2>.
   So every property THIS SHEET's h1 rule declares is answered below, and RocTypeRoleTests holds that
   true. Bootstrap's own h1 also sets margin-top, margin-bottom and line-height; those keep applying
   and are deliberately left alone, being layout rather than role.
   Only those three moved to the 15px section step from 16.25px (Bootstrap's .h5 at 1.25rem against
   the 13px root). MainLayout fell further, 22px to 15px, since it was reading at the h1 step that
   made this a bug; TourReferralResults did not move at all, because an <h2> was already 15px.
   colour is the one deliberately handed back: `inherit` takes the surrounding alert's colour, so a
   danger notice reads danger rather than navy. */
.alert-heading {
    color: inherit;
    font-weight: 600;
    font-size: 15px;
    text-transform: none;
    letter-spacing: normal;
}

/* One step below the card/table header, for a grouping inside a card body or a dialog where an <h3>
   would collide with the header band directly above it. h4-h6 carried no rule at all before this, so
   they took Bootstrap's weight 500 and heading colour instead of the system's 600 and navy, and their
   sizes came off Bootstrap's rem/vw scale while every other role here is absolute px: a bare <h4> sat
   around 19.5-20.2px against the 13px root — between the h2 and h1 steps, owning neither, and moving
   with the viewport because the sub-1200px size is calc(1.275rem + .3vw).
   A page-level message that wants the section-heading size takes <h2>, not a smaller level. */
h4, h5, h6, .text-subheading {
    color: var(--roc-color-primary);
    font-weight: 600;
    font-size: 12px;
}

/* Bootstrap owns .text-body and .text-secondary and sets their colour with !important, so these
   cannot simply restate `color`. Both resolve rgba() from a Bootstrap channel variable at use time,
   and a custom property declared on the same element wins there — so re-pointing the variable
   re-tints the utility without !important, the same trick .btn uses for its focus shadow below.
   Caveat: custom properties inherit, so a .bg-secondary nested inside a .text-secondary element
   picks up the BGV grey too. That is the palette either way, which is why it is left alone. */
.text-body {
    --bs-body-color-rgb: var(--roc-text-rgb);
    font-weight: 400;
    font-size: 13px;
}

.text-secondary {
    --bs-secondary-rgb: var(--roc-text-muted-rgb);
    font-weight: 400;
    font-size: 13px;
}

/* Clickable text that is not a button and not an <a> (those are covered further down). The accent
   is 3.70:1 on white and fails AA at this size, so text takes --roc-color-link. */
.text-link {
    color: var(--roc-color-link);
    font-weight: 400;
    font-size: 13px;
    cursor: pointer;
    transition: color 0.15s ease;
}

.text-link:hover {
    color: var(--roc-color-primary);
}

.text-disabled {
    color: var(--roc-text-disabled);
    font-weight: 400;
    font-size: 13px;
    cursor: not-allowed;
}

/* Hint / example text. The italic is what separates it from real content at the same size; the
   colour cannot go lighter without failing contrast — placeholders are not AA-exempt. */
.text-placeholder {
    color: var(--roc-text-placeholder);
    font-weight: 400;
    font-size: 13px;
    font-style: italic;
}

/* Blazor focuses the routed h1 (tabindex="-1") after navigation. When the click that navigated was
   a keypress, :focus-visible matches, so without suppressing the ring here every keyboard nav would
   draw one around the page title. */
h1:focus {
    outline: none;
    box-shadow: none;
}

/* One focus treatment for every focusable surface. Replaces the rings that were in play: the
   off-palette #258cfb one that used to live here, and Bootstrap's own #86b7fe border plus its
   several rgba(13,110,253,.25) shadows.
   The bare :focus-visible only reaches plain elements — Bootstrap styles its components' focus
   states at two-class specificity, which outranks it, so every Bootstrap component ROC actually
   uses has to be named here or it keeps Bootstrap's blue. When adding a Bootstrap component that
   ships its own :focus / :focus-visible rule, add it to this list; `grep -o '[^,{}]*:focus[^,{}]*'
   lib/bootstrap/bootstrap.min.css` lists the candidates.
   Buttons and links key off :focus-visible (ring on keyboard focus, not on every mouse click);
   text inputs key off :focus, where a ring on click is the expected affordance.
   The spec's `border-radius: 3px` is left off: as a global rule it would override each element's
   own radius, and the shadow already follows that radius.
   `outline: 2px solid transparent` rather than `outline: none` — forced-colors mode (Windows High
   Contrast) suppresses box-shadow entirely but forces a transparent outline to a visible system
   colour, so this is the only thing keeping focus visible there. Do not "simplify" it to none.
   Mind the extent: these two declarations reach FURTHER than the ring does. The outline's outer
   edge sits at outline-offset + outline-width = 4px past the border box, against the ring's 3px
   spread, so 4px is the clearance any surface below has to give a focused control — and in
   forced-colors mode the outline is the only indicator left, so it is the one that matters most.
   Known limitation: the decoration is clipped by an ancestor with a non-visible overflow, so focus
   on the first/last row inside .table-responsive can be partly cut off. Same for anything at the
   edge of .roc-data-table-wrap, which sets overflow: hidden — clipping applies whether or not the
   box actually overflows, which is exactly why .card omits overflow: hidden below. A scroll box can
   buy the decoration room with block-axis padding and a matching negative margin — .section-nav
   does exactly that in NavMenu.razor.css — but that only covers the axis the content does not
   scroll along, so it is a per-surface fix rather than something this rule can do for everyone.
   Swapping box-shadow for outline does NOT fix this: an ancestor's overflow clips a descendant's
   outline exactly as it clips its shadow, so the decoration is cut off either way. Short of the
   per-surface padding above, the only ring that survives a clipping ancestor is one drawn inside
   the element's own box — a negative outline-offset — which buys clip-immunity by painting over the
   control's edge instead of around it. An inset box-shadow is NOT an equivalent option: it would
   leave nothing at all in forced-colors mode, where box-shadow is suppressed. So the surviving
   option is a different look on every focusable surface and a deliberate deviation from the spec,
   which names a box-shadow, and it stays a design-system owner's call — AB#8173.
   What is pinned and what is not: RocFocusRingClippingTests measures the extent above out of these
   declarations and holds .section-nav's padding at or above it, so that one mitigation cannot drift.
   Nothing pins the paragraph itself — both stylesheet guards strip comments before scanning, so a
   wrong claim here cannot fail a build. Re-verify in a browser before acting on it. */
/* Bootstrap rings these two on :focus, which fires on mouse click too. Cancel that first, then the
   rule below re-applies the ring on :focus-visible so they behave like every other button. Order
   matters: both selectors match a keyboard focus, so the ring has to come second to win. */
.btn-close:focus, .page-link:focus {
    box-shadow: none;
}

:focus-visible,
.btn:focus-visible,
.nav-link:focus-visible,
.btn-close:focus-visible,
.page-link:focus-visible,
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: var(--roc-focus-ring);
}

/* Border colour only applies to the input family — the buttons and links above keep their own. */
.form-control:focus, .form-select:focus, .form-check-input:focus {
    border-color: var(--roc-color-accent);
}

/* Bootstrap raises .btn's focus shadow to three- and four-class specificity while a button is
   active or shown (.btn.active:focus-visible, .btn:first-child:active:focus-visible, …), which
   outranks the list above — every one of those reads this variable, so overriding it here covers
   them all instead of restating each selector. Same trick .alert-info uses further down. */
.btn {
    --bs-btn-focus-box-shadow: var(--roc-focus-ring);
}

/* Validated inputs: Bootstrap's .is-invalid focus rules are three-class and keep their own red
   0.25rem ring. The error ring is right in principle, just off-palette — re-tint it rather than let
   a second ring style survive. The border has to be restated too, or the accent border from the
   rule above would repaint a focused errored field blue. The unfocused border and the message
   colour move with the validation rewire (.invalid + .validation-message), not here. */
.form-control.is-invalid:focus, .form-select.is-invalid:focus, .form-check-input.is-invalid:focus,
.was-validated .form-control:invalid:focus, .was-validated .form-select:invalid:focus {
    border-color: var(--roc-danger);
    box-shadow: var(--roc-focus-ring-danger);
}

/* The switch knob is a background-image, so its focused variant can only be re-tinted by restating
   the SVG. This is the one place a literal hex is unavoidable — url() cannot read a custom property.
   Keep the fill in step with --roc-color-accent. */
.form-switch .form-check-input:focus {
    --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%235B89B4'/%3e%3c/svg%3e");
}

/* Link text takes the darkened blue, not --roc-color-accent: the accent is 3.70:1 on white and
   fails AA at body size. Hover goes to navy (11.81:1) per the spec. */
a {
    color: var(--roc-color-link);
}

a:hover {
    color: var(--roc-color-primary);
}

/* .btn-link is a button wearing a link's clothes, so it takes the palette the way the roles below
   do, not the way `a` does. `color` on the class is only (0,1,0): Bootstrap repaints hover and
   keyboard focus from --bs-btn-hover-color at (0,2,0), which .btn-link points at --bs-link-hover-color
   (#0a58ca) — the same off-palette blue, and the same specificity mistake, the button block below
   exists to fix. All nine `btn btn-link` sites were showing it. Variables win at any specificity.
   Disabled is left on Bootstrap's #6c757d at .65 opacity, as it was. */
.btn-link {
    --bs-btn-color: var(--roc-color-link);
    --bs-btn-hover-color: var(--roc-color-primary);
    --bs-btn-active-color: var(--roc-color-primary);
}

/* ============================ Button roles (spec §3) ============================
   The agreed old→new mapping (AB#8142) — every button role in the spec, which is not the same as
   every button in ROC. The two commit-weight classes are aliased onto one treatment rather than
   migrated, so no .razor markup changes in this layer:

     .btn-primary, .btn-roc-accent  →  COMMIT     navy fill, light text
     .btn-outline-secondary         →  SELECTOR   accent outline, fill when .active
     .btn-secondary                 →  SECONDARY  white fill, navy text, grey border
     .roc-icon-link                 →  ICON LINK  (net-new, no container)

   .btn-primary and .btn-roc-accent are deliberately one role under two names: the pair used to be
   a quiet grey commit and a loud blue commit, and the spec has a single Commit button. Collapsing
   the names is a later sweep's job — 75 usages across 47 files.
   The two time-slot roles are net-new component work and land with AB#8158, not here.
   Bootstrap variants the spec never named keep their stock palette until a sweep maps them:
   .btn-danger, .btn-success, .btn-outline-primary and .btn-outline-danger are all live in ROC and
   none of them is a role below. .btn-link is the exception — it is handled above, with the links.

   Contrast: the spec's hover for Commit is the accent itself, which puts light text at 3.70:1 —
   below AA, and a regression from navy's 11.81:1. Hover/active fills therefore use
   --roc-color-accent-hover (#46708F, 4.76:1 against --roc-text-light), which reads as the same move
   toward the accent while staying legible. Same substitution fixes .btn-roc-accent's and
   .roc-nav-pill.active's existing AA failures, which is why they are resolved here rather than
   deferred again.
   Text on a dark fill is --roc-text-light, the token already defined for exactly that, rather than
   the literal #fff these rules used to carry.

   Each role is expressed as --bs-btn-* variables rather than as a list of state selectors. That is
   not a style preference: Bootstrap reads these variables from .btn:hover (0,2,0),
   .btn:focus-visible (0,2,0) and .btn.active/.btn:first-child:active/:not(.btn-check)+.btn:active
   (0,2,0 and 0,3,0). A role rule is only (0,1,0), so restating `background-color` per state loses
   every one of those — most visibly on :focus-visible, which repaints a keyboard-focused button
   with Bootstrap's --bs-btn-hover-bg. Setting the variables wins at any specificity, so hover,
   keyboard focus and the pressed state all follow the palette without naming a single state
   selector. See the two-class-specificity note in CONTRIBUTING.md.

   The trade: only Bootstrap's own .btn rules read these variables, so a role class now paints
   nothing on its own. That is free for the three Bootstrap names, which are never written without
   .btn, but .btn-roc-accent is OURS — it used to set background-color directly and would have
   worked bare. All 52 current usages pair it with .btn; keep it that way, or give it back a
   literal declaration. */

/* 1. COMMIT */
.btn-primary, .btn-roc-accent {
    --bs-btn-color: var(--roc-text-light);
    --bs-btn-bg: var(--roc-color-primary);
    --bs-btn-border-color: var(--roc-color-primary);
    --bs-btn-hover-color: var(--roc-text-light);
    --bs-btn-hover-bg: var(--roc-color-accent-hover);
    --bs-btn-hover-border-color: var(--roc-color-accent-hover);
    --bs-btn-active-color: var(--roc-text-light);
    --bs-btn-active-bg: var(--roc-color-primary-active);
    --bs-btn-active-border-color: var(--roc-color-primary-active);
    /* The spec's disabled fill is the same grey as a card/table header band, so a disabled commit
       button sitting on one is defined only by its border. Kept as specified; the border is what
       carries it. Opacity 1 because the palette above already reads as disabled — Bootstrap would
       otherwise dim it to .65 on top. */
    --bs-btn-disabled-color: var(--roc-text-disabled);
    --bs-btn-disabled-bg: var(--roc-surface-muted);
    --bs-btn-disabled-border-color: var(--roc-border);
    --bs-btn-disabled-opacity: 1;
}

/* 2. SELECTOR — a set of mutually exclusive choices (e.g. Week (5+2) / Weekdays (5) / Weekend (2)).
   Border keeps the accent (3:1 is the non-text threshold); the label takes --roc-color-link.
   Disabled is left on Bootstrap's outline defaults, as it was — the role has no disabled treatment
   in the spec yet. */
.btn-outline-secondary {
    --bs-btn-color: var(--roc-color-link);
    --bs-btn-bg: var(--roc-surface);
    --bs-btn-border-color: var(--roc-color-accent);
    --bs-btn-hover-color: var(--roc-color-primary);
    --bs-btn-hover-bg: var(--roc-surface-muted);
    --bs-btn-hover-border-color: var(--roc-color-primary);
    --bs-btn-active-color: var(--roc-text-light);
    --bs-btn-active-bg: var(--roc-color-accent-hover);
    --bs-btn-active-border-color: var(--roc-color-accent-hover);
}

/* Bootstrap orders .btn.active after .btn:hover at equal specificity, so a chosen selector that is
   also hovered keeps its active fill. Deepening it to navy is the one state no variable expresses;
   (0,3,0) is what it takes to outrank .btn.active.
   Nothing renders it yet: no ROC markup puts .active on a .btn-outline-secondary. The one genuine
   selector group, TourReferrals.razor:101, swaps the class instead (btn-primary when chosen), so
   the chosen option currently reads as COMMIT. The filled state below is the role as specified,
   waiting on that call site — not dead by accident. */
.btn-outline-secondary.active:hover {
    color: var(--roc-text-light);
    background-color: var(--roc-color-primary);
    border-color: var(--roc-color-primary);
}

/* 3. SECONDARY — dismisses or cancels; submits nothing and changes nothing (Close, Cancel). */
.btn-secondary {
    --bs-btn-color: var(--roc-color-primary);
    --bs-btn-bg: var(--roc-surface);
    --bs-btn-border-color: var(--roc-border);
    --bs-btn-hover-color: var(--roc-color-primary);
    --bs-btn-hover-bg: var(--roc-surface-muted);
    --bs-btn-hover-border-color: var(--roc-color-primary);
    --bs-btn-active-color: var(--roc-color-primary);
    --bs-btn-active-bg: var(--roc-surface-muted);
    --bs-btn-active-border-color: var(--roc-color-primary);
    --bs-btn-disabled-color: var(--roc-text-disabled);
    --bs-btn-disabled-bg: var(--roc-surface-muted);
    --bs-btn-disabled-border-color: var(--roc-border);
    --bs-btn-disabled-opacity: 1;
}

/* 4. ICON LINK — a bare actionable icon with no button container (e.g. the Owner Relations grid).
   :disabled only matches form elements and .disabled is what an <a> can carry, so both are needed;
   pointer-events keeps a disabled anchor from navigating, which `cursor` alone does not do. */
.roc-icon-link {
    color: var(--roc-color-link);
    cursor: pointer;
    transition: color 0.15s ease;
}

.roc-icon-link:hover {
    color: var(--roc-color-primary);
}

.roc-icon-link:disabled, .roc-icon-link.disabled {
    color: var(--roc-border-muted);
    cursor: not-allowed;
    pointer-events: none;
}

/* ================= Containers: cards, sections, tables, badges (spec §4) =================
   Every container shares one silhouette: a light-grey header band, a 1px grey outline, and a 3px
   accent bar down the left edge with that side's corners squared so the bar reads as a spine.
   The spec's 0.5px borders are deliberately 1px here — 0.5px rounds to 0 or 1 device pixel
   depending on DPI, and the spec itself pairs 0.5px chrome with 1px inputs, so a card edge would
   not line up with the input beside it.
   These restyle the Bootstrap classes in place; there is no .roc-card duplicate. */

/* Bootstrap drives .card entirely through --bs-card-*, so setting those re-skins the component —
   including the header's inner radius, which it derives from the card radius — instead of fighting
   its selectors. Only the left spine has no variable behind it.
   The spec's `overflow: hidden` is deliberately omitted: it would clip the focus ring on any
   control near the card's edge (see the known limitation on the focus rule above). Bootstrap's own
   inner-radius handling rounds the header band without it. */
.card {
    --bs-card-bg: var(--roc-surface);
    --bs-card-color: var(--roc-text);
    --bs-card-border-color: var(--roc-border);
    --bs-card-border-width: 1px;
    --bs-card-border-radius: var(--roc-radius-container);
    --bs-card-inner-border-radius: var(--roc-radius-container);
    --bs-card-cap-bg: var(--roc-surface-muted);
    --bs-card-cap-color: var(--roc-color-primary);
    --bs-card-cap-padding-y: var(--roc-space-3);
    --bs-card-cap-padding-x: var(--roc-space-4);
    --bs-card-spacer-y: var(--roc-space-4);
    --bs-card-spacer-x: var(--roc-space-4);
    border-left: 3px solid var(--roc-color-accent);
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* Bootstrap rounds a leading header's top corners from the inner radius; the left one has to come
   back off or it would bow away from the spine. */
.card > .card-header:first-child {
    border-top-left-radius: 0;
}

.card-header {
    font-weight: 600;
    font-size: 13px;
}

/* Data grid. The wrapper carries the outline and spine so the table itself can stay borderless and
   its header band can sit flush against the top edge. */
.roc-data-table-wrap {
    border: 1px solid var(--roc-border);
    border-left: 3px solid var(--roc-color-accent);
    border-radius: 0 var(--roc-radius-container) var(--roc-radius-container) 0;
    overflow: hidden;
}

.roc-data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.roc-data-table th {
    text-align: left;
    background-color: var(--roc-surface-muted);
    color: var(--roc-color-primary);
    font-weight: 600;
    padding: var(--roc-space-2) var(--roc-space-3);
    border-bottom: 1px solid var(--roc-border);
}

.roc-data-table td {
    padding: var(--roc-space-2) var(--roc-space-3);
    color: var(--roc-text);
    border-bottom: 1px solid var(--roc-border);
}

/* The wrapper's own edge closes the grid, so the last row's rule would double it. */
.roc-data-table tr:last-child td {
    border-bottom: none;
}

.roc-data-table tbody tr:hover {
    background-color: var(--roc-surface-muted);
}

/* .table paints background-color on every cell, which covers the row rule above; the state variable
   is what the cell actually reads. */
.roc-data-table tbody tr:hover > * {
    --bs-table-bg-state: var(--roc-surface-muted);
}

/* Zebra striping stays Bootstrap's .table-striped — already on 37 tables across 31 files — rather
   than the spec's own nth-child rule, so there is one mechanism rather than two that disagree about
   which rows are tinted. .roc-data-table deliberately declares no stripe of its own; compose the
   two classes when a grid wants banding. */
.table-striped {
    --bs-table-striped-bg: var(--roc-row-alt);
}

/* Row-level action (edit / delete / open). Darkens with its own hover and with the row's, so the
   whole row reads as one target. */
.roc-table-action-icon {
    color: var(--roc-color-link);
    cursor: pointer;
    transition: color 0.15s ease;
}

.roc-table-action-icon:hover,
.roc-data-table tbody tr:hover .roc-table-action-icon {
    color: var(--roc-color-primary);
}

/* Shape applies to every badge; the colour pair does not. Bootstrap's .bg-* utilities set
   `background-color … !important`, so on a `badge bg-danger` the tint below loses but
   --bs-badge-color still wins — navy text stranded on a saturated fill (#1F3956 on #dc3545 is
   2.61:1, down from 4.53:1 with Bootstrap's #fff). Fill and text therefore move together or not at
   all: the seven live `badge bg-*` sites keep Bootstrap's pairing until the sweep migrates them.
   Which leaves the ROC tint with nothing to paint today — all seven rendered badges carry a bg-*
   class, and the only bare <span class="badge"> in the tree is inside GroupAuthorizeView's usage
   comment. The rule is the role for the sweep to migrate onto, not a live treatment; §4's badge is
   shape-only until then.
   The bg-* test is a substring match, so it also stands aside for a badge carrying only
   .bg-gradient, .bg-opacity-* or 5.3's .text-bg-* — none of which necessarily supplies a
   background-color. Nothing in ROC does today; if the sweep needs to be exact, a .roc-badge opt-in
   is the precise version of this. */
.badge {
    font-size: 11px;
    font-weight: 600;
    padding: var(--roc-space-1) var(--roc-space-2);
    border-radius: 12px; /* a pill at badge height — not the control/container radii, which are squarer */
    display: inline-block;
}

.badge:not([class*="bg-"]) {
    --bs-badge-color: var(--roc-color-primary);
    background-color: var(--roc-surface-tint);
}

/* Cap an action button's width so a long label wraps instead of stretching the button across its
   column. Bootstrap has no max-width utility, hence the named class. The 160px that #4950 deferred
   to this file's token layer is now --roc-size-button-cap — call sites unchanged, as promised. */
.btn-roc-capped {
    max-width: var(--roc-size-button-cap);
}

/* Re-tint Bootstrap's info-alert to BGV Grey by overriding its scoped --bs-alert-bg
   and --bs-alert-color variables — .alert reads both from these vars, so no need to
   touch .alert itself or fight specificity. */
.alert-info {
    --bs-alert-color: var(--roc-text);
    --bs-alert-bg: var(--roc-surface-muted);
    --bs-alert-border-color: var(--roc-border);
    --bs-alert-link-color: var(--roc-color-link); /* accent is only 3.39:1 on the light-grey alert fill */
}

/* Cap rate-builder + folio-payments tables at ~half width on wide desktops so the
   short label/value rows don't get visually pulled apart by the empty horizontal
   space between the label and its figure. Below the lg breakpoint, the table goes
   back to full-width responsive so the figures remain readable on narrow screens.
   Rate-quote tables get a lighter trim — five columns wide, so still need most of
   the row but not the full 1920+ stretch. */
@media (min-width: 992px) {
    .rate-builder-table {
        width: 50%;
    }

    .rate-quote-table {
        width: 75%;
    }
}

/* Shared nav "pill" — the uppercase, white, rounded link recipe used by both the main nav
   buttons (NavMenu) and the user name (UserBar). Lifted here so the two surfaces stay in sync
   instead of duplicating the rule across two scoped stylesheets. Components add only their
   own layout extras (e.g. UserBar's icon flex/gap) on top of this class.
   Both consumers render inside a .navbar-nav (NavMenu's section list, UserBar's profile block),
   which is where the Bootstrap overrides noted here and on .active below come from. The horizontal
   padding is one: at >= 768px, .navbar-expand-md .navbar-nav .nav-link (0,3,0) restates
   padding-left/right from --bs-navbar-nav-link-padding-x, so 0.85rem only applies below the
   breakpoint and the pills ship at 0.5rem on desktop. Left alone on purpose — forcing it through
   the variable would re-space the nav on every page, which is a design change, not a cascade fix. */
.roc-nav-pill {
    padding: 0.45rem 0.85rem;
    color: var(--roc-text-light);
    font-weight: 500;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-decoration: none;
    border-radius: var(--roc-radius-control);
    white-space: nowrap;
}

/* The tint composites over the navy bar rather than replacing it, so the result stays dark and the
   label stays legible. */
.roc-nav-pill:hover {
    background-color: var(--roc-color-accent-tint);
    color: var(--roc-text-light);
    text-decoration: none;
}

/* Was the accent at 3.70:1 against its own label. The darkened accent is the same "active nav is
   blue" read at 4.76:1 against --roc-text-light — see the contrast note in the button block above.
   The label colour is set as --bs-navbar-active-color rather than as `color`, for the same reason
   the button roles set --bs-btn-*: inside a navbar, .navbar-nav .nav-link.active (0,3,0) owns that
   property, and .navbar-dark points it at #fff. The plain declaration this rule used to carry was
   (0,2,0) and never landed, so the pills actually shipped #fff — 5.28:1, not the 4.76:1 recorded
   here. Both clear AA, so this is not a contrast fix; it makes the token the design system names
   the one that paints, instead of quietly deferring to Bootstrap's white.
   Known gap, and it is not solvable by picking a better blue: this pill sits on the
   --roc-color-primary bar, so the fill owes 3:1 to #1F3956 to mark the active item AND the label
   owes 4.5:1 to the fill. Those bound the fill's luminance to >= 0.216 and <= 0.160 respectively —
   an empty range. Any fill legible under --roc-text-light is under 3:1 against the bar (this one is
   2.24:1, and the lighter accent it replaced was 2.39:1). Closing it needs a non-colour cue or a
   dark-on-light active pill, which is a design call — AB#8188, not a token tweak. Do not "fix" it
   by lightening the fill; that trades a visible boundary for an illegible label. */
.roc-nav-pill.active {
    --bs-navbar-active-color: var(--roc-text-light);
    background-color: var(--roc-color-accent-hover);
}

/* Resort logo tabs — the per-resort tab strip that lets an operator pick which resort a page
   applies to (Owner Week Calendar, Manage Day Use Availability Counts). Ported from
   UmbracoGC/wwwroot/css/tabs.css. Lifted here so the consuming pages stay in sync instead of
   duplicating the rule across scoped stylesheets (same rationale as .roc-nav-pill above).
   Inactive tabs use the _black silhouette on a grey background with a visible border; the
   active tab swaps to the _color logo on a white background and merges into the body below.
   Hover moves the border to the accent — the fill shifts too, but only from --roc-surface-muted to
   --roc-surface-hover, which is 1.045:1 and carries no affordance by itself.
   Sized 120x120 (100px logo) on desktop; the @media block drops to 60x60 (50px logo) on narrow
   viewports, mirroring legacy. */
.resort-logo-tab {
    width: 120px;
    height: 120px;
    padding: 0;
    background-size: 100px;
    background-position: center;
    background-repeat: no-repeat;
    background-color: var(--roc-surface-muted);
}
.resort-logo-tab:hover {
    background-color: var(--roc-surface-hover);
}

/* Border and radius are set at two-class specificity on purpose, and deliberately NOT on the rule
   above. All seven consuming pages render these as `.nav-link` inside `.nav .nav-tabs`, and
   Bootstrap's `.nav-tabs .nav-link` (0,2,0) paints a literal `transparent` border and sets both
   top-corner radii — a bare `.resort-logo-tab` (0,1,0) cannot outrank either, so anything declared
   there is simply never drawn. That is what left the strip defined by its band alone: #F5F5F5 on
   the white page is 1.09:1. Only border-color is restated, because the 1px and `solid` already
   come from Bootstrap. :hover/:focus and .active each need their own entry because Bootstrap
   restates border-color for both at (0,3,0); the rules below match that and win on source order. */
.nav-tabs .resort-logo-tab {
    border-color: var(--roc-border);
    border-top-left-radius: var(--roc-radius-control);
    border-top-right-radius: var(--roc-radius-control);
}

/* The accent, not --roc-border, because this is the whole hover cue: the fill only moves
   --roc-surface-muted → --roc-surface-hover, a 1.045:1 step that nobody sees. :focus is in the
   selector for a different reason — Bootstrap pairs it with :hover in the same (0,3,0) rule, so
   leaving it out would hand a keyboard-focused tab back Bootstrap's grey border. */
.nav-tabs .resort-logo-tab:hover,
.nav-tabs .resort-logo-tab:focus {
    border-color: var(--roc-color-accent);
}

/* Bottom edge takes the active fill so the selected tab merges into the panel below — Bootstrap's
   own three-value pattern for --bs-nav-tabs-link-active-border-color, and the reason the base rule
   no longer carries `border-bottom: none`. The background has to be restated here too:
   `.nav-tabs .nav-link.active` (0,3,0) owns it, so setting it at (0,2,0) had no effect. */
.nav-tabs .resort-logo-tab.active,
.nav-tabs .resort-logo-tab.active:hover {
    background-color: var(--roc-surface);
    border-color: var(--roc-border) var(--roc-border) var(--roc-surface);
}
.resort-logo-tab-gc8 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/gc8_black.png); }
.resort-logo-tab-gl7 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/gl7_black.png); }
.resort-logo-tab-gtl { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/gtl_black.png); }
.resort-logo-tab-ihpr { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/ihpr_black_transparent.png); }
.resort-logo-tab.active.resort-logo-tab-gc8 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/gc8_color.png); }
.resort-logo-tab.active.resort-logo-tab-gl7 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/gl7_color.png); }
.resort-logo-tab.active.resort-logo-tab-gtl { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/gtl_color.png); }
.resort-logo-tab.active.resort-logo-tab-ihpr { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/100x100/ihpr_color.png); }

/* Screen-reader-only resort label — visible to assistive tech, invisible visually. */
.resort-logo-tab-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

@media (max-width: 767px) {
    .resort-logo-tab {
        width: 60px;
        height: 60px;
        background-size: 50px;
    }
    .resort-logo-tab-gc8 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/gc8_black.png); }
    .resort-logo-tab-gl7 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/gl7_black.png); }
    .resort-logo-tab-gtl { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/gtl_black.png); }
    .resort-logo-tab-ihpr { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/ihpr_black.png); }
    .resort-logo-tab.active.resort-logo-tab-gc8 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/gc8_color.png); }
    .resort-logo-tab.active.resort-logo-tab-gl7 { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/gl7_color.png); }
    .resort-logo-tab.active.resort-logo-tab-gtl { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/gtl_color.png); }
    .resort-logo-tab.active.resort-logo-tab-ihpr { background-image: url(https://breckenridgegrandvacations.azureedge.net/umbraco10/media/images/logos/50x50/ihpr_color.png); }
}

.content {
    padding-top: 1.1rem;
}

/* ===================== Form inputs and validation (spec §5) =====================
   The styling lands on .form-control rather than the spec's .form-input: ROC carries 285 of the
   former across 42 files and a rename buys nothing.
   Validation is keyed to .invalid and .validation-message, the classes Blazor's EditForm actually
   emits — the spec's .form-input.error would never fire, because Blazor emits .valid / .invalid /
   .modified and never .error. .validation-message is also what E2E.Tests selects on, so the name
   stays put.
   What used to be here — a green outline on every touched-and-valid field, a red outline on invalid,
   and `color: red` — is deleted rather than kept alongside: an outline plus the border below would
   ring the same field twice, and the green "you typed something acceptable" outline has no
   counterpart in the spec.
   The focus ring, including the errored variant, is already settled further up and is deliberately
   not restated here. */
/* .form-select is styled alongside .form-control, not left to Bootstrap: the two sit side by side in
   almost every ROC form, and a select keeping Bootstrap's #dee2e6 border next to an input on
   --roc-border reads as a misalignment rather than a variant.

   Skin and density are split across three rules on purpose. The size modifiers .form-control-sm /
   .form-select-sm are (0,1,0), exactly the specificity of the bare class, and app.css loads after
   Bootstrap — so any padding or font-size named on the bare class silently wins and flattens the
   modifier into a no-op (66 usages: 44 .form-control-sm, 22 .form-select-sm). The skin below
   therefore names neither, and density lives in the two rules after it.
   Those two wrap the class in :where() so they stay (0,1,0) rather than the (0,2,0) a bare :not()
   would produce. That matters: at (0,2,0) they would start beating every two-class Bootstrap rule
   that currently wins, `.form-floating > .form-control` among them — trading this bug for the same
   one a level up. :where() contributes nothing to specificity, the :not() supplies the exclusion,
   and the modifiers keep the palette while owning their own density.
   border-radius stays in the skin on purpose, and it does flatten .form-control-sm's smaller
   --bs-border-radius-sm. That one is deliberate: colour, border and radius are skin, padding and
   font-size are density, and one control radius across every size is what §5 asks for — a size
   modifier is not licence to change the silhouette.
   What the 66 modifiers get back is Bootstrap's own .875rem / .25rem .5rem, and that is a real
   change: flattened, they had been rendering at the bare class's 13px / 8px 12px. :root sets html
   to 13px, so .875rem resolves to 11.375px — under the 13px body and the 12px validation message,
   over the 11px badge. Restoring the modifier is this fix; re-picking small-control density is a
   design call, and belongs to the per-surface sweeps. */
.form-control, .form-select {
    background-color: var(--roc-surface);
    border: 1px solid var(--roc-border);
    border-radius: var(--roc-radius-control);
    color: var(--roc-text);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

:where(.form-control):not(.form-control-sm, .form-control-lg) {
    padding: var(--roc-space-2) var(--roc-space-3);
    font-size: 13px;
}

/* The right padding is Bootstrap's own 2.25rem, not --roc-space-3. A .form-select carries the
   dropdown caret as a background-image at `right .75rem center`, 16px wide, and only its
   background-color is overridden here — so the caret survives any padding change. The shorthand
   this replaces cut the gutter from 2.25rem to 12px and long option text ran underneath the arrow.
   Staying in rem keeps the gutter tracking the caret's own rem-based offset. */
:where(.form-select):not(.form-select-sm, .form-select-lg) {
    padding: var(--roc-space-2) 2.25rem var(--roc-space-2) var(--roc-space-3);
    font-size: 13px;
}

.form-control::placeholder {
    color: var(--roc-text-placeholder);
    font-style: italic;
}

.form-control:disabled, .form-select:disabled {
    background-color: var(--roc-surface-muted);
    border-color: var(--roc-border);
    color: var(--roc-text-disabled);
    cursor: not-allowed;
}

/* .invalid is Blazor's; .is-invalid is Bootstrap's, and ROC markup uses both. Naming both here
   keeps a field's error state from depending on which one a page happened to apply. */
.form-control.invalid, .form-control.is-invalid,
.form-select.invalid, .form-select.is-invalid {
    border-color: var(--roc-danger);
}

/* 12px rather than the spec's 11px: an error is the one message a user must not miss, and 11px is
   below everything else in the type scale. Deviation recorded on AB#8144. */
.validation-message {
    color: var(--roc-danger-border);
    font-size: 12px;
    margin-top: var(--roc-space-1);
}

#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 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: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: 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: #e0e0e0;
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: #1b6ec2;
            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: #c02d76;
}

/* Outranks the .form-control::placeholder rule in the form block above, so it has to carry the same
   colour or floating-label fields would be the one place a placeholder is off-palette. The
   right-then-left text-align flip is the behaviour this rule exists for; only the colour moved. */
.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--roc-text-placeholder);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Hide the browser's native up/down spinner arrows on number inputs. Every BgvInputNumber
   carries the .bgv-input-number class, which scopes this to ROC's Rate Calculator and leaves
   other pages' number inputs untouched. Arrows are hidden when the input has no step (the
   default) or when it opts in with .bgv-input-number--no-spinner (HideSpinner="true"), which
   lets a field keep a step for decimal entry without showing the arrows. Inputs that set a
   step without opting in keep their arrows (e.g. Number of Nights, MLOS). */
.bgv-input-number:not([step])::-webkit-outer-spin-button,
.bgv-input-number:not([step])::-webkit-inner-spin-button,
.bgv-input-number--no-spinner::-webkit-outer-spin-button,
.bgv-input-number--no-spinner::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.bgv-input-number:not([step]),
.bgv-input-number--no-spinner {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Native <select> dropdown highlight — tint the hovered / selected <option> with BGV Light
   Grey instead of the browser's default (typically a blue OS accent). Browser support varies:
   Chromium and Firefox honor the option background for the checked / hovered item; on some
   platforms the open list is OS-rendered and may ignore this. */
option:hover,
option:focus,
option:checked {
    background-color: var(--roc-surface-muted);   /* BGV Light Grey */
    color: var(--roc-text);
}

/* Shared resort-selector layout: a left ResortTabs sidebar next to the page body. Backs both
   ResortSelectorLayout and OnPropertyLayout (identical full-height sidebar shell). The
   bonus-time layout is a separate sticky variant that keeps its own scoped styles. */
.resort-selector-layout {
    display: flex;
    gap: 1.5rem;
    align-items: flex-start;
}

.resort-selector-sidebar {
    width: 200px;
    flex-shrink: 0;
    background-color: var(--roc-surface);
    border: 1px solid var(--roc-border);
    border-radius: var(--roc-radius-control);
    /* Fill the side of the page so the resort menu reads as a full-height panel rather than a
       short box. Offsets the top bar + content padding above the layout. */
    min-height: calc(100vh - 5.5rem);
}

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

@media (max-width: 768px) {
    .resort-selector-layout {
        flex-direction: column;
    }

    .resort-selector-sidebar {
        width: 100%;
        /* Stacked above the content on narrow screens — collapse back to content height so it
           doesn't leave a tall empty panel. */
        min-height: 0;
    }
}

/* Promotional-cost breakdown tooltip — a pure-CSS hover/focus popup anchored to the discount
   amount on the rate builders. No Bootstrap tooltip JS is loaded, so the popup is shown by
   :hover of, or keyboard :focus-within, the icon wrapper. The
   icon renders just left of the value (inside the right-aligned amount cell, so the value stays
   lined up with the column); the popup opens above the icon and extends left, overlaying the
   rows above it. Opening upward keeps it clear of the table's bottom edge — the discount row
   sits low in every calculator, so a downward popup would spill past the .table-responsive
   scroll box and get trapped behind its overflow scrollbar. */
.promo-cost-tooltip {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin-right: 0.25rem;
    vertical-align: middle;
    cursor: help;
}

.promo-cost-tooltip-icon {
    vertical-align: middle;
}

.promo-cost-tooltip-popup {
    position: absolute;
    bottom: calc(100% + 0.35rem);
    right: 0;
    z-index: 1080;
    display: none;
    padding: 0.4rem 0.6rem;
    background-color: var(--roc-surface-muted);
    color: var(--roc-text);
    border: 1px solid var(--roc-border);
    border-radius: var(--roc-radius-control);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.promo-cost-tooltip:hover .promo-cost-tooltip-popup,
.promo-cost-tooltip:focus-within .promo-cost-tooltip-popup {
    display: block;
}

.promo-cost-tooltip-table {
    margin: 0;
    border-collapse: collapse;
    font-size: 0.8rem;
    font-weight: 400;
    white-space: nowrap;
}

.promo-cost-tooltip-table th {
    font-weight: 400;
    text-align: left;
    padding: 0.1rem 0.75rem 0.1rem 0;
}

.promo-cost-tooltip-table td.amount {
    text-align: right;
    font-variant-numeric: tabular-nums;
    padding: 0.1rem 0 0.1rem 0;
}

/* Accounting-style red for negative amounts, matching AmountCell's scoped .amount-negative
   (which can't reach this component's markup). */
.promo-cost-tooltip-table td.amount-negative {
    color: var(--bs-danger, #dc3545);
}

/* Rack rate calendar (#7855): read-only month-grid overview of the effective rate per day on the
   Edit Rack Rates admin panel. Global + marker-class scoped (.rackrate-calendar) rather than
   component-isolated, per ROC's shared-stylesheet convention. Record management stays in the table;
   this only visualizes what is effective, with a click opening the Add form pre-filled. */
.rackrate-calendar-nav {
    display: flex;
    gap: 0.25rem;
    justify-content: flex-end;
    margin-bottom: 0.5rem;
}

.rackrate-calendar-months {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
}

.rackrate-calendar-month {
    flex: 1 1 210px;
    min-width: 210px;
    max-width: 280px;
}

.rackrate-calendar-month-header {
    text-align: center;
    font-weight: 600;
    color: var(--roc-color-primary);
    margin-bottom: 0.25rem;
}

.rackrate-calendar-grid {
    border-collapse: collapse;
    width: 100%;
    table-layout: fixed;
}

.rackrate-calendar-grid th {
    text-align: center;
    font-weight: 500;
    font-size: 0.8rem;
    color: var(--roc-text-muted);
    padding: 0.25rem 0;
}

.rackrate-calendar-grid td {
    border: 1px solid var(--roc-border);
    height: 3rem;
    padding: 0;
    vertical-align: top;
}

/* Spillover days from an adjacent month — blank so the grid stays rectangular. */
.rackrate-calendar-grid td.out-of-month {
    border-color: transparent;
}

/* In the rendered month but outside the loaded [start, end] window — dimmed, non-interactive. */
.rackrate-calendar-grid td.out-of-range {
    color: var(--roc-border-muted);
    text-align: center;
    font-size: 0.8rem;
    padding-top: 0.25rem;
}

/* Fri/Sat cells get a subtle tint so weekend pricing reads at a glance. */
.rackrate-calendar-grid td.weekend {
    background: var(--roc-surface-muted);
}

.rackrate-calendar-day {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 100%;
    height: 100%;
    border: 0;
    background: transparent;
    cursor: pointer;
    padding: 0.2rem 0.3rem;
    color: inherit;
}

.rackrate-calendar-day:not(:disabled):hover,
.rackrate-calendar-day:not(:disabled):focus-visible {
    background: var(--roc-color-accent-tint);
}

/* While the form is busy the day cells are non-interactive, but the effective rates stay a
   readable reference — just drop the click affordance. */
.rackrate-calendar-day:disabled {
    cursor: default;
    opacity: 1;
}

.rackrate-calendar-daynum {
    font-size: 0.75rem;
    color: var(--roc-text-muted);
}

.rackrate-calendar-rate {
    font-size: 0.8rem;
    font-weight: 600;
    text-align: right;
    color: var(--roc-color-primary);
}

/* The anchor (first-clicked) day of an in-progress range selection. */
.rackrate-calendar-day.range-anchor {
    background: var(--roc-color-accent-tint);
    box-shadow: inset 0 0 0 2px var(--roc-color-accent);
}

/* The anchor marker is itself a box-shadow, so it would otherwise replace the focus ring outright
   and leave a focused anchor day looking identical to an unfocused one. Carry both. */
.rackrate-calendar-day.range-anchor:focus-visible {
    box-shadow: inset 0 0 0 2px var(--roc-color-accent), var(--roc-focus-ring);
}

/* Instruction shown above the grid while a range selection is in progress. */
.rackrate-calendar-hint {
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
    color: var(--roc-text-muted);
}

/* Sortable data-grid headers. SkiLockers / BonusTime / TourReferrals carry equivalent
   component-isolated copies; new grids (Rental Search) opt in with this marker class so the shared
   rules live in one place rather than a per-component copy. */
.roc-sortable-table > thead > tr > th {
    background-color: var(--roc-surface-muted);
    border-bottom: 1px solid var(--roc-border);
}

.roc-sortable-table th.sortable {
    cursor: pointer;
    user-select: none;
}

/* The sortable header's control is a real <button> so it is focusable, Enter/Space activated and
   announced as actionable, while the <th> keeps its columnheader role and aria-sort. */
.roc-sortable-table th.sortable > button {
    display: block;
    width: 100%;
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    text-align: inherit;
    cursor: pointer;
}

.roc-sortable-table th.sortable:hover {
    background-color: var(--roc-surface-hover);
}
