:where(slot-picker) {
  --sp-bg: #ffffff;
  --sp-fg: #1f2328;
  --sp-muted: color-mix(in srgb, var(--sp-fg) 58%, var(--sp-bg));
  --sp-border: color-mix(in srgb, var(--sp-fg) 16%, var(--sp-bg));
  --sp-hover: color-mix(in srgb, var(--sp-fg) 5%, var(--sp-bg));
  --sp-notice-hover-bg: color-mix(in srgb, var(--sp-fg) 12%, var(--sp-bg));
  --sp-accent: #2563eb;
  --sp-accent-fg: #ffffff;
  --sp-accent-soft: color-mix(in srgb, var(--sp-accent) 16%, var(--sp-bg));
  --sp-focus: var(--sp-accent);
  --sp-radius: 0.5rem;
  --sp-gap: 0.5rem;
  --sp-day-gap: 0.75rem;
  --sp-slot-columns: 3;
  --sp-card-bg: transparent;
  --sp-slot-block-size: 2.75rem;
  /* Slot colors are their own theming surface so a `data-tone` can recolor a
     single slot without touching focus or the rest of the picker. */
  --sp-slot-bg: var(--sp-accent-soft);
  --sp-slot-fg: var(--sp-fg);
  --sp-slot-border: transparent;
  --sp-slot-hover-bg: color-mix(in srgb, var(--sp-accent) 22%, var(--sp-bg));
  --sp-slot-selected-bg: var(--sp-accent);
  --sp-slot-selected-fg: var(--sp-accent-fg);
  --sp-nav-size: 2.5rem;
  /* Stable collapsed footprint. `--sp-day-header-block-size` is a minimum, not
     a fixed height: the reserved area follows `max-visible-rows` so navigating
     between sparse and empty ranges never shifts the page. */
  --sp-day-header-block-size: 3.4rem;
  --sp-collapsed-rows: var(--_sp-max-visible-rows, 5);
  --sp-collapsed-body-block-size: calc(
    var(--sp-collapsed-rows) *
    (var(--sp-slot-block-size) + var(--sp-gap)) -
    var(--sp-gap)
  );
  --sp-footer-block-size: 2.5rem;
  /* Reserved height for the `home` shortcut when `home-date` is configured. */
  --sp-shortcuts-block-size: 2.5rem;
  --sp-collapsed-block-size: calc(
    var(--sp-day-header-block-size) +
    var(--sp-collapsed-body-block-size) +
    var(--sp-footer-block-size)
  );
  /* Collapsed "show more" floats in the reserved footer band; the gradient
     rises above that band to hint at availability that is not rendered. */
  --sp-more-fade-size: 4rem;
  --sp-more-bg: var(--sp-bg);
  --sp-panel-min-block-size: calc(2 * var(--sp-slot-block-size) + var(--sp-gap));
  /* `closed` is a normal day state; themes may restyle it entirely. */
  --sp-closed-opacity: 0.55;
  --sp-loading-fade-opacity: 0.72;
  --sp-loading-fade-delay: 400ms;
  display: block;
  color: var(--sp-fg);
  font: inherit;
}

/* The component renders in light DOM, so a page stylesheet can reach these
   declarations. `!important` is what keeps assistive-technology-only text (the
   loading status, the day strip's spoken labels) out of sight: losing it is an
   accessibility regression, not a cosmetic one. */
/* biome-ignore-start lint/complexity/noImportantStyles: visually-hidden must win over page styles */
.sp-visually-hidden {
  position: absolute !important;
  inline-size: 1px !important;
  block-size: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}
/* biome-ignore-end lint/complexity/noImportantStyles: visually-hidden must win over page styles */

.sp-shell {
  display: block;
}

/* `previous`/`next` are a symmetric pair around a centered projection. They
   are the only range-navigation chrome; `home` is not their mirror and lives
   in `.sp-shortcuts` instead. */
.sp-projection {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--sp-gap);
}

