:root {
  --bs-border-radius-sm: .5rem;
  --bs-border-radius: .75rem;
  --bs-border-radius-lg: 1rem;
  --bs-border-radius-xl: 1.5rem;
  --bs-border-radius-pill: 50rem;

  --elevation-1: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);
  --elevation-2: 0 4px 8px rgba(0,0,0,.10), 0 2px 4px rgba(0,0,0,.06);
}

[data-bs-theme="dark"] {
  --elevation-1: 0 1px 3px rgba(0,0,0,.40), 0 1px 2px rgba(0,0,0,.30);
  --elevation-2: 0 4px 10px rgba(0,0,0,.45), 0 2px 6px rgba(0,0,0,.35);
}

html {
  font-size: 14px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

/* :focus-visible, not plain :focus, on the button-like selectors: a browser
   keeps plain :focus after a mouse click (not just keyboard navigation), so a
   clicked button in a group (e.g. the calendar's prev/next pair) would keep
   this ring while its unclicked sibling doesn't — the same lingering-focus
   bug already fixed once for FullCalendar's own buttons, now relevant here
   too since the calendar nav is real .btn elements (see the pane header bar
   work). Left as plain :focus on form-control/form-check-input, where a
   lingering ring after a click is normal, expected behaviour, not a bug. */
.btn:focus-visible, .btn:active:focus-visible, .btn-link.nav-link:focus-visible, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem var(--bs-body-bg), 0 0 0 0.25rem var(--bs-primary);
}

/* Fixed header/footer app shell: html/body are exactly viewport-height, body
   is a flex column with header/footer sized to their own content, and
   .app-main (the middle container) takes whatever's left and scrolls
   internally. min-height: 0 is required — flex items default to
   min-height: auto, which refuses to shrink below content size and would
   silently defeat the internal scrolling (content would just push the
   footer down/off-screen instead). */
html, body {
  height: 100%;
}

body {
  display: flex;
  flex-direction: column;
}

body > header,
body > footer {
  flex: 0 0 auto;
}

.app-main {
  /* flex-basis 0 (not auto): sizing comes purely from the flex distribution
     of body's leftover space, never influenced by this element's own content
     height — the more robust, standard pattern for a flex scroll pane. */
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  /* Establishes a stacking context for this scroll pane. Without it, a
     positioned descendant (FullCalendar's time grid is built almost
     entirely from position:absolute layers — the now-indicator, column
     backgrounds, event layers) stacks against <footer> at the body level,
     where "positioned beats static" applies regardless of DOM order —
     letting it paint over the footer even though it's correctly clipped to
     this element's own scrolled box. */
  position: relative;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

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

.fc-event.session-past {
  opacity: 0.6;
}

.navbar {
  box-shadow: var(--elevation-1);
}

.card {
  box-shadow: var(--elevation-1);
  border: 0;
}

/* Match the .card treatment above: elevation instead of a border, consistent
   with every other surface in the app. Bootstrap's own accordion styling
   (unlike .card) keeps a visible border and no shadow, which reads as a flat,
   disconnected block rather than one of this app's elevated surfaces. */
.accordion-item {
  box-shadow: var(--elevation-1);
  border: 0;
}

/* Bootstrap's own accordion-button is plain white when collapsed (same
   --bs-accordion-bg as the body below it), only picking up a themed tint —
   --bs-primary-bg-subtle, the same pale wash --bs-accordion-active-bg already
   uses when expanded — once opened. Apply that same subtle tint to the
   collapsed state too, so the header reads as a distinct, clickable surface
   either way, without the stronger, full-strength --bs-primary read as too
   dark for this. --bs-primary-text-emphasis/--bs-accordion-btn-active-icon
   are Bootstrap's own matching text colour and chevron for this tint
   (confirmed in its CSS: the active icon's stroke colour is literally
   --bs-primary-text-emphasis's light-mode value), reused here rather than
   custom colours so both states look identically "designed" for the tint. */
.accordion-button {
  background-color: var(--bs-primary-bg-subtle);
  color: var(--bs-primary-text-emphasis);
  --bs-accordion-btn-icon: var(--bs-accordion-btn-active-icon);
}

.dropdown-menu, #clientFilterDropdown {
  box-shadow: var(--elevation-2);
}

