/**
 * Day Detail Panel Styles
 * Slide-in panel for viewing day details and events
 */

/* Backdrop */
#day-detail-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  z-index: 999;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
}

#day-detail-backdrop.visible {
  opacity: 1;
  visibility: visible;
}

/* Panel container */
#day-detail-panel {
  position: fixed;
  top: 0;
  right: 0;
  width: 380px;
  max-width: 100%;
  /* 100vh on iOS / mobile Chrome includes the chrome bar; dvh tracks the
     dynamic viewport. Keep 100vh as a fallback for older browsers. */
  height: 100vh;
  height: 100dvh;
  background: var(--white, #fff);
  box-shadow: -4px 0 20px rgba(0, 0, 0, 0.15);
  z-index: 1000;
  transform: translateX(100%);
  /* Hide the closed panel from layout/hit-testing. Without this it stays
     rendered, translated a full panel-width to the RIGHT of the viewport — on a
     phone (where the panel is width:100vw) that off-screen copy extended the
     document to ~2× the viewport width and showed up as phantom horizontal
     overflow / a dead horizontal scroll (measured day-panel-content at
     right ~935 on a 390px screen). visibility:hidden takes it out of the
     overflow box; it's transition-delayed so the slide-out still animates before
     the panel disappears. */
  visibility: hidden;
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
              visibility 0s linear 0.3s;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#day-detail-panel.open {
  transform: translateX(0);
  visibility: visible;
  /* Cancel the close delay so the panel is visible immediately as it slides in. */
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
              visibility 0s linear 0s;
}

body.day-panel-open {
  overflow: hidden;
}

/* Panel header */
.day-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--slate-200, #e2e8f0);
  background: var(--slate-50, #f8fafc);
  flex-shrink: 0;
}