.sp-content {
  position: relative;
  min-inline-size: 0;
  opacity: 1;
  transition-property: opacity;
  transition-duration: 160ms;
  transition-timing-function: ease;
  transition-delay: 0ms;
}

/* Slow loads fade the current projection to signal stale data, but only after
   a delay: fast requests never flicker. `aria-busy` is the only state source. */
slot-picker[aria-busy="true"] .sp-content {
  opacity: var(--sp-loading-fade-opacity, 0.72);
  transition-delay: var(--sp-loading-fade-delay, 400ms);
}

/* Keep the delay (the stale hint), drop the animation. */
@media (prefers-reduced-motion: reduce) {
  .sp-content {
    transition-duration: 0ms;
  }
}

/* Collapsed columns keep the same footprint whether the range is full, sparse,
   or empty. Expanded content simply grows past this floor. */
slot-picker:not([layout="day"]) .sp-content {
  min-block-size: var(--sp-collapsed-block-size);
}

/* Auxiliary, start-aligned shortcut. Rendered only when `homeDate` is outside
   the visible range, i.e. when it would actually change something. */
.sp-shortcuts {
  display: flex;
  justify-content: flex-start;
  margin-block-start: var(--sp-gap);
}

/* Keep the wrapper present (empty when `homeDate` is visible) so the shortcut
   appearing never shifts the content below. */
slot-picker[home-date] .sp-shortcuts {
  min-block-size: var(--sp-shortcuts-block-size, 2.5rem);
}

.sp-home {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0;
  border: 0;
  background: transparent;
  color: var(--sp-accent);
  font: inherit;
  cursor: pointer;
}

.sp-home:hover {
  text-decoration: underline;
}

.sp-grid {
  display: grid;
  grid-template-columns: repeat(var(--_sp-day-count, 5), minmax(0, 1fr));
  gap: var(--sp-day-gap);
}

.sp-day {
  min-inline-size: 0;
}

.sp-day-header {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.1rem;
  /* Deterministic leading: an inherited `normal` line-height can exceed the
     reserved header height and break the stable footprint. */
  line-height: 1.25;
  box-sizing: border-box;
  min-block-size: var(--sp-day-header-block-size);
  padding-block: 0.15rem 0.55rem;
  text-align: center;
}

.sp-weekday {
  color: var(--sp-muted);
  font-size: 0.85rem;
}

.sp-date {
  font-size: 0.9rem;
  font-weight: 650;
}

/* Notice indicator. Without `data-day-index` it is decorative; with it, it is
   the accessible control used by notice-display="action". */
.sp-notice {
  position: absolute;
  inset-block-start: 0;
  inset-inline-end: 0;
  display: grid;
  place-items: center;
  inline-size: 1.5rem;
  block-size: 1.5rem;
  color: var(--sp-muted);
  pointer-events: none;
}