.sessions-shell .sidebar-node {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem;
  border-radius: var(--bs-border-radius);
  color: inherit;
  text-decoration: none;
}

.sessions-shell .sidebar-node:hover {
  background: var(--bs-secondary-bg);
}

/* Unified pane header bar: a constant-height strip at the top of every
   right-hand pane, above its title, holding that pane's primary controls
   (nothing on Sessions, for now). --bs-primary is a single fixed value in
   Sandstone (not redefined per theme, same reasoning as the day-number
   chips), so this looks identical in light and dark mode. */
.pane-header {
  background-color: var(--bs-primary);
  color: #fff;
  min-height: 3.25rem;
  padding: .5rem 1rem;
  border-radius: var(--bs-border-radius);
  box-shadow: var(--elevation-1);
  margin-bottom: 1rem;
}

/* Mirrors .app-main's own flex-basis-0 + min-height:0 pattern (see that
   rule's comment) — needed so a page like Calendar, whose content measures
   its own height as a percentage (#calendar { height: 100% }), measures
   against the space actually left under the bar rather than the whole
   column (which would overflow by exactly the bar's height). Pages with
   ordinary flowing content (Clients/Sessions/Notes) are unaffected — no
   overflow/scroll change, this only establishes a definite height for
   percentage children to measure against. */
.pane-body {
  flex: 1 1 0;
  min-height: 0;
}

.sessions-shell .sidebar-node.active {
  background: var(--bs-primary-bg-subtle);
  font-weight: 600;
}

/* A child of the node above it (e.g. the open client under Clients) —
   indented past the parent's icon so the text lines up under its label. */
.sessions-shell .sidebar-subnode {
  padding-left: calc(.75rem + 18px + .5rem);
}

/* A child of a sub-node (e.g. Testing under Developer) — indented once more, past the
   sub-node's 14px icon. */
.sessions-shell .sidebar-subnode-2 {
  padding-left: calc(.75rem + 18px + .5rem + 14px + .5rem);
}

/* A sidebar node that runs an action (e.g. Add booking) rather than linking to a
   page: a <button>, reset to look like the link nodes around it. */
.sessions-shell .sidebar-action {
  width: 100%;
  border: 0;
  background: none;
  text-align: start;
}

.clickable-row {
  cursor: pointer;
}

/* A clickable row's main cell is still a real <a> (keyboard focus, right-click
   "open in new tab", same reasoning as the day-of-week header cushion/day-number
   chip elsewhere), just not styled as one — plain text is the ask here, not a
   neutralized-but-still-link look. The row click itself is site.js. */
.clickable-row a {
  color: inherit;
  text-decoration: none;
}

/* --bs-secondary-bg (used here previously) is Sandstone's low-contrast
   hairline-adjacent token (see the month-view border/chip comments above for
   the same issue) — on a plain white row it's nearly imperceptible, and a
   plain background-color on the <tr> never even got the chance to show it:
   Bootstrap's table CSS paints an opaque background-color plus a striping
   box-shadow on every <td> individually (confirmed in its own stylesheet),
   which fully covers whatever background the <tr> itself has. The supported
   hook is the same custom property Bootstrap's own .table-hover class sets
   on tr:hover — --bs-table-bg-state, the highest-priority fallback in each
   cell's box-shadow — so setting it here reaches the cells (custom
   properties inherit) and wins over the striping color on odd rows too.
   --bs-primary-bg-subtle gives a clearly visible, still-subtle tinted
   highlight in both themes; it's the same token already proven visible for
   the calendar's today-highlight. */
.clickable-row:hover,
.clickable-row:focus-visible {
  --bs-table-bg-state: var(--bs-primary-bg-subtle);
}

/* A row that's focusable itself (e.g. the notes History list) needs a visible
   focus ring as well as the tint; the theme's ring colour matches the buttons'. */
.clickable-row:focus-visible {
  outline: .2rem solid var(--bs-primary);
  outline-offset: -.2rem;
}

.sortable-header {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .25rem .5rem;
  margin: -.25rem -.5rem;
  border-radius: var(--bs-border-radius-sm);
  text-decoration: none;
  color: inherit;
}