.day-panel-back {
  display: flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  color: var(--slate-500, #64748b);
  font-size: 0.8125rem;
  cursor: pointer;
  padding: 6px 10px;
  margin-left: -10px;
  border-radius: var(--radius-sm, 6px);
  transition: all 0.15s ease;
}

.day-panel-back:hover {
  background: var(--slate-100, #f1f5f9);
  color: var(--slate-700, #334155);
}

.day-panel-date {
  font-size: 1rem;
  font-weight: 600;
  color: var(--slate-800, #1e293b);
  flex: 1;
  text-align: center;
}

.day-panel-close {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Give the X its own surface + a darker glyph so it stays visible against the
     near-white header and any light content that scrolls beneath it. The old
     transparent bg + slate-400 glyph was ~2.45:1 contrast (failed; user report
     2026-06-17 — close buttons vanish over light areas). */
  background: var(--slate-100, #f1f5f9);
  border: 1px solid var(--slate-200, #e2e8f0);
  color: var(--slate-600, #475569);
  cursor: pointer;
  border-radius: var(--radius-full, 9999px);
  transition: all 0.15s ease;
}

.day-panel-close:hover {
  background: var(--red-50, #fef2f2);
  border-color: var(--red-200, #fecaca);
  color: var(--red-500, #ef4444);
}

/* Panel content */
.day-panel-content {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

/* ── "View this day on the board" ─────────────────────────────────────────
   Pinned below the scrolling list, mirroring the header's own bar treatment so
   the panel reads as header / content / footer rather than a list with a
   stray button after it.

   Why a FOOTER and not a header button: the header is a 3-slot space-between
   row (back / date / close) and the date is the dialog's aria-labelledby
   target which also takes focus on open, so it can be neither a button nor
   squeezed by a fourth control on a 390px screen.

   flex-shrink:0 keeps it visible while the events list scrolls; the panel is
   already display:flex/column. */
.day-panel-footer {
  flex-shrink: 0;
  padding: 12px 20px;
  padding-bottom: max(12px, env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--slate-200, #e2e8f0);
  background: var(--slate-50, #f8fafc);
}
.day-panel-footer:has(.day-panel-goto[hidden]) {
  /* Nothing to show once the board is already on this day: collapse the bar
     rather than leave an empty strip. */
  display: none;
}
.day-panel-goto {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  /* 44px: the panel's primary use is touch, and this is the one control here
     that navigates rather than dismisses. */
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid var(--slate-200, #e2e8f0);
  border-radius: 8px;
  background: var(--white, #fff);
  color: var(--slate-800, #1e293b);
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.day-panel-goto:hover {
  background: var(--slate-50, #f8fafc);
  border-color: var(--slate-300, #cbd5e1);
}
.day-panel-goto:focus-visible {
  outline: 2px solid var(--accent-primary, #06b6d4);
  outline-offset: 2px;
}
.day-panel-goto i {
  font-size: 0.875rem;
  color: var(--slate-500, #64748b);
}
.day-panel-goto[hidden] { display: none; }
body.dark-mode .day-panel-footer {
  border-top-color: var(--slate-700, #334155);
  background: var(--slate-900, #0f172a);
}
body.dark-mode .day-panel-goto {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
  color: var(--slate-100, #f1f5f9);
}
body.dark-mode .day-panel-goto:hover {
  background: var(--slate-700, #334155);
}

/* The per-event actions menu is `position:absolute; top:100%` INSIDE its card,
   so it overhangs the card's bottom edge. This container scrolls, and a
   scroll container clips its overflow on BOTH axes — `overflow-y:auto` with the
   default `overflow-x:visible` computes to `overflow-x:auto` per spec. So for
   the LAST card in the list the menu had nothing to overhang into and was cut
   off at the scroller's edge. That is an overflow clip, not a paint order
   problem: the existing z-index:50 fix below cannot reach it.

   Reserving space only while a menu is open keeps the normal scroll height
   honest (no permanent dead gap under the list) and gives the menu somewhere to
   land. `scroll-padding-bottom` additionally stops a programmatic
   scrollIntoView from parking the open menu under the pinned actions footer. */
.day-panel-content:has(.event-context-menu.open) {
  padding-bottom: 260px;
  scroll-padding-bottom: 260px;
}

/* Panel actions — the "Add event" affordance.
   Clicking any calendar day opens this panel, so without a create path an
   empty day was a dead end ("No events scheduled" and nothing to do).

   This is a SIBLING of .day-panel-content (the flex:1 scroller), not a child:
   as a pinned footer the primary action stays reachable on a busy day instead
   of scrolling out of view. flex-shrink:0 stops a long event list from
   squeezing it. The bottom padding clears the iOS home indicator. */
.day-panel-actions {
  flex-shrink: 0;
  padding: 16px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--slate-200, #e2e8f0);
  background: var(--slate-50, #f8fafc);
}

/* Filled teal, matching .btn-primary / .cal-find-times-btn so the app's
   primary action reads the same everywhere. */
.day-panel-add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 0 16px;
  /* 44px is the minimum comfortable touch target; the panel is full-screen on
     mobile, where this is the screen's primary action. */
  height: 44px;
  border: none;
  border-radius: var(--radius-full, 9999px);
  background: linear-gradient(135deg, var(--primary-500, #14b8a6) 0%, var(--accent-500, #06b6d4) 100%);
  color: #fff;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter 0.15s ease, opacity 0.15s ease;
}

.day-panel-add-btn:hover:not(:disabled) {
  filter: brightness(1.06);
}

.day-panel-add-btn:focus-visible {
  outline: 2px solid var(--primary-500, #14b8a6);
  outline-offset: 2px;
}

/* Past dates are view-only (PastDateGuard). Render the action disabled with a
   reason rather than hiding it — an absent control reads as a bug, a disabled
   one explains itself. Flat grey so it cannot be mistaken for the live CTA. */
.day-panel-add-btn:disabled {
  background: var(--slate-100, #f1f5f9);
  color: var(--slate-400, #94a3b8);
  cursor: not-allowed;
}

.day-panel-actions-note {
  margin: 8px 0 0;
  font-size: 0.75rem;
  color: var(--slate-500, #64748b);
  text-align: center;
}

body.dark-mode .day-panel-actions {
  border-top-color: var(--slate-700, #334155);
  /* Matches body.dark-mode .day-panel-header (slate-800), so the panel is
     bookended by the same surface top and bottom. Without this the light
     slate-50 fill above would paint a white bar across a dark panel's foot. */
  background: var(--slate-800, #1e293b);
}

body.dark-mode .day-panel-add-btn:disabled {
  background: var(--slate-800, #1e293b);
  color: var(--slate-500, #64748b);
}

body.dark-mode .day-panel-actions-note {
  color: var(--slate-400, #94a3b8);
}

/* Day status section */
.day-panel-section {
  margin-bottom: 24px;
}

.day-panel-section-title {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--slate-500, #64748b);
  margin-bottom: 10px;
}

/* Day status buttons */
.day-status-group {
  display: flex;
  gap: 8px;
}

.day-status-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 8px;
  background: var(--slate-50, #f8fafc);
  border: 2px solid var(--slate-200, #e2e8f0);
  border-radius: var(--radius-md, 8px);
  cursor: pointer;
  transition: all 0.15s ease;
}

.day-status-btn i {
  font-size: 1.125rem;
  color: var(--slate-400, #94a3b8);
}

.day-status-btn span {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--slate-600, #475569);
}

.day-status-btn:hover {
  background: var(--slate-100, #f1f5f9);
  border-color: var(--slate-300, #cbd5e1);
}

/* Available */
.day-status-btn[data-status="available"].active {
  background: var(--green-50, #f0fdf4);
  border-color: var(--green-500, #22c55e);
}

.day-status-btn[data-status="available"].active i {
  color: var(--green-500, #22c55e);
}

.day-status-btn[data-status="available"].active span {
  color: var(--green-700, #15803d);
}

/* Busy */
.day-status-btn[data-status="busy"].active {
  background: var(--amber-50, #fffbeb);
  border-color: var(--amber-500, #f59e0b);
}

.day-status-btn[data-status="busy"].active i {
  color: var(--amber-500, #f59e0b);
}

.day-status-btn[data-status="busy"].active span {
  color: var(--amber-700, #b45309);
}

/* Off */
.day-status-btn[data-status="off"].active {
  background: var(--slate-100, #f1f5f9);
  border-color: var(--slate-500, #64748b);
}

.day-status-btn[data-status="off"].active i {
  color: var(--slate-500, #64748b);
}

.day-status-btn[data-status="off"].active span {
  color: var(--slate-700, #334155);
}

/* Events list */
.day-panel-events-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* A column flex container sizes to its widest item unless this is set —
     without it an over-wide card widens the whole list past the panel. */
  min-width: 0;
}

/* Section header — used when shift events appear alongside regular ones. */
.day-panel-section-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  padding: 6px 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--slate-500, #64748b);
}
.day-panel-section-header:first-child { margin-top: 0; }
.day-panel-section-header i { font-size: 0.85rem; opacity: 0.8; }
.day-panel-section-count {
  margin-left: auto;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--slate-100, rgba(148, 163, 184, 0.15));
  color: var(--slate-600, #475569);
  font-weight: 600;
  font-size: 0.7rem;
}

/* Empty state */
.day-panel-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 20px;
  text-align: center;
  color: var(--slate-400, #94a3b8);
}

.day-panel-empty i {
  font-size: 2rem;
  margin-bottom: 12px;
  opacity: 0.5;
}

.day-panel-empty p {
  font-size: 0.875rem;
  margin: 0;
}

/* Event card */
.day-panel-event-card {
  background: var(--white, #fff);
  border: 1px solid var(--slate-200, #e2e8f0);
  border-radius: var(--radius-md, 8px);
  padding: 12px 14px;
  position: relative;
  cursor: pointer;
  transition: all 0.15s ease;
  /* Card contents are contained by the card, never the other way round. */
  min-width: 0;
  box-sizing: border-box;
}

.day-panel-event-card:hover {
  border-color: var(--slate-300, #cbd5e1);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

/* ⭐⭐⭐ TENTATIVE / PROPOSED (2026-08-15, event-block vocabulary audit).
   The day panel rendered a tentative event IDENTICALLY to a confirmed one:
   this card never carried the status at all, so none of the board's
   confirmation vocabulary could reach it. That is one of the surfaces behind
   the owner's report that "proposed and tentative events weren't showing
   dashed borders" - the border was never missing here, the STATE was.

   Same channel as the board (border-style = confirmation) and the same 135
   degree stripe, mixed from currentColor so no amber enters the vocabulary.
   The card's fill is white/slate rather than a category hue, so the stripe is
   held low - enough to read as unsettled without fighting the title. */
.day-panel-event-card[data-status="tentative"],
.day-panel-event-card[data-status="proposed"] {
  border-style: dashed;
  border-color: color-mix(in srgb, currentColor 38%, transparent);
  background-image: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, currentColor 7%, transparent) 0px,
    color-mix(in srgb, currentColor 7%, transparent) 5px,
    transparent 5px,
    transparent 10px
  );
}

/* Declined is struck through rather than hidden here: the day panel is a
   LIST, and silently dropping a row reads as data loss. */
.day-panel-event-card[data-status="declined"] .event-card-title {
  text-decoration: line-through;
  opacity: 0.6;
}

.day-panel-event-card.external {
  cursor: default;
}

.day-panel-event-card.external:hover {
  box-shadow: none;
}

/* Read-only event card (user lacks edit permission) */
.day-panel-event-card.read-only {
  cursor: default;
  opacity: 0.85;
}

.day-panel-event-card.read-only:hover {
  box-shadow: none;
}

/* Focused event card (when navigating from calendar click).
   `.focused` carries the one-shot entry pulse (fires only when the class is
   freshly added on click). `.focus-persist` carries the steady ring and is
   re-applied across list re-renders WITHOUT re-triggering the pulse, so a
   visibility-pill change doesn't make the focused card jump. */
.day-panel-event-card.focus-persist {
  border-color: var(--primary-400, #2dd4bf);
  box-shadow: 0 0 0 3px rgba(20, 184, 166, 0.2), 0 4px 12px rgba(0, 0, 0, 0.1);
}
.day-panel-event-card.focused {
  border-color: var(--primary-400, #2dd4bf);
  box-shadow: 0 0 0 3px rgba(20, 184, 166, 0.2), 0 4px 12px rgba(0, 0, 0, 0.1);
  animation: event-focus-pulse 0.5s ease-out;
}

@keyframes event-focus-pulse {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 3px rgba(20, 184, 166, 0.4), 0 4px 12px rgba(0, 0, 0, 0.1);
  }
  50% {
    transform: scale(1.02);
    box-shadow: 0 0 0 5px rgba(20, 184, 166, 0.3), 0 6px 16px rgba(0, 0, 0, 0.12);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 3px rgba(20, 184, 166, 0.2), 0 4px 12px rgba(0, 0, 0, 0.1);
  }
}

/* Event card header.
   TWO units, not four loose children: `.event-card-when` (time + duration) and
   `.event-card-meta` (source badge + continuation badge). The old rule put all
   four children directly on a `space-between` row, which had two consequences:
   the duration got flung away from the time range it annotates, and — because
   nothing could shrink — a long range plus "Continues tomorrow" overflowed the
   card's upper section. Now the time unit holds its intrinsic width and the
   meta unit is the only flexible item, so overflow truncates there instead of
   spilling out of the card. `gap` replaces the old child `margin-left`. */
.event-card-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
  /* Nothing may escape the card's upper section. */
  overflow: hidden;
}

/* Time + duration read as one phrase and must never be split or wrapped. */
.event-card-when {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  flex: 0 0 auto;
  min-width: 0;
  white-space: nowrap;
}

.event-card-time {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--slate-500, #64748b);
  white-space: nowrap;
}

/* Compact duration ("1h30") next to the time range. Subdued vs time so the
   range stays the primary read. Spacing comes from `.event-card-when`'s gap. */
.event-card-duration {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--slate-400, #94a3b8);
  letter-spacing: 0.02em;
  white-space: nowrap;
  flex: 0 0 auto;
}

body.dark-mode .event-card-duration {
  color: var(--slate-500, #64748b);
}

/* Badge group — the flexible half of the header. Absorbs leftover width and
   is where any truncation happens. */
.event-card-meta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
}

/* Source badge */
.event-card-source {
  display: inline-flex;
  flex: 0 0 auto;
}

/* Multi-day continuation badge. The icon is fixed; only the label truncates,
   so the arrow stays legible even in a very narrow panel. */
.event-continuation-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  font-size: 0.7rem;
  line-height: 1.2;
  opacity: 0.6;
  color: var(--slate-500, #64748b);
}

.event-continuation-badge i {
  flex: 0 0 auto;
  font-size: 0.65rem;
}

.event-continuation-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.dark-mode .event-continuation-badge {
  color: var(--slate-400, #94a3b8);
}

.source-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 0.625rem;
  font-weight: 700;
  border-radius: 4px;
  color: white;
}

.source-badge.google {
  background: #4285f4;
}

.source-badge.microsoft {
  background: #00a4ef;
}

/* Event title. `overflow-wrap` + `word-break` keep a long unbroken string (a
   pasted meeting URL is the common case) inside the card instead of pushing
   the card's own width past the panel. */
.event-card-title {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--slate-800, #1e293b);
  margin-bottom: 8px;
  line-height: 1.3;
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}

/* Shift assignment reason — P2.4. One-line "Why this person?" summary
   rendered between the title and footer for quota-assigned shifts only.
   Subtle, secondary text so it doesn't compete with the title. */
.event-card-assignment-reason {
  font-size: 0.8125rem;
  color: var(--text-secondary, #64748b);
  margin-bottom: 8px;
  line-height: 1.35;
  display: flex;
  align-items: center;
  gap: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.event-card-assignment-reason i {
  font-size: 0.75rem;
  opacity: 0.7;
  flex-shrink: 0;
}
body.dark-mode .event-card-assignment-reason {
  color: var(--text-secondary, #94a3b8);
}

/* Event card footer */
.event-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.event-card-privacy {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.6875rem;
  font-weight: 500;
  padding: 3px 8px;
  border-radius: 12px;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.1s ease;
  user-select: none;
}

.event-card-privacy:hover {
  filter: brightness(0.92);
  transform: scale(1.04);
}

.event-card-privacy:active {
  transform: scale(0.97);
}

.event-card-privacy i {
  font-size: 0.625rem;
}

.event-card-privacy.privacy-hidden {
  background: var(--purple-50, #f5f3ff);
  color: var(--purple-600, #7c3aed);
}

.event-card-privacy.privacy-busy {
  background: var(--amber-50, #fffbeb);
  color: var(--amber-600, #d97706);
}

.event-card-privacy.privacy-full,
.event-card-privacy.privacy-visible {
  background: var(--green-50, #f0fdf4);
  color: var(--green-600, #16a34a);
}

/* Menu button */
.event-card-menu-btn {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--slate-400, #94a3b8);
  cursor: pointer;
  border-radius: var(--radius-sm, 6px);
  transition: all 0.15s ease;
}

.event-card-menu-btn:hover {
  background: var(--slate-100, #f1f5f9);
  color: var(--slate-600, #475569);
}

/* Context menu */
.event-context-menu {
  position: absolute;
  top: 100%;
  right: 8px;
  width: 220px;
  background: var(--white, #fff);
  border: 1px solid var(--slate-200, #e2e8f0);
  border-radius: var(--radius-md, 8px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
  padding: 8px;
  z-index: 100;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: all 0.15s ease;
}

.event-context-menu.open {
  opacity: 1;
  visibility: visible;
  transform: translateY(4px);
}

/* 2026-08-04 (user: "the options menu for events is hidden … the menu is under
   the layer"). The menu is `position:absolute; z-index:100` INSIDE its own
   card, and it overhangs the card's bottom edge (`top:100%`). But
   `.day-panel-event-card` is `position:relative` with z-index:auto, so it
   creates NO stacking context — every card paints in plain DOM order within
   the shared list context. The menu's z-index:100 therefore only sorts it
   against its own card's children; the NEXT card in the list is a positioned
   later sibling, so it paints straight over the overhanging menu. With four
   events stacked, the dropdown from card 1 disappeared behind cards 2-4 (it
   was rendering the whole time, just underneath).
   Fix: give the card that owns an OPEN menu a real z-index so it and its
   overhanging menu win against the cards below. Scoped to the open state so
   normal cards keep their default painting and the hover shadow order. */
.day-panel-event-card:has(.event-context-menu.open) {
  z-index: 50;
}

.context-menu-section {
  margin-bottom: 4px;
}

.context-menu-label {
  font-size: 0.625rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--slate-400, #94a3b8);
  padding: 6px 10px 4px;
}

.context-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  background: none;
  border: none;
  font-size: 0.8125rem;
  color: var(--slate-700, #334155);
  cursor: pointer;
  border-radius: var(--radius-sm, 6px);
  text-align: left;
  transition: all 0.1s ease;
}

.context-menu-item i {
  width: 16px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--slate-400, #94a3b8);
}

.context-menu-item:hover {
  background: var(--slate-100, #f1f5f9);
}

.context-menu-item.active {
  background: var(--primary-50, #f0fdfa);
  color: var(--primary-700, #0f766e);
}

.context-menu-item.active i {
  color: var(--primary-500, #14b8a6);
}

.context-menu-item.danger:hover {
  background: var(--red-50, #fef2f2);
  color: var(--red-600, #dc2626);
}

.context-menu-item.danger:hover i {
  color: var(--red-500, #ef4444);
}

.context-menu-divider {
  height: 1px;
  background: var(--slate-200, #e2e8f0);
  margin: 6px 0;
}

/* Source badge for synced events */
.context-menu-source-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin-bottom: 4px;
  background: var(--slate-100, #f1f5f9);
  border-radius: var(--radius-sm, 6px);
  font-size: 0.6875rem;
  font-weight: 600;
  color: var(--slate-600, #475569);
}

.context-menu-source-badge i {
  font-size: 0.875rem;
  color: var(--slate-500, #64748b);
}

.context-menu-source-badge i.fa-google {
  color: #4285f4;
}

.context-menu-source-badge i.fa-microsoft {
  color: #00a4ef;
}

/* Info message for external events */
.context-menu-info {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px;
  margin-top: 4px;
  background: var(--blue-50, #eff6ff);
  border-radius: var(--radius-sm, 6px);
  font-size: 0.75rem;
  color: var(--blue-700, #1d4ed8);
  line-height: 1.4;
}

.context-menu-info i {
  flex-shrink: 0;
  margin-top: 1px;
}

/* Per-board override indicator in All Groups context menu */
.context-menu-override-note {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  margin-top: 4px;
  background: var(--amber-50, #fffbeb);
  border-radius: var(--radius-sm, 6px);
  font-size: 0.7rem;
  color: var(--amber-700, #b45309);
  line-height: 1.3;
}

.context-menu-override-note i {
  flex-shrink: 0;
  font-size: 0.65rem;
}

/* 2026-08-04 AUDIT — a teammate's event shows its visibility as a read-only
   FACT, never as a control (only the owner may change who sees an event).
   Neutral slate, not the amber "action needed" treatment above. */
.context-menu-readonly-note {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--slate-50, #f8fafc);
  border-radius: var(--radius-sm, 6px);
  font-size: 0.7rem;
  color: var(--slate-500, #64748b);
  line-height: 1.3;
}

.context-menu-readonly-note i {
  flex-shrink: 0;
  font-size: 0.65rem;
}

/* The privacy pill on someone else's card: same colour language, but nothing
   about it should invite a tap (no pointer, no hover lift, not focusable). */
.event-card-privacy.is-readonly {
  cursor: default;
  opacity: 0.75;
}

.event-card-privacy.is-readonly:hover {
  filter: none;
  transform: none;
}

/* ============================================
   DARK MODE
   ============================================ */

body.dark-mode #day-detail-backdrop {
  background: rgba(0, 0, 0, 0.5);
}

body.dark-mode #day-detail-panel {
  background: var(--slate-900, #0f172a);
  box-shadow: -4px 0 30px rgba(0, 0, 0, 0.4);
}

body.dark-mode .day-panel-header {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}

body.dark-mode .day-panel-back {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .day-panel-back:hover {
  background: var(--slate-700, #334155);
  color: var(--slate-200, #e2e8f0);
}

body.dark-mode .day-panel-date {
  color: var(--slate-100, #f1f5f9);
}

body.dark-mode .day-panel-close:hover {
  background: rgba(239, 68, 68, 0.15);
}

body.dark-mode .day-panel-section-title {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .day-status-btn {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}

body.dark-mode .day-status-btn span {
  color: var(--slate-300, #cbd5e1);
}

body.dark-mode .day-status-btn:hover {
  background: var(--slate-700, #334155);
  border-color: var(--slate-600, #475569);
}

body.dark-mode .day-status-btn[data-status="available"].active {
  background: rgba(34, 197, 94, 0.15);
  border-color: var(--green-500, #22c55e);
}

body.dark-mode .day-status-btn[data-status="busy"].active {
  background: rgba(245, 158, 11, 0.15);
  border-color: var(--amber-500, #f59e0b);
}

body.dark-mode .day-status-btn[data-status="off"].active {
  background: var(--slate-700, #334155);
  border-color: var(--slate-500, #64748b);
}

body.dark-mode .day-panel-empty {
  color: var(--slate-500, #64748b);
}

body.dark-mode .day-panel-event-card {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}

body.dark-mode .day-panel-event-card:hover {
  border-color: var(--slate-600, #475569);
}

body.dark-mode .event-card-time {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .event-card-title {
  color: var(--slate-100, #f1f5f9);
}

body.dark-mode .event-card-privacy.privacy-hidden {
  background: rgba(139, 92, 246, 0.15);
  color: var(--purple-400, #a78bfa);
}

body.dark-mode .event-card-privacy.privacy-busy {
  background: rgba(217, 119, 6, 0.15);
  color: var(--amber-400, #fbbf24);
}

body.dark-mode .event-card-privacy.privacy-full,
body.dark-mode .event-card-privacy.privacy-visible {
  background: rgba(22, 163, 74, 0.15);
  color: var(--green-400, #4ade80);
}

body.dark-mode .event-card-menu-btn:hover {
  background: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}

body.dark-mode .event-context-menu {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}

body.dark-mode .context-menu-item {
  color: var(--slate-200, #e2e8f0);
}

body.dark-mode .context-menu-item:hover {
  background: var(--slate-700, #334155);
}

body.dark-mode .context-menu-item.active {
  background: rgba(20, 184, 166, 0.15);
  color: var(--primary-400, #2dd4bf);
}

body.dark-mode .context-menu-divider {
  background: var(--slate-700, #334155);
}

body.dark-mode .context-menu-source-badge {
  background: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}

body.dark-mode .context-menu-source-badge i {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .context-menu-info {
  background: rgba(59, 130, 246, 0.15);
  color: var(--blue-400, #60a5fa);
}

body.dark-mode .context-menu-override-note {
  background: rgba(245, 158, 11, 0.15);
  color: var(--amber-400, #fbbf24);
}

/* Paired dark variant — without it the light slate panel paints on a dark
   board (this repo does NOT fall back to a neutral; the light rule wins). */
body.dark-mode .context-menu-readonly-note {
  background: rgba(148, 163, 184, 0.12);
  color: var(--slate-400, #94a3b8);
}

/* ============================================
   MOBILE RESPONSIVE
   ============================================ */

@media (max-width: 480px) {
  /* Full-screen sheet on phones. width:100vw (not 100%) anchors to the visual
     viewport so a contributing ancestor can't widen it, and the panel already
     uses height:100dvh, so it reads as a native full-screen push screen. */
  #day-detail-panel {
    width: 100vw;
    max-width: 100vw;
  }

  /* Belt-and-suspenders: nothing inside the sheet may exceed it. The header
     date could be a long localized string; let it ellipsize rather than push
     the close button off the edge. */
  .day-panel-content,
  .day-panel-section,
  .day-panel-header {
    max-width: 100%;
  }

  .day-panel-date {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }
}