.sp-notice[data-day-index] {
  pointer-events: auto;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.sp-notice[data-day-index]:hover {
  background: var(--sp-notice-hover-bg);
  color: var(--sp-fg);
}

.sp-notice-dot {
  inline-size: 0.45rem;
  block-size: 0.45rem;
  border-radius: 50%;
  background: currentColor;
}

.sp-slots {
  display: grid;
  /* Bound the single column to the day column: an `auto` track follows the
     widest slot's min-content and would push every slot past the day card. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-gap);
}

.sp-slot,
.sp-empty {
  display: grid;
  place-items: center;
  min-block-size: var(--sp-slot-block-size);
  box-sizing: border-box;
  border-radius: var(--sp-radius);
  font: inherit;
  /* A grid item defaults to `min-width: auto`, i.e. its min-content; that would
     let a wide slot (a theme icon next to the time) push the bounded day column.
     Clamp the button to its track instead; the content stays centered. */
  min-inline-size: 0;
  max-inline-size: 100%;
}

/* Time wrapper: inline-flex so a theme can append an in-flow icon (`::after`)
   that stays adjacent to the time and vertically centered. */
.sp-slot-time {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.sp-slot {
  border: 1px solid var(--sp-slot-border);
  background: var(--sp-slot-bg);
  color: var(--sp-slot-fg);
  cursor: pointer;
}

.sp-slot:hover:not(:disabled):not([aria-selected="true"]) {
  background: var(--sp-slot-hover-bg);
}

.sp-slot[aria-selected="true"] {
  background: var(--sp-slot-selected-bg);
  color: var(--sp-slot-selected-fg);
}

.sp-slot:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}

.sp-slot:focus-visible {
  outline: 2px solid var(--sp-focus);
  outline-offset: 2px;
}

.sp-slot[aria-selected="true"]:focus-visible {
  outline-color: var(--sp-fg);
}

.sp-empty {
  color: var(--sp-muted);
  user-select: none;
}

.sp-nav {
  display: grid;
  place-items: center;
  inline-size: var(--sp-nav-size);
  block-size: var(--sp-nav-size);
  margin-block-start: 0.45rem;
  padding: 0;
  border: 1px solid var(--sp-border);
  border-radius: 50%;
  background: var(--sp-bg);
  color: var(--sp-fg);
  cursor: pointer;
}

.sp-nav:hover:not(:disabled) {
  background: var(--sp-hover);
}

.sp-nav:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.sp-nav svg {
  display: block;
  inline-size: 1rem;
  block-size: 1rem;
  pointer-events: none;
}

[dir="rtl"] .sp-nav svg,
html[dir="rtl"] .sp-nav svg {
  transform: scaleX(-1);
}

.sp-more {
  display: flex;
  justify-content: center;
  margin-block-start: 1rem;
}

/* Collapsed: float the control inside the reserved footer band while the
   gradient rises above it to suggest the availability that is not rendered.
   The last rendered row stays fully interactive. */
slot-picker:not([expanded]) .sp-more {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  display: grid;
  place-items: end center;
  margin-block-start: 0;
  min-block-size: var(--sp-footer-block-size);
}

slot-picker:not([expanded]) .sp-more::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: var(--sp-more-fade-size, 4rem);
  background: linear-gradient(to bottom, transparent, var(--sp-more-bg, var(--sp-bg)));
  pointer-events: none;
}

/* Expanded: back to normal flow, overlay and gradient removed. */
slot-picker[expanded] .sp-more {
  position: static;
}

slot-picker[expanded] .sp-more::before {
  content: none;
}

.sp-more-button {
  position: relative;
  z-index: 1;
  border: 0;
  background: transparent;
  color: var(--sp-accent);
  font: inherit;
  cursor: pointer;
}

.sp-status {
  margin-block-end: 0.75rem;
  color: var(--sp-muted);
  text-align: center;
}

.sp-status-error {
  color: var(--sp-fg);
}

.sp-day-empty {
  display: grid;
  place-items: center;
  min-block-size: var(--sp-slot-block-size);
  padding-inline: 0.5rem;
  color: var(--sp-muted);
  font-size: 0.9rem;
  text-align: center;
}

/* A day closed by the application's opening rule. It stays in the civil
   projection; only its presentation changes. */
.sp-day[data-closed],
.sp-panel[data-closed],
.sp-strip-day[data-closed] {
  opacity: var(--sp-closed-opacity, 0.55);
}

.sp-range-empty {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 0.5rem;
  box-sizing: border-box;
  min-block-size: var(--sp-collapsed-block-size);
  padding: 1.5rem 1rem;
  border-radius: var(--sp-radius);
  background: var(--sp-card-bg);
  text-align: center;
}

slot-picker[layout="day"] .sp-range-empty {
  min-block-size: var(--sp-panel-min-block-size);
}

/* Day layout: only the empty state needs a baseline, a populated panel keeps
   its natural height. */
slot-picker[layout="day"] .sp-day-empty {
  align-content: center;
  min-block-size: var(--sp-panel-min-block-size);
}

.sp-range-empty-title {
  font-size: 1rem;
}

.sp-range-empty-description {
  margin: 0;
  color: var(--sp-muted);
}

.sp-range-empty-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}