.sortable-header:hover {
  background: var(--bs-secondary-bg);
}

/* Round icon buttons in the top bar: help (tutorial) and the theme toggle. */
.header-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--bs-border-radius-pill);
  border: 0;
  background: transparent;
  color: inherit;
}

.header-icon-button:hover {
  background: var(--bs-secondary-bg);
}

.theme-icon-moon {
  display: none;
}

[data-bs-theme="dark"] .theme-icon-sun {
  display: none;
}

[data-bs-theme="dark"] .theme-icon-moon {
  display: inline;
}

/* FullCalendar re-themes for free by aliasing its own custom properties to
   Bootstrap's — no JS re-init needed when the theme toggles. Grid borders are
   removed (transparent) for a flatter, less blocky look; a couple of
   selectors hardcode a border outside that variable, so those are zeroed
   explicitly too. */
.fc {
  --fc-border-color: transparent;
  --fc-page-bg-color: var(--bs-body-bg);
  --fc-neutral-bg-color: var(--bs-tertiary-bg);
  --fc-neutral-text-color: var(--bs-body-color);
  /* Translucent, not transparent: the time-grid view's today-highlight is a
     separate overlay layer that sits above the hour-slot grid lines (not a
     descendant of them — confirmed by inspecting FullCalendar's actual DOM
     construction, they're sibling structures kept visually aligned via
     absolute positioning, not nesting). An opaque tint here would cover the
     slot borders again; a translucent one lets them show through while
     still visibly marking today. */
  --fc-today-bg-color: color-mix(in srgb, var(--bs-primary) 15%, transparent);
  --fc-button-bg-color: var(--bs-primary);
  --fc-button-border-color: var(--bs-primary);
  --fc-button-hover-bg-color: var(--bs-primary-text-emphasis);
  --fc-button-active-bg-color: var(--bs-primary-text-emphasis);
  --fc-list-event-hover-bg-color: var(--bs-secondary-bg);
}

/* (No blanket "border: none" override here on purpose — it previously zeroed
   out a border-width FullCalendar's own CSS relies on to keep its separately
   laid-out axis/column structures aligned, which showed up as the
   now-indicator's container rendering far taller than the visible grid.
   --fc-border-color: transparent above already makes the border invisible
   without touching its width, which is the supported way to do this. )*/

/* FullCalendar explicitly zeroes this out itself (border-bottom:0) to leave
   hour dividers to the theme; add them back as a real border, not routed
   through --fc-border-color (now transparent). !important is deliberate:
   this is the exact selector FullCalendar's own injected stylesheet uses,
   at equal specificity, injected after site.css — without it the library's
   own rule wins the cascade tie. Same reasoning applies to height: its
   default (1.5em) is set in that same rule, so it needs the same override. */
.fc .fc-timegrid-slot {
  border-bottom: 1px solid var(--bs-border-color) !important;
  height: 3em !important;
}

/* Month view's day cells get their grid lines from the same now-transparent
   --fc-border-color (via .fc-theme-standard td), so they went invisible along
   with everything else that variable touches — confirmed by inspecting the
   computed style (border-color: rgba(0,0,0,0)). Restore them the same way as
   the week/day view's hour rows above, scoped to .fc-daygrid-day specifically
   so week/day view (already handled separately) isn't affected.
   --bs-border-color-translucent (not --bs-border-color, used for the hour
   rows) is deliberate here: Sandstone's --bs-border-color is a very low-
   contrast hairline tuned for things we already render as shadowed, borderless
   surfaces (.card, .accordion-item) — too pale to read as a grid on its own
   over a plain white cell. The translucent token is black/white at a fixed
   opacity regardless of theme, designed to stay visible over any background. */
.fc .fc-daygrid-day {
  border: 1px solid var(--bs-border-color-translucent) !important;
}

/* Tidy the day-of-week column headers to match the Clients table's
   sort-header spacing/rounding (no hover highlight — these aren't
   clickable, so a hover affordance would be misleading). The cushion
   renders as a real <a> (FullCalendar makes it one even though it carries
   no navigation here), which is why Bootstrap's default link underline
   shows up and needs removing explicitly, and — same reason — it picks up
   Bootstrap's link color (blue) instead of plain theme-aware body text,
   same bug already fixed on the Clients table's sort headers. */
.fc .fc-col-header-cell-cushion {
  padding: .5rem .75rem;
  border-radius: var(--bs-border-radius-sm);
  text-decoration: none;
  color: inherit;
}

/* Month view's day numbers (navLinks: true in _CalendarPanel.cshtml makes
   these real navigation links, to the day view for that date) default to
   plain underlined text — same underline/link-color bug already fixed on the
   column headers above, but here the link is real, so it's styled as a chip
   instead of neutralized like the non-interactive header cushion. --bs-primary
   (not a gray token) so it reads as an accented, clickable chip — distinct
   from the --bs-info event chips above, keeping a "primary = navigate,
   info = data" distinction consistent with the rest of the app (prev/next,
   Apply, etc. are all --bs-primary too). Like --bs-info, --bs-primary is a
   single fixed value in Sandstone (not redefined per theme, confirmed by
   inspecting its CSS), so this looks identical in light and dark mode without
   any theme-conditional rule — and for the same reason, the hover shade is
   mixed toward white rather than reused from a theme token (see the event
   chip's hover comment above for why a theme token can't serve that role
   consistently across both modes). FullCalendar fades adjacent-month days via
   opacity on their container (.fc-day-other .fc-daygrid-day-top), so those
   chips come out automatically muted rather than needing separate styling. */
.fc .fc-daygrid-day-number {
  display: inline-block;
  padding: .1rem .5rem;
  margin: .25rem;
  border-radius: var(--bs-border-radius-pill);
  background-color: var(--bs-primary);
  color: #fff;
  text-decoration: none;
}

.fc .fc-daygrid-day-number:hover {
  background-color: color-mix(in srgb, var(--bs-primary) 65%, white);
  color: #fff;
}

/* Month view renders each booking as a dot + time + title with no background
   at all (confirmed: resting background-color is rgba(0,0,0,0)), so it reads
   as plain text rather than an item sitting in the cell. --bs-info is a
   single fixed value (not redefined per theme, confirmed by inspecting
   Sandstone's CSS), so it's solid/saturated rather than a pale "subtle" tint
   — picked deliberately for contrast, and it reads clearly against both a
   near-white and a near-black page background. The hover shade is mixed
   toward true white rather than reused from a theme token: Sandstone's own
   --bs-info-bg-subtle/--bs-info-border-subtle pair flips which one is
   visually lighter between light and dark mode (confirmed), so neither can
   serve as a theme-independent "lighter than rest" shade on its own —
   mixing toward white guarantees the hover shade is lighter than --bs-info
   in every theme, by construction. */
.fc .fc-daygrid-event {
  background-color: var(--bs-info);
  color: #fff;
  border-radius: var(--bs-border-radius-sm);
  padding: 1px 4px;
}

.fc .fc-daygrid-event .fc-daygrid-event-dot {
  border-color: #fff;
}

/* FullCalendar's own hover rule hardcodes rgba(0,0,0,.1) regardless of theme
   (confirmed), which is nearly invisible against an already-dark surface in
   dark mode. !important for the same reason as the other FullCalendar
   overrides above — this needs to beat its own injected-after-site.css rule. */
.fc .fc-daygrid-dot-event:hover,
.fc .fc-daygrid-dot-event.fc-event-mirror {
  background-color: color-mix(in srgb, var(--bs-info) 65%, white) !important;
}

/* FullCalendar sets no background on these cells itself (confirmed — no
   rule targets .fc-col-header-cell anywhere in its stylesheet); match the
   Clients table's plain header look explicitly rather than leave it to
   whatever the browser's default table-cell rendering happens to produce. */
.fc .fc-col-header-cell {
  background: var(--bs-body-bg);
}


/* Sandstone hardcodes light-only hex colours (#f8f5f0 / #dfd7ca / #8e8c84)
   for tabs and pagination instead of theme tokens, so they stay light in
   dark mode. Re-point them at Bootstrap's theme-aware tokens. The active tab
   takes the body background so it still merges into the content below it. */