.sp-range-empty-next {
  border: 0;
  border-radius: var(--sp-radius);
  padding: 0.6rem 1rem;
  background: var(--sp-accent);
  color: var(--sp-accent-fg);
  font: inherit;
  cursor: pointer;
}

.sp-range-empty-next:hover {
  background: color-mix(in srgb, var(--sp-accent) 85%, var(--sp-bg));
}

.sp-range-empty-availability {
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  padding: 0.6rem 1rem;
  background: var(--sp-bg);
  color: var(--sp-accent);
  font: inherit;
  cursor: pointer;
}

.sp-range-empty-availability:hover {
  background: var(--sp-hover);
}

.sp-range-empty-next:focus-visible,
.sp-range-empty-availability:focus-visible {
  outline: 2px solid var(--sp-focus);
  outline-offset: 2px;
}

.sp-daystrip {
  display: grid;
  grid-template-columns: repeat(var(--_sp-day-count, 5), minmax(0, 1fr));
  gap: var(--sp-gap);
  margin-block-end: 1rem;
}

.sp-strip-day {
  display: grid;
  justify-items: center;
  gap: 0.1rem;
  min-inline-size: 0;
  padding-block: 0.6rem 0.55rem;
  padding-inline: 0.25rem;
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  background: var(--sp-card-bg);
  color: var(--sp-fg);
  font: inherit;
  cursor: pointer;
}

.sp-strip-day:hover {
  background: var(--sp-hover);
}

.sp-strip-day[aria-pressed="true"] {
  border-color: var(--sp-accent);
  background: var(--sp-accent-soft);
}

.sp-strip-weekday {
  color: var(--sp-muted);
  font-size: 0.85rem;
}

.sp-strip-day[data-today] .sp-strip-weekday {
  font-weight: 700;
}

.sp-strip-date {
  font-size: 0.9rem;
}

.sp-strip-count {
  max-inline-size: 100%;
  color: var(--sp-muted);
  font-size: 0.8rem;
  text-align: center;
  overflow-wrap: anywhere;
}

.sp-panel-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-block-end: 0.75rem;
  text-align: center;
}

.sp-panel-title {
  font-size: 1rem;
}

.sp-panel-slots {
  display: grid;
  grid-template-columns: repeat(var(--sp-slot-columns, 3), minmax(0, 1fr));
  gap: var(--sp-gap);
}

/* Readable notice. Non-interactive: the control is the dot. Overflow is
   structurally contained so it can never bleed into the next column. */
.sp-day-notice {
  display: block;
  box-sizing: border-box;
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow: hidden;
  margin-block-end: 0.75rem;
  padding: 0.75rem 1rem;
  border-radius: var(--sp-radius);
  background: var(--sp-hover);
  text-align: center;
}

.sp-day-notice-label {
  display: -webkit-box;
  overflow: hidden;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  margin-block-end: 0.25rem;
}

/* The description stays in the DOM in every projection; the layout decides
   how much is revealed. Themes may override either rule. */
.sp-day-notice-description {
  display: none;
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
  margin: 0;
  color: var(--sp-muted);
  font-size: 0.9rem;
}

slot-picker[layout="day"] .sp-day-notice-label {
  display: block;
  -webkit-line-clamp: unset;
}

slot-picker[layout="day"] .sp-day-notice-description {
  display: block;
}

.sp-nav:focus-visible,
.sp-home:focus-visible,
.sp-more-button:focus-visible,
.sp-notice[data-day-index]:focus-visible,
.sp-strip-day:focus-visible {
  outline: 2px solid var(--sp-focus);
  outline-offset: 2px;
}

@media (forced-colors: active) {
  .sp-slot {
    border-color: ButtonText;
  }

  .sp-slot[aria-selected="true"] {
    border-width: 2px;
  }

  .sp-strip-day[aria-pressed="true"] {
    border-width: 2px;
    border-color: ButtonText;
  }

  .sp-day-notice {
    border: 1px solid ButtonText;
  }

  .sp-notice-dot {
    background: CanvasText;
  }
}