[data-bs-theme="dark"] .nav-tabs {
  --bs-nav-tabs-border-color: var(--bs-border-color);
  --bs-nav-tabs-link-hover-border-color: var(--bs-border-color);
  --bs-nav-tabs-link-active-bg: var(--bs-body-bg);
  --bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);
}

[data-bs-theme="dark"] .nav-tabs .nav-link {
  background-color: var(--bs-tertiary-bg);
  border-color: var(--bs-border-color);
}

[data-bs-theme="dark"] .nav-tabs .nav-link,
[data-bs-theme="dark"] .nav-tabs .nav-link:focus,
[data-bs-theme="dark"] .nav-tabs .nav-link:hover {
  color: var(--bs-secondary-color);
}

[data-bs-theme="dark"] .nav-tabs .nav-link.active {
  color: var(--bs-emphasis-color);
  background-color: var(--bs-nav-tabs-link-active-bg);
  border-color: var(--bs-nav-tabs-link-active-border-color);
}

[data-bs-theme="dark"] .pagination {
  --bs-pagination-color: var(--bs-secondary-color);
  --bs-pagination-bg: var(--bs-tertiary-bg);
  --bs-pagination-border-color: var(--bs-border-color);
  --bs-pagination-hover-color: var(--bs-emphasis-color);
  --bs-pagination-hover-bg: var(--bs-secondary-bg);
  --bs-pagination-active-color: var(--bs-emphasis-color);
  --bs-pagination-active-bg: var(--bs-secondary-bg);
  --bs-pagination-active-border-color: var(--bs-border-color);
  --bs-pagination-disabled-color: var(--bs-tertiary-color);
  --bs-pagination-disabled-bg: var(--bs-body-bg);
  --bs-pagination-disabled-border-color: var(--bs-border-color);
}

/* Expired-client hourglass (Views/Shared/_ExpiryIcon.cshtml): muted, sits on the
   text baseline next to the name, and keeps its own cursor so the tooltip is
   discoverable inside clickable rows. Sized in em (overriding the SVG's 14px
   attributes) so it scales with the text around it — a fixed 14px icon next to
   the dashboard's <h1> looked tiny and, with the em-based offset, like
   subscript. .875em is 14px at body size, so lists are unchanged. */
.expiry-icon {
  display: inline-flex;
  vertical-align: -0.125em;
  color: var(--bs-secondary-color);
  cursor: help;
}

.expiry-icon svg {
  width: .875em;
  height: .875em;
}

/* Vditor (notes editor + read-only previews) hardcodes light-only content
   colours on .vditor-reset — most importantly the text itself (#24292e), which
   is near-invisible on its dark editor background and on our dark modal. Its
   own dark *content* theme is a separate stylesheet it would fetch from unpkg
   (not bundled in wwwroot/lib/vditor), so instead re-point those colours at
   Bootstrap's theme tokens here, the same approach as tabs/pagination above.
   Covers the editor (Sessions/Notes), the revision history previews, and the
   client dashboard's notes modal — all render inside .vditor-reset. */
[data-bs-theme="dark"] .vditor-reset {
  color: var(--bs-body-color);
}

[data-bs-theme="dark"] .vditor-reset hr {
  background-color: var(--bs-border-color);
}

[data-bs-theme="dark"] .vditor-reset blockquote {
  color: var(--bs-secondary-color);
  border-left-color: var(--bs-border-color);
}

[data-bs-theme="dark"] .vditor-reset table tr,
[data-bs-theme="dark"] .vditor-reset table tbody tr:nth-child(2n) {
  background-color: transparent;
  border-top-color: var(--bs-border-color);
}

[data-bs-theme="dark"] .vditor-reset table tbody tr:nth-child(2n) {
  background-color: var(--bs-tertiary-bg);
}

[data-bs-theme="dark"] .vditor-reset table td,
[data-bs-theme="dark"] .vditor-reset table th {
  border-color: var(--bs-border-color);
}

[data-bs-theme="dark"] .vditor-reset code:not(.hljs):not(.highlight-chroma),
[data-bs-theme="dark"] .vditor-reset kbd {
  color: var(--bs-body-color);
  background-color: var(--bs-tertiary-bg);
  border-color: var(--bs-border-color);
}

/* Skip link (WCAG 2.4.1): hidden until keyboard focus, then pinned top-left
   above the navbar. visually-hidden-focusable handles the show/hide. */
.skip-link:focus {
  position: absolute;
  top: .5rem;
  left: .5rem;
  z-index: 1080;
  padding: .5rem 1rem;
  background-color: var(--bs-body-bg);
  color: var(--bs-body-color);
  border: 2px solid var(--bs-primary);
  border-radius: var(--bs-border-radius);
}

/* The skip link focuses <main> (tabindex="-1"); no outline on a whole region. */
#main:focus {
  outline: none;
}

/* Signed-out landing page (Views/Home/Landing.cshtml). Colours come from
   Bootstrap's theme variables only, so both light and dark modes work
   without separate overrides. */
.landing {
  padding-block: 2rem 3rem;
}

.landing-hero {
  max-width: 48rem;
  margin: 0 auto 3rem;
  padding: 2.5rem 1rem 1rem;
}

.landing-eyebrow {
  text-transform: uppercase;
  letter-spacing: .08em;
  font-size: .8rem;
  font-weight: 600;
  color: var(--bs-primary-text-emphasis);
  margin-bottom: .75rem;
}

.landing-title {
  font-size: clamp(2rem, 5vw, 3.25rem);
  font-weight: 700;
  line-height: 1.15;
  margin-bottom: 1rem;
}

.landing-accent {
  color: var(--bs-primary);
}

.landing-lead {
  color: var(--bs-secondary-color);
  margin-bottom: 2rem;
}

.landing-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .75rem;
}

.landing-cta-note {
  margin-top: 1rem;
  font-size: .9rem;
}

/* Each card takes one of the colour variants below. The variants only set
   these properties, so the card, icon and footnote rules stay in one place. */
.landing-feature {
  --landing-icon-bg: var(--bs-primary-bg-subtle);
  --landing-icon-color: var(--bs-primary-text-emphasis);
  --landing-muted: var(--bs-secondary-color);
  transition: transform .15s ease, box-shadow .15s ease;
}

/* Dark cards: only the two Sandstone colours that pass WCAG AA with white
   text (navy #325d88 at about 6.9:1, charcoal #3e3f3a at about 10.6:1). The
   -rgb variables keep the same value in dark mode, so these cards look the
   same in both themes. Green, cyan and orange are too light for white text,
   so they only appear as the light tints. */
.landing-dark-primary,
.landing-dark-charcoal {
  --bs-card-color: #fff;
  --bs-card-title-color: #fff;
  --landing-icon-bg: rgba(255, 255, 255, .15);
  --landing-icon-color: #fff;
  --landing-muted: rgba(255, 255, 255, .8);
}

.landing-dark-primary {
  --bs-card-bg: rgb(var(--bs-primary-rgb));
}

.landing-dark-charcoal {
  --bs-card-bg: rgb(var(--bs-dark-rgb));
}

/* Light cards: Bootstrap's -bg-subtle tints with their matching
   -text-emphasis colour for the icon. Both are theme-aware, so in dark mode
   they become deeper versions of the same colour. */
.landing-light-success {
  --bs-card-bg: var(--bs-success-bg-subtle);
  --landing-icon-bg: var(--bs-success-border-subtle);
  --landing-icon-color: var(--bs-success-text-emphasis);
}

.landing-light-info {
  --bs-card-bg: var(--bs-info-bg-subtle);
  --landing-icon-bg: var(--bs-info-border-subtle);
  --landing-icon-color: var(--bs-info-text-emphasis);
}

.landing-light-warning {
  --bs-card-bg: var(--bs-warning-bg-subtle);
  --landing-icon-bg: var(--bs-warning-border-subtle);
  --landing-icon-color: var(--bs-warning-text-emphasis);
}

.landing-feature:hover {
  transform: translateY(-2px);
  box-shadow: var(--elevation-2);
}

@media (prefers-reduced-motion: reduce) {
  .landing-feature {
    transition: none;
  }

  .landing-feature:hover {
    transform: none;
  }
}

.landing-group + .landing-group {
  margin-top: 3rem;
}

.landing-group-title {
  font-size: 1.5rem;
  font-weight: 600;
  margin-bottom: 1.25rem;
}

/* Column flex so the .landing-tech footnote sits at the foot of the card,
   lining up across a row whatever the length of each card's main text. */
.landing-feature .card-body {
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
}

/* The technical detail for anyone checking a list: small and quiet, so the
   plain-English text stays the main message. */
.landing-tech {
  margin: auto 0 0;
  padding-top: 1rem;
  font-size: .8rem;
  color: var(--landing-muted);
}

.landing-feature .card-text {
  margin-bottom: 0;
}

.landing-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-bottom: 1rem;
  border-radius: var(--bs-border-radius);
  background: var(--landing-icon-bg);
  color: var(--landing-icon-color);
}

.landing-closing {
  margin-top: 3.5rem;
  padding: 2.5rem 1rem;
  border-radius: var(--bs-border-radius-lg);
  background: var(--bs-tertiary-bg);
}

.landing-closing h2 {
  margin-bottom: 1.25rem;
}

/* A card that holds content or controls in the app (settings groups, admin tools).
   The app-wide shadow-only .card treatment is too faint to separate it from the
   page around it. A border (the theme-aware translucent token, as on the calendar
   grid) and a deeper shadow make it read as its own panel in both themes. */
.card-panel {
  border: 1px solid var(--bs-border-color-translucent);
  box-shadow: var(--elevation-2);
}

/* Settings page: space each option out so its help text reads as belonging to it. */
.settings-option + .settings-option {
  margin-top: 1.25rem;
}

/* Undo the browser's fieldset box; only on the fieldset, since the switch
   options rely on Bootstrap's .form-switch padding. */
fieldset.settings-option {
  border: 0;
  padding: 0;
  margin-inline: 0;
}

/* Selects and time inputs don't need the card's full width. */
.settings-narrow {
  width: auto;
  min-width: 9rem;
}

/* The summary only appears when there are errors; ASP.NET renders an empty
   (valid) summary with this class. */
.settings-form .validation-summary-valid {
  display: none;
}

/* Tutorial popovers (Driver.js, popoverClass "app-tour"). Driver ships fixed light
   colours and its own font, so re-theme with Bootstrap's variables to follow light/dark.
   The arrow is a CSS triangle: only the border on its pointing side is visible, so set
   just that side's colour per placement (the other three stay transparent). */
.driver-popover.app-tour {
  font-family: var(--bs-body-font-family);
  color: var(--bs-body-color);
  background-color: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-lg);
  box-shadow: var(--bs-box-shadow);
  max-width: 22rem;
  padding: 1rem 1.25rem;
}

.app-tour .driver-popover-title {
  font-size: 1.05rem;
  font-weight: 600;
  padding-right: 1.5rem;
}

.app-tour .driver-popover-description {
  font-size: .95rem;
}

.app-tour .driver-popover-progress-text {
  color: var(--bs-secondary-color);
}

.app-tour .driver-popover-close-btn {
  color: var(--bs-secondary-color);
}

.app-tour .driver-popover-close-btn:hover,
.app-tour .driver-popover-close-btn:focus-visible {
  color: var(--bs-body-color);
}

.app-tour .driver-popover-footer-btn {
  font: inherit;
  font-size: .875rem;
  text-shadow: none;
  padding: .3rem .8rem;
  border-radius: var(--bs-border-radius);
  color: var(--bs-body-color);
  background-color: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
}

.app-tour .driver-popover-footer-btn:hover {
  background-color: var(--bs-secondary-bg);
}

.app-tour .driver-popover-next-btn,
.app-tour .driver-popover-next-btn:hover {
  color: #fff;
  background-color: var(--bs-primary);
  border-color: var(--bs-primary);
}

.app-tour .driver-popover-footer-btn:focus-visible {
  outline: 0;
  box-shadow: 0 0 0 0.1rem var(--bs-body-bg), 0 0 0 0.25rem var(--bs-primary);
}

.app-tour .driver-popover-arrow-side-left { border-left-color: var(--bs-body-bg); }
.app-tour .driver-popover-arrow-side-right { border-right-color: var(--bs-body-bg); }
.app-tour .driver-popover-arrow-side-top { border-top-color: var(--bs-body-bg); }
.app-tour .driver-popover-arrow-side-bottom { border-bottom-color: var(--bs-body-bg); }
