/* ============================================
   CALENDAR WEEK & AGENDA VIEW STYLES
   ============================================ */

/* ============================================
   VIEW SWITCHER (Month/Week/Agenda)
   Matches event-modal-tabs styling
   ============================================ */

.cal-view-switcher {
  display: flex;
  gap: 2px;
  padding: 2px;
  background: var(--slate-100, #f1f5f9);
  border-radius: var(--radius-lg, 12px);
  /* Allow the switcher to give up width so the Find Times button stays on the
     SAME header row (user 2026-07-11: "the find times button still takes its
     own row reduce tabs to fit the button in the same row"). It used to be
     flex-shrink:0, which forced the row over its width budget on narrower
     calendars and pushed Find Times to wrap. min-width:0 lets the flex items
     inside actually shrink; white-space:nowrap on the buttons below keeps each
     label on one line as they narrow. */
  flex-shrink: 1;
  min-width: 0;
}

.cal-view-btn {
  padding: 6px 10px;
  border: none;
  background: transparent;
  border-radius: var(--radius-md, 8px);
  font-size: 12px;
  font-weight: 500;
  color: var(--slate-500, #64748b);
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.15s ease;
}

.cal-view-btn:hover {
  color: var(--slate-700, #334155);
  background: rgba(255, 255, 255, 0.5);
}

.cal-view-btn.active {
  background: white;
  color: var(--primary-600, #0d9488);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  font-weight: 600;
}

/* Dark mode */
body.dark-mode .cal-view-switcher {
  background: var(--slate-800, #1e293b);
}

body.dark-mode .cal-view-btn {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .cal-view-btn:hover {
  color: var(--slate-200, #e2e8f0);
  background: var(--slate-700, #334155);
}

body.dark-mode .cal-view-btn.active {
  background: var(--slate-700, #334155);
  color: var(--emerald-400, #34d399);
  box-shadow: var(--shadow-sm);
}


/* ============================================
   SCOPE FILTER TABS (Mine / Team / All)
   Primary axis — whose events the calendar shows. Sits above the category
   filter so it reads first.
   ============================================ */

/* 2026-06-22 redesign: scope segment + category pill share ONE row
   (.calendar-filter-bar) instead of two stacked full-width segmented rows —
   different shapes on one line read as two distinct axes, not "duplicate rows",
   and reclaim a row of vertical space so more day cells show. */
.calendar-filter-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0 4px 8px;
  flex-shrink: 0;
  position: relative; /* anchor for the absolutely-positioned category menu */
}
/* When Find Times is active the always-visible #find-times-banner (a sibling
   below this bar) takes over the row's job — criteria summary + live duration
   slider. Collapse this now-redundant filter bar entirely so we don't leave an
   empty gap above the banner (set by renderFindTimesBanner). */
.calendar-filter-bar[data-find-times="active"] {
  display: none;
}

/* Find Times button relocated into the filter bar (see _mountFindTimesInFilterBar
   in calendar.js). It shares this row with the Mine/Team/All scope tabs, pinned
   to the RIGHT edge via margin-left:auto so scope tabs (+ any category/heatmap
   controls) pack left and Find Times reads as a right-aligned CTA. This is what
   collapses the mobile header to two rows (Row 1: date + Month/Week/Agenda; Row
   2: scope tabs + Find Times). It rides the base .cal-find-times-btn pill styling
   (day-nav.css) for its fill/label. */
.calendar-filter-bar .cal-find-times-btn--in-filter-bar {
  margin-left: auto;
  flex: 0 0 auto;
  align-self: center;
}

.calendar-scope-tabs {
  display: flex;
  gap: 2px;
  padding: 3px;
  margin: 0;            /* the .calendar-filter-bar owns row spacing now */
  background: var(--slate-100, #f1f5f9);
  border-radius: var(--radius-lg, 12px);
  flex-shrink: 0;
}

.calendar-scope-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  font-size: 12px;
  font-weight: 500;
  color: var(--slate-500, #64748b);
  background: transparent;
  border: none;
  border-radius: var(--radius-md, 8px);
  cursor: pointer;
  transition: all 0.15s ease;
  white-space: nowrap;
  flex: 1;
}

.calendar-scope-tab:hover {
  color: var(--slate-700, #334155);
  background: rgba(255, 255, 255, 0.5);
}

.calendar-scope-tab.active {
  background: white;
  color: var(--primary-600, #0d9488);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  font-weight: 600;
}

.calendar-scope-tab i { font-size: 11px; }

/* Team scope — indigo accent when active, distinct from the personal/work
   pink/blue so the axis reads as separate from category. */
.calendar-scope-tab[data-scope="team"].active {
  color: #6366f1;
}
.calendar-scope-tab[data-scope="team"].active i { color: #818cf8; }

.calendar-scope-tab[data-scope="all"].active {
  color: #475569;
}

/* ============================================================
   ROW SWAP (user 2026-07-04) — both viewports
   Scope tabs (Mine/Team/All) relocated by calendar.js into the
   .calendar-header-row's trailing corner (next to the day-nav);
   the Month/Week/Agenda switcher relocated down into the
   .calendar-filter-bar as its leading child, sharing that row
   with the Find Times CTA. Only the placement classes are styled
   here — the segmented-control chrome is inherited unchanged.
   ============================================================ */
/* The header row itself had NO layout rule anywhere in the stylesheet — it
   rendered as a plain block, so `margin-left:auto` on the scope tabs below
   could never fire and the tabs dropped onto their own line under the date.
   That is the "Mine/All is on its own row on mobile" report: the row swap in
   calendar.js re-parented the tabs correctly, but the parent was never a flex
   container, so they simply stacked. Declare the row as a single no-wrap flex
   line so the day-nav leads and the scope tabs ride its trailing corner. */
.calendar-header-row {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;      /* one line — never let the tabs wrap under the date */
  gap: 8px;
  min-width: 0;           /* allow the day-nav to shrink instead of forcing a wrap */
}
/* The day-nav is `flex:1 1 auto` (day-nav.css) so its date cluster can centre.
   Paired with a nowrap row that is right: it yields the leftover space to the
   scope tabs rather than pushing them off. It must be allowed to SHRINK below
   its content width though, or a long date label ("Today, Jul 26") would force
   the row wider than the viewport on a phone. */
.calendar-header-row .cal-day-nav {
  min-width: 0;
}
/* Scope tabs pinned to the far-right corner of the header row (the day-nav
   leads on the left; margin-left:auto opens the gap between them). */
.calendar-header-row .calendar-scope-tabs--in-header {
  margin-left: auto;
  flex: 0 0 auto;
}
/* View switcher now leads the filter-bar row; Find Times keeps its own
   margin-left:auto so it stays right-pinned and the switcher packs left. */
.calendar-filter-bar .cal-view-switcher--in-filter-bar {
  flex: 0 0 auto;
  margin: 0;
}
/* When Find Times mode is active the filter bar collapses (display:none) and
   the in-flow #find-times-banner takes its place. But the Month/Week/Agenda
   switcher now lives in that bar, so collapsing the bar would strip the only way
   to leave month view while Find Times is on. Re-float the bar as a switcher +
   Find Times strip in that state. 2026-07-10 (user: "the find times button
   maintains its presence"): the Find Times CTA now STAYS visible while active —
   re-pressing it reopens the criteria menu and its reset ✕ exits the mode — so
   we keep the switcher on the left and the Find Times CTA right-pinned. */
.calendar-filter-bar[data-find-times="active"]:has(.cal-view-switcher--in-filter-bar) {
  display: flex;
  justify-content: flex-start;
}

/* ============================================================
   WEEK VIEW header compaction (user 2026-07-12: "bring up the
   find times and bring one tab into this space to reduce the
   view"). In week view the range now lives BETWEEN the chevrons
   (#cal-current-date) and the separate #cal-view-title is hidden,
   which frees the header row. Pull the Find Times CTA + the
   Month/Week/Agenda switcher UP tight against that row so the
   second (filter) row stops eating vertical space — the week grid
   gets those pixels back. Scoped to [data-cal-view="week"] on the
   calendar container so month/agenda keep their normal spacing.
   ============================================================ */
#calendar-container[data-cal-view="week"] .calendar-filter-bar {
  margin-top: -2px;
  margin-bottom: 4px;
}
/* Trim the switcher + Find Times CTA a touch so both sit comfortably on the
   pulled-up row without wrapping on narrow calendars. */
#calendar-container[data-cal-view="week"] .cal-view-switcher--in-filter-bar .cal-view-btn {
  padding-top: 4px;
  padding-bottom: 4px;
}
#calendar-container[data-cal-view="week"] .cal-find-times-btn--in-filter-bar {
  height: 32px;
}
/* The standalone range title never shows in week view (the range is in the
   chevrons now) — belt-and-braces in case a stale render leaves text behind. */
#calendar-container[data-cal-view="week"] .cal-view-title {
  display: none;
}

/* ============================================================
   MOBILE: keep [Mine|Team|All] on the DATE row
   ============================================================
   Making .calendar-header-row a nowrap flex line (above) is what stops the
   tabs dropping to their own row, but at ~360px the date cluster + three
   labelled segments still overflow. Rather than let them spill, compact the
   segmented control: the icons alone carry the meaning at this size (each
   button keeps its title/aria label), and the text labels return as soon as
   there is room. Segments stay ≥36px wide so they remain a real touch target.
   ============================================================ */
@media (max-width: 640px) {
  .calendar-header-row {
    gap: 6px;
    /* RECLAIM THE TOP ROWS (2026-08-16, user: "on mobile,.top rows have extra
       wasted space now"). Measured on the live build at narrow width: the
       header row stood at 54px and the filter bar added 36px plus an 8px
       margin, so ~98px of chrome sat above the grid before a single day cell
       — on the viewport with the least room to spare. Trim the padding and
       the inter-row margin; the controls keep their touch targets. */
    padding-top: 2px;
    padding-bottom: 2px;
    /* Added 2026-08-17 with the row merge below: this row now owns the filter
       bar's former children, so it owns the spacing that used to sit on it. */
    row-gap: 6px;
    margin-bottom: 4px;
  }
  /* MERGE THE TWO CHROME ROWS INTO ONE (2026-08-17, user re-reported the same
     thing: "two empty week rows at the top of month view").

     The 2026-08-16 trim above only shaved padding, so BOTH rows survived and
     the report came back. There are genuinely two full-width flex rows above
     the weekday strip: the header row (date nav + scope tabs) and the filter
     bar (Month/Week/Agenda + Find Times), the latter created by
     _applyRowSwap() moving the switcher down out of the header. At phone width
     they read as two blank week rows before a single date appears.

     The merge itself is done in JS (_applyRowSwap re-parents the filter bar's
     children into the header row under 640px) rather than in CSS. `display:
     contents` cannot do it here: .calendar-filter-bar is a SIBLING of
     .calendar-header-row, both children of a column-direction flex container,
     so dissolving its box would stack its children vertically and make the
     problem worse rather than merging the rows.

     What remains here is the styling the merged row needs. The empty filter
     bar collapses so it contributes no height, and Find Times drops its
     right-pin so it flows inline instead of stranding itself on its own line. */
  .calendar-filter-bar:empty {
    display: none;
  }
  /* TIGHTEN THE MERGED CHROME (2026-08-29, user: "calendar white space …
     reduce one unnecessary row on mobile" — and, on their device, "3 rows").

     MEASURED on the running build at 390px before this pass:
       cal-day-nav 189 · ? 44 · pills 114 · switcher 164 · Find Times 44
       = 555px of controls in a 370px row.
     One line is therefore NOT reachable by shrinking — it needs a control
     REMOVED, which is a product call, not a CSS one. (An earlier attempt at
     this pass shrank Find Times 125px→44px and reclaimed exactly ZERO height:
     chrome stayed 106px and the grid still started at y=141. Width was never
     the thing costing vertical space.)

     What IS wrong, read off the render: line 2 was nearly EMPTY — the switcher
     at the left edge, Find Times shoved to the far right by its margin-left:auto,
     and a lake between them. And two cases went to THREE rows:
       · AGENDA view at every width — #cal-view-title (the ~110px range label)
         becomes visible and takes a line of its own.
       · any view at ≤344px — 152px of chrome.

     So this pass keeps two rows and makes them tight and honest:
       1. Find Times packs next to the switcher instead of stranding itself, so
          line 2 carries real content rather than a gap.
       2. The range title shares line 1 with the date instead of claiming a row.
       3. Vertical padding and row-gap come down; that is the actual white space.
     flex-wrap:wrap stays (guard-pinned) so a long locale date still wraps
     instead of overflowing. */
  .calendar-header-row {
    flex-wrap: wrap;
    row-gap: 2px;
    padding-top: 0;
    padding-bottom: 0;
    margin-bottom: 2px;
  }
  .calendar-header-row .cal-view-switcher {
    margin-left: 0;
    flex: 0 0 auto;
  }
  .calendar-header-row .cal-view-switcher .cal-view-btn {
    padding: 6px 8px;
    font-size: 12px;
  }
  /* ONE ROW OF CHROME (2026-08-30, owner: "4 attempts and still no change. I
     want two rows, bring the smaller tab structure upwards and remove help if
     necessary").

     ⚠️WHY THE PREVIOUS FOUR ATTEMPTS FAILED: every one of them re-parented
     controls or trimmed padding. None changed the ARITHMETIC, and the row was
     overflowing. Measured live on the deployed build at a 481px header row:

       help 30 + date-nav 190 + scope-tabs 114 + switcher 164 + Find 144
       + gaps = 666px into 481px  →  overflows by 185px  →  wraps.

     Re-parenting cannot fix that; something has to leave. Dropping help alone
     leaves 630px (still wraps); dropping help AND the tabs leaves 510px (STILL
     wraps). Only removing the scope tabs and capping Find Times fits:
     190 + 143 + 104 + gaps = 437px → ONE line, header 96px → 54px.

     The scope tabs are the right thing to cut. filterEventsByScope() is real,
     but 'mine' and 'all' both return the events unfiltered — only 'team'
     discriminates, and only when events carry a participants array naming
     someone else. On a typical board all three tabs show the same thing, so
     they cost 114px of the tightest row in the app to express a distinction the
     user cannot see. The filter function and its saved preference are KEPT;
     only the phone-width control is hidden.

     ⚠️HELP GOES TOO, and it is the LAST 26px that decides it (owner: "remove
     help if necessary" — it is). Measured live with the tabs already hidden:
     help 26+4 + nav 180 + switcher 164 + Find 108 + gaps = 478px into 485px,
     which STILL wrapped Find onto its own line (96px). Trimming the switcher's
     button padding changed nothing — the sum was already the constraint.
     Hiding help: 452px, ONE line, 54px. The calendar key is still reachable
     from the board's own "?" trigger, so the legend is not lost — only this
     duplicate entry point at the width that cannot afford it. */
  .calendar-header-row .calendar-scope-tabs--in-header,
  .calendar-header-row .calendar-key-trigger {
    display: none;
  }
  /* The auto margin is now HARMFUL, and the note that defended it no longer
     applies. It said: keep `auto` because packing Find Times left brings the
     wrap point forward, and "the gap on line 2 is cosmetic; an extra row is
     not." That reasoning assumed a row that wraps. With the tabs gone the row
     fits on ONE line, so there is no line 2 to have a gap on — and on a
     wrapping flex row `margin-left:auto` consumes all the free space, which is
     what pushed Find Times onto its own line in the first place. Measured: with
     the tabs hidden the three survivors sit at 437px of 481px with the button
     still in its trailing corner, because `auto` on a NON-wrapping line does
     exactly what it does on desktop. */
  .calendar-header-row .cal-find-times-btn {
    margin-left: auto;
    /* Cap the pill so a long locale label cannot re-create the overflow. At
       481px the button measures 144px; 104px keeps the search glyph and the
       label legible while leaving ~44px of slack for narrower phones. */
    max-width: 108px;
    overflow: hidden;
  }
  /* The week/agenda range title took a whole line to itself in agenda view
     (measured: 3 rows at every width). Let it sit inline and truncate rather
     than claim a row; the date cluster beside it already carries the day. */
  .calendar-header-row .cal-view-title {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Reclaim the button chrome's own vertical padding. 36px keeps every control
     a legitimate touch target while dropping 8px per row versus 44px. */
  .calendar-header-row .cal-day-nav .cal-icon-btn,
  .calendar-header-row .calendar-key-trigger {
    height: 36px;
  }
  .calendar-weekdays {
    margin-bottom: 0;
    padding-bottom: 1px;
  }
  /* Shrink-to-fit, but never below a legible date. */
  .calendar-header-row .cal-day-nav .cal-current-date {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .calendar-header-row .calendar-scope-tabs--in-header {
    padding: 2px;
    gap: 1px;
  }
  .calendar-header-row .calendar-scope-tabs--in-header .calendar-scope-tab {
    padding: 7px 9px;
    min-width: 36px;      /* touch target preserved without the text label */
    gap: 0;
  }
  /* Icon-only at phone width — the label is the first thing to go, not the
     whole control. title + aria-label still name each segment. */
  .calendar-header-row .calendar-scope-tabs--in-header .calendar-scope-tab > span {
    display: none;
  }
  .calendar-header-row .calendar-scope-tabs--in-header .calendar-scope-tab i {
    font-size: 12px;
  }
}

/* ONE LINE AT PHONE WIDTH (2026-09-01, owner screenshot: the Find Times
   pill — and especially its active search/undo split state — wrapped onto a
   second header line at 412px).

   Measured live at a 412px viewport: day-nav 167 + switcher 164 + Find Times
   108 + gaps ≈ 451px into a ~404px row → wraps. The ≤640px pass above already
   removed the scope tabs and the help trigger, so nothing else can LEAVE —
   the remaining trio has to slim down. Same recipe the scope pills used:
   Find Times goes ICON-ONLY (the 🔍 glyph + the reset slot; title/aria-label
   keep the full name), the switcher and day-nav shed a few px of padding, and
   the row gap tightens. Sum after: ~380px, which clears 390px and 412px on
   ONE line. flex-wrap:wrap stays (guard-pinned) as the safety valve for very
   long locale strings — this is a preference for one line, not a ban on two.

   Scoped under #calendar-container so these win over the equal-specificity
   ≤640px rules in style.css regardless of sheet order (dist inverts dev). */
@media (max-width: 480px) {
  /* 2026-09-02: the label clip moved to <=399px (see day-nav.css for the
     measurements). Everything else in this block is SPACE-SAVING trim and must
     stay at <=480px — those few px are what keep the now-labelled button on ONE
     header line at 400-480px. Demoting them to <=399px wrapped the header to 2
     lines and cost 50px of day grid, which is the opposite of the point. */
  #calendar-container .calendar-header-row .cal-find-times-btn {
    padding: 0 10px;
  }
  /* Trim the Month/Week/Agenda tabs a touch more than the ≤640 pass. */
  #calendar-container .calendar-header-row .cal-view-switcher .cal-view-btn {
    padding-left: 6px;
    padding-right: 6px;
  }
  /* The close/calendar chip joins the other day-nav buttons at 30px. */
  #calendar-container .calendar-header-row .cal-day-nav .cal-icon-btn.cal-close-btn {
    width: 30px;
    min-width: 30px;
  }
  #calendar-container .calendar-header-row {
    column-gap: 4px;
  }
}

/* 400-429px: the icon-only squash that used to live here is GONE (2026-09-02,
   owner: "find times button is deformed. bring it to the row with the
   dragger"). It only existed because the dragger took a full-width line of its
   own, stranding the button on a third line where 17px of overflow forced it to
   a 36px puck. The dragger now shares the button's line and flexes, so the
   button renders at its natural labelled size at every width from 400px up. */

/* Icon-only Find Times on the tightest phones only. The label is the first
   thing to go, never the control — title + aria-label (index.html) still name
   it. 2026-09-02: gated to <=399px (was <=480px) in lockstep with the
   day-nav.css twin; measured, the label is FREE from 400px up once the duration
   dragger takes its own header line, and below 400px it would only clip to
   "Times" against the 36px circle anyway. */
@media (max-width: 399px) {
  #calendar-container .calendar-header-row .cal-find-times-btn .cal-find-times-btn__label {
    display: none;
  }
}

body.dark-mode .calendar-scope-tabs {
  background: var(--slate-800, #1e293b);
}
body.dark-mode .calendar-scope-tab {
  color: var(--slate-400, #94a3b8);
}
body.dark-mode .calendar-scope-tab:hover {
  color: var(--slate-200, #e2e8f0);
  background: var(--slate-700, #334155);
}
body.dark-mode .calendar-scope-tab.active {
  background: var(--slate-700, #334155);
  color: var(--emerald-400, #34d399);
}
body.dark-mode .calendar-scope-tab[data-scope="team"].active {
  color: #a5b4fc;
}

/* ============================================
   CATEGORY FILTER — PILL + DROPDOWN MENU (2026-06-22)
   Replaces the old full-width 4-tab .calendar-filter-tabs row. The pill shows
   the CURRENT category (icon + label + accent) and opens a small menu; it sits
   on the shared .calendar-filter-bar beside the scope segmented control. Its
   distinct pill shape is what visually separates the "what" axis from the
   segmented "whose" axis, answering the user's "two duplicate rows?" report.
   ============================================ */

.calendar-category-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 7px 12px;
  border: 1px solid var(--slate-200, #e2e8f0);
  border-radius: var(--radius-full, 999px);
  background: var(--slate-100, #f1f5f9);
  color: var(--slate-600, #475569);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.calendar-category-pill:hover {
  background: var(--slate-200, #e2e8f0);
  color: var(--slate-700, #334155);
}
.calendar-category-pill::after {
  content: "\f107"; /* fa-chevron-down */
  font-family: "Font Awesome 6 Free";
  font-weight: 900;
  font-size: 11px;
  opacity: 0.6;
  margin-left: 2px;
}
.calendar-category-pill[aria-expanded="true"]::after { transform: rotate(180deg); }
.calendar-category-pill i { font-size: 12px; }
/* Accent the pill in the active category's colour so "Personal"/"Work" read at
   a glance (mirrors the old tab accents). 'all' stays neutral. */
.calendar-category-pill[data-filter="personal"] { color: #db2777; border-color: color-mix(in srgb, #db2777 35%, transparent); }
.calendar-category-pill[data-filter="personal"] i { color: #db2777; }
.calendar-category-pill[data-filter="work"] { color: #2563eb; border-color: color-mix(in srgb, #2563eb 35%, transparent); }
.calendar-category-pill[data-filter="work"] i { color: #2563eb; }
.calendar-category-pill[data-filter="shifts"] { color: var(--primary-600, #0d9488); border-color: color-mix(in srgb, var(--primary-600, #0d9488) 35%, transparent); }
.calendar-category-pill[data-filter="shifts"] i { color: var(--primary-600, #0d9488); }

.calendar-category-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 30;
  min-width: 168px;
  padding: 4px;
  background: var(--surface-primary, #ffffff);
  border: 1px solid var(--slate-200, #e2e8f0);
  border-radius: var(--radius-lg, 12px);
  box-shadow: 0 12px 32px -8px rgba(15, 23, 42, 0.2), 0 4px 12px -2px rgba(15, 23, 42, 0.08);
  animation: calCatMenuIn 0.14s ease-out;
}
@keyframes calCatMenuIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.calendar-category-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: none;
  background: transparent;
  border-radius: var(--radius-md, 8px);
  color: var(--slate-700, #334155);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
}
.calendar-category-menu-item:hover { background: var(--slate-100, #f1f5f9); }
.calendar-category-menu-item.is-active { font-weight: 600; }
.calendar-category-menu-item i { font-size: 13px; width: 16px; text-align: center; }
.calendar-category-menu-item__check { margin-left: auto; color: var(--primary-600, #0d9488); }
.calendar-category-menu-item[data-filter="personal"] i { color: #db2777; }
.calendar-category-menu-item[data-filter="work"] i { color: #2563eb; }
.calendar-category-menu-item[data-filter="shifts"] i { color: var(--primary-600, #0d9488); }

/* Touch: ≥44px targets for the pill + menu items + each scope segment. */
@media (pointer: coarse) {
  .calendar-category-pill { min-height: 44px; }
  .calendar-category-menu-item { min-height: 44px; }
  .calendar-scope-tab { min-height: 44px; }
}

/* Dark mode */
body.dark-mode .calendar-category-pill {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}
body.dark-mode .calendar-category-pill:hover { background: var(--slate-700, #334155); }
body.dark-mode .calendar-category-pill[data-filter="personal"] { color: #f9a8d4; }
body.dark-mode .calendar-category-pill[data-filter="work"] { color: #60a5fa; }
body.dark-mode .calendar-category-menu {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}
body.dark-mode .calendar-category-menu-item { color: var(--slate-200, #e2e8f0); }
body.dark-mode .calendar-category-menu-item:hover { background: var(--slate-700, #334155); }

/* ============================================
   ALTERNATIVE VIEW CONTAINER (Week/Agenda)
   ============================================ */

#cal-alt-view-container {
  width: 100%;
  min-height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

#cal-alt-view-container:empty {
  display: none;
}

/* Reset calendar container when switching views */
#calendar-container {
  overflow: hidden;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* Calendar-days grid should fill available space */
#calendar-container .calendar-days,
.calendar-days {
  width: 100% !important;
  max-width: 100% !important;
  box-sizing: border-box;
  overflow: hidden;
  flex: 1;
  min-height: 0;
}

/* ============================================
   WEEK VIEW - AGENDA STYLE
   ============================================ */

/* Agenda wrapper - 7 column grid */
.cal-week-agenda-view {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  background: var(--surface-primary, #ffffff);
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

.cal-week-agenda-wrapper {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--slate-200, #e2e8f0);
  flex: 1;
  overflow-x: hidden;
  overflow-y: auto;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* Individual day column. container-type: inline-size lets event-row layout
   stack time-above-title when the column is too narrow (≤140px) — see the
   @container query in `.cal-week-event-row`. */
.cal-week-day-column {
  display: flex;
  flex-direction: column;
  background: var(--surface-primary, #ffffff);
  min-height: 0;
  min-width: 0;
  max-width: 100%;
  overflow-x: hidden;
  overflow-y: hidden;
  container-type: inline-size;
}

.cal-week-day-column.is-today {
  background: transparent;
  border-left: 2px solid var(--info, #3b82f6);
  border-right: 2px solid var(--info, #3b82f6);
}

.cal-week-day-column.is-weekend {
  background: var(--slate-50, #f8fafc);
}

.cal-week-day-column.is-weekend.is-today {
  background: var(--slate-50, #f8fafc);
  border-left: 2px solid var(--info, #3b82f6);
  border-right: 2px solid var(--info, #3b82f6);
}

/* Day header in agenda view */
.cal-week-day-header-agenda {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8px 4px 6px;
  border-bottom: 1px solid var(--slate-200, #e2e8f0);
  cursor: pointer;
  transition: background 0.15s;
  position: relative;
  min-width: 0;
  overflow: hidden;
}

.cal-week-day-header-agenda:hover {
  background: var(--slate-50, #f8fafc);
}

/* V4.7: traffic-light band on weekly column headers — matches the monthly
   day-header strip tint so "how busy" reads the same in both views. Hover
   keeps precedence. */
.cal-week-day-header-agenda[data-day-signal="green"] {
  background: linear-gradient(180deg,
      color-mix(in srgb, var(--cal-day-green-solid, #16a34a) 14%, transparent) 0%,
      color-mix(in srgb, var(--cal-day-green-solid, #16a34a) 7%, transparent) 100%);
  border-bottom-color: color-mix(in srgb, var(--cal-day-green-solid, #16a34a) 25%, transparent);
}
.cal-week-day-header-agenda[data-day-signal="amber"] {
  background: linear-gradient(180deg,
      color-mix(in srgb, var(--cal-day-amber-solid, #ca8a04) 14%, transparent) 0%,
      color-mix(in srgb, var(--cal-day-amber-solid, #ca8a04) 7%, transparent) 100%);
  border-bottom-color: color-mix(in srgb, var(--cal-day-amber-solid, #ca8a04) 25%, transparent);
}
.cal-week-day-header-agenda[data-day-signal="red"] {
  background: linear-gradient(180deg,
      color-mix(in srgb, var(--cal-day-red-solid, #dc2626) 12%, transparent) 0%,
      color-mix(in srgb, var(--cal-day-red-solid, #dc2626) 6%, transparent) 100%);
  border-bottom-color: color-mix(in srgb, var(--cal-day-red-solid, #dc2626) 25%, transparent);
}
/* Today tint wins over signal band, same convention as monthly. */
.cal-week-day-column.is-today .cal-week-day-header-agenda {
  background: linear-gradient(180deg,
      rgba(20, 184, 166, 0.18) 0%,
      rgba(20, 184, 166, 0.10) 100%) !important;
  border-bottom-color: rgba(20, 184, 166, 0.35) !important;
}

.cal-week-day-header-agenda .day-name {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--slate-500, #64748b);
  margin-bottom: 2px;
}

.cal-week-day-header-agenda .day-num {
  font-size: 20px;
  font-weight: 700;
  color: var(--slate-800, #1e293b);
  line-height: 1.2;
}

.cal-week-day-header-agenda .day-num.today-badge {
  background: var(--info, #3b82f6);
  color: #ffffff;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cal-week-day-header-agenda .month-label {
  font-size: 9px;
  color: var(--slate-400, #94a3b8);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  margin-top: 2px;
}

.cal-week-day-header-agenda .event-count-badge {
  position: absolute;
  top: 6px;
  right: 6px;
  background: var(--slate-200, #e2e8f0);
  color: var(--slate-600, #475569);
  font-size: 9px;
  font-weight: 600;
  padding: 2px 5px;
  border-radius: 10px;
  min-width: 16px;
  text-align: center;
}

.is-today .event-count-badge {
  background: var(--info, #3b82f6);
  color: #ffffff;
}

/* Events list container */
.cal-week-events-list {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 4px 3px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  min-height: 0;
  max-width: 100%;
  box-sizing: border-box;
}

/* Empty day state */
.cal-week-empty-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 20px 8px;
  color: var(--slate-300, #cbd5e1);
  cursor: pointer;
  transition: all 0.15s;
  flex: 1;
}

.cal-week-empty-day:hover {
  color: var(--slate-400, #94a3b8);
  background: var(--slate-50, #f8fafc);
}

.cal-week-empty-day i {
  font-size: 18px;
}

.cal-week-empty-day span {
  font-size: 10px;
}

/* Event row in agenda - compact single-line with left color border */
.cal-week-event-row {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 4px;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.15s;
  background: var(--surface-secondary, #f8fafc);
  min-width: 0;
  overflow: hidden;
  max-width: 100%;
  box-sizing: border-box;
  border-left: 3px solid transparent;
}

/* 2026-07-06 (user: "week view shows a long list of times and no labels
   regarding event types … keep a consistent style ie blue and pink event
   blocks"). Fill each agenda row as a tinted BLOCK keyed on its event category
   so the week view reads like the month grid + timeline: work/meeting = BLUE,
   personal = PINK, time-off = green, availability = teal. The left border
   deepens the same hue for a crisp edge. data-category is stamped in
   calendar-week-view.js buildEventRow via the shared EventService classifier. */
.cal-week-event-row[data-category="work"],
.cal-week-event-row[data-category="shift"] {
  background: color-mix(in srgb, #3b82f6 14%, var(--surface-primary, #fff));
  border-left-color: #3b82f6;
}
.cal-week-event-row[data-category="meeting"] {
  background: color-mix(in srgb, #8b5cf6 14%, var(--surface-primary, #fff));
  border-left-color: #8b5cf6;
}
/* Personal is #f472b6 (--event-personal), NOT #ec4899 — that is the HOVER token
   (--event-personal-hover), so the base state was painted in the hover colour
   and the week row disagreed with every other surface. (2026-08-05) */
.cal-week-event-row[data-category="personal"] {
  background: color-mix(in srgb, #f472b6 15%, var(--surface-primary, #fff));
  border-left-color: #f472b6;
}
/* Time off is AMBER (--event-timeoff #f59e0b), not green. Green is
   availability's hue — see [data-category="availability"] directly below, which
   is still #22c55e. Painting leave green inverted its meaning on the one surface
   people scan to find open time: "I am away" rendered in the colour that means
   "free to book". event-chip.css:70 already had the amber; this sheet was the
   outlier. (2026-08-05) */
.cal-week-event-row[data-category="timeOff"],
.cal-week-event-row[data-category="timeoff"] {
  background: color-mix(in srgb, #f59e0b 14%, var(--surface-primary, #fff));
  border-left-color: #f59e0b;
}
.cal-week-event-row[data-category="availability"],
.cal-week-event-row[data-category="external"] {
  background: color-mix(in srgb, #14b8a6 14%, var(--surface-primary, #fff));
  border-left-color: #14b8a6;
}
/* CANONICAL BUSY (2026-08-04). A masked teammate block is one concept with one
   design across the whole app: neutral grey rgb(120,130,150) + the -45deg
   diagonal hatch. The hatch is what SAYS "busy/masked" rather than "some
   uncategorised grey event" — same reasoning, same angle and same stops as
   .timeline-event-marker.busy-block (style.css ~16173) and the compact chip
   (~7319), so the calendar family joins that one design instead of inventing a
   third grey. Before this, 'busy' matched NO rule here and the row rendered
   with the bare .cal-week-event-row surface while every sibling category got a
   tinted block. Kept subtle: this is an agenda row, not a timeline pill, so the
   hatch sits at a low alpha over the tint and the title stays readable. */
.cal-week-event-row[data-category="busy"] {
  background:
    repeating-linear-gradient(
      -45deg,
      rgba(120, 130, 150, 0.16) 0px,
      rgba(120, 130, 150, 0.16) 3px,
      rgba(148, 163, 184, 0.26) 3px,
      rgba(148, 163, 184, 0.26) 7px
    ),
    color-mix(in srgb, rgb(120, 130, 150) 13%, var(--surface-primary, #fff));
  border-left-color: rgb(120, 130, 150);
}
/* ⭐⭐⭐ CONFIRMATION STATE IN WEEK + AGENDA (2026-08-15, event-block
   vocabulary audit).

   Neither view carried the status channel at all, so a tentative event read as
   confirmed in both - part of the owner's report that proposed and tentative
   events "weren't showing dashed borders". They now speak the same vocabulary
   as the board: STRUCTURE (a dashed edge + the 135 degree stripe) carries the
   confirmation state, while the CATEGORY hue keeps saying what kind of event
   it is. Mixed from currentColor so no amber enters the event-block palette.

   The week row's category accent is a border-LEFT, so dashing the whole box
   would fight it; the accent edge itself goes dashed instead, which is the
   same channel reading the same way. */
.cal-week-event-row[data-status="tentative"],
.cal-week-event-row[data-status="proposed"] {
  border-left-style: dashed;
  background-image: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, currentColor 10%, transparent) 0px,
    color-mix(in srgb, currentColor 10%, transparent) 5px,
    transparent 5px,
    transparent 10px
  );
}

.cal-agenda-event[data-status="tentative"],
.cal-agenda-event[data-status="proposed"] {
  border: 1.5px dashed color-mix(in srgb, currentColor 38%, transparent);
  background-image: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, currentColor 10%, transparent) 0px,
    color-mix(in srgb, currentColor 10%, transparent) 5px,
    transparent 5px,
    transparent 10px
  );
}
/* The agenda's category hue lives in a leading colour bar, so dash that too:
   it is the element the eye reads as this row's event identity. */
.cal-agenda-event[data-status="tentative"] .cal-agenda-event-color,
.cal-agenda-event[data-status="proposed"] .cal-agenda-event-color {
  opacity: 0.55;
}

.cal-week-event-row[data-category="work"]:hover,
.cal-week-event-row[data-category="shift"]:hover {
  background: color-mix(in srgb, #3b82f6 22%, var(--surface-primary, #fff));
}
.cal-week-event-row[data-category="meeting"]:hover {
  background: color-mix(in srgb, #8b5cf6 22%, var(--surface-primary, #fff));
}
.cal-week-event-row[data-category="personal"]:hover {
  background: color-mix(in srgb, #ec4899 24%, var(--surface-primary, #fff));
}
/* Amber, matching the corrected base above. #ec4899 on the personal:hover rule
   directly above is CORRECT — that is --event-personal-hover doing its job. */
.cal-week-event-row[data-category="timeOff"]:hover,
.cal-week-event-row[data-category="timeoff"]:hover {
  background: color-mix(in srgb, #d97706 22%, var(--surface-primary, #fff));
}
.cal-week-event-row[data-category="availability"]:hover,
.cal-week-event-row[data-category="external"]:hover {
  background: color-mix(in srgb, #14b8a6 22%, var(--surface-primary, #fff));
}
/* Hover must restate the hatch: `background` is a shorthand, so a hover rule
   that set only a colour would DROP the gradient layer and the row would lose
   its busy identity on mouseover. */
.cal-week-event-row[data-category="busy"]:hover {
  background:
    repeating-linear-gradient(
      -45deg,
      rgba(120, 130, 150, 0.22) 0px,
      rgba(120, 130, 150, 0.22) 3px,
      rgba(148, 163, 184, 0.34) 3px,
      rgba(148, 163, 184, 0.34) 7px
    ),
    color-mix(in srgb, rgb(120, 130, 150) 20%, var(--surface-primary, #fff));
}
body.dark-mode .cal-week-event-row[data-category="work"],
body.dark-mode .cal-week-event-row[data-category="shift"] {
  background: color-mix(in srgb, #3b82f6 26%, var(--surface-primary, #1e293b));
}
body.dark-mode .cal-week-event-row[data-category="meeting"] {
  background: color-mix(in srgb, #8b5cf6 26%, var(--surface-primary, #1e293b));
}
body.dark-mode .cal-week-event-row[data-category="personal"] {
  background: color-mix(in srgb, #f472b6 26%, var(--surface-primary, #1e293b));
}
body.dark-mode .cal-week-event-row[data-category="timeOff"],
body.dark-mode .cal-week-event-row[data-category="timeoff"] {
  background: color-mix(in srgb, #f59e0b 24%, var(--surface-primary, #1e293b));
}
body.dark-mode .cal-week-event-row[data-category="availability"],
body.dark-mode .cal-week-event-row[data-category="external"] {
  background: color-mix(in srgb, #14b8a6 24%, var(--surface-primary, #1e293b));
}
/* ⚠️DARK BUSY IS MANDATORY, NOT OPTIONAL. A missing dark variant does not fall
   back to a neutral grey — it paints the LIGHT hatch, which is mixed for a light
   surface and reads washed-out and too pale on a dark board. That is the exact
   defect the compact chip shipped with (style.css ~7397). Slate stops copied
   verbatim from the canonical dark rules (style.css ~16251 / ~7410) so all
   surfaces stay ONE design in BOTH themes. */
body.dark-mode .cal-week-event-row[data-category="busy"] {
  background:
    repeating-linear-gradient(
      -45deg,
      rgba(51, 65, 85, 0.5) 0px,
      rgba(51, 65, 85, 0.5) 3px,
      rgba(71, 85, 105, 0.6) 3px,
      rgba(71, 85, 105, 0.6) 7px
    ),
    color-mix(in srgb, rgb(71, 85, 105) 30%, var(--surface-primary, #1e293b));
  border-left-color: rgb(100, 116, 139);
}
body.dark-mode .cal-week-event-row[data-category="busy"]:hover {
  background:
    repeating-linear-gradient(
      -45deg,
      rgba(51, 65, 85, 0.6) 0px,
      rgba(51, 65, 85, 0.6) 3px,
      rgba(71, 85, 105, 0.72) 3px,
      rgba(71, 85, 105, 0.72) 7px
    ),
    color-mix(in srgb, rgb(71, 85, 105) 40%, var(--surface-primary, #1e293b));
}

/* Event-type label — a compact word under the title naming the KIND of event.
   Muted so the title still leads; the block colour carries the category, this
   spells it out. */
.cal-week-event-row .event-type-label {
  display: block;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--slate-500, #64748b);
  line-height: 1.2;
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.dark-mode .cal-week-event-row .event-type-label {
  color: var(--slate-400, #94a3b8);
}

/* Narrow columns: stack time above title so the title gets the full row
   width and ellipses past 6-8 chars instead of 2. Kicks in when the day
   column is too tight to fit "8:00 AM " and a meaningful title side-by-side.
   This is per-column container queries, not viewport — desktop with 7
   columns at 1440px is still cramped. */
@container (max-width: 140px) {
  .cal-week-event-row {
    flex-direction: column;
    align-items: stretch;
    gap: 1px;
    padding: 4px 6px;
  }
  .cal-week-event-row .event-time {
    font-size: 9px;
    opacity: 0.85;
  }
  .cal-week-event-row .event-vis-icon {
    display: none; /* re-surface on hover via tooltip; saves 14 px */
  }
}

.cal-week-event-row:hover {
  background: var(--slate-100, #f1f5f9);
}

/* Color bar hidden - replaced by left border on row */
.cal-week-event-row .event-color-bar {
  display: none;
}

/* Event time */
.cal-week-event-row .event-time {
  font-size: 10px;
  font-weight: 600;
  color: var(--slate-500, #64748b);
  white-space: nowrap;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}

/* Compact visibility icon (replaces the old coloured dot which was read
   as an online/offline status). Colour travels with the icon. */
.event-vis-icon {
  font-size: 10px;
  flex-shrink: 0;
  align-self: center;
  line-height: 1;
  width: 12px;
  text-align: center;
}

.event-vis-icon.vis-full {
  color: var(--visibility-shared, #059669);
}

.event-vis-icon.vis-busy {
  color: var(--visibility-blocked, #d97706);
}

.event-vis-icon.vis-hidden {
  color: var(--visibility-private, #8b5cf6);
}

.cal-week-event-row .event-time .all-day-label {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  background: var(--slate-200, #e2e8f0);
  padding: 2px 5px;
  border-radius: 3px;
  font-weight: 600;
}

/* Event content - single line, truncates */
.cal-week-event-row .event-content {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.cal-week-event-row .event-title {
  font-size: 11px;
  font-weight: 500;
  color: var(--slate-800, #1e293b);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* "+N more" button at bottom of day column */
.cal-week-more-btn {
  font-size: 10px;
  font-weight: 700;
  color: var(--primary-600, #0d9488);
  background: rgba(20, 184, 166, 0.1);
  padding: 4px 6px;
  border-radius: 4px;
  text-align: center;
  cursor: pointer;
  transition: background 0.15s;
}

.cal-week-more-btn:hover {
  background: rgba(20, 184, 166, 0.2);
  color: var(--primary-700, #0f766e);
}

/* (old visibility icon rules removed - replaced by .event-vis-dot) */

/* Dark mode - Agenda View */
body.dark-mode .cal-week-agenda-view {
  background: var(--surface-primary, #0f172a);
}

body.dark-mode .cal-week-agenda-wrapper {
  background: var(--slate-700, #334155);
}

body.dark-mode .cal-week-day-column {
  background: var(--surface-primary, #0f172a);
}

body.dark-mode .cal-week-day-column.is-today {
  background: transparent;
  border-left: 2px solid rgba(59, 130, 246, 0.5);
  border-right: 2px solid rgba(59, 130, 246, 0.5);
}

body.dark-mode .cal-week-day-column.is-weekend {
  background: var(--slate-900, #0f172a);
}

body.dark-mode .cal-week-day-header-agenda {
  border-bottom-color: var(--slate-700, #334155);
}

body.dark-mode .cal-week-day-header-agenda:hover {
  background: var(--slate-800, #1e293b);
}

body.dark-mode .cal-week-day-header-agenda .day-name {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .cal-week-day-header-agenda .day-num {
  color: var(--slate-100, #f1f5f9);
}

body.dark-mode .cal-week-day-header-agenda .event-count-badge {
  background: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}

body.dark-mode .is-today .event-count-badge {
  background: var(--info, #3b82f6);
  color: #ffffff;
}

body.dark-mode .cal-week-empty-day {
  color: var(--slate-600, #475569);
}

body.dark-mode .cal-week-empty-day:hover {
  color: var(--slate-500, #64748b);
  background: var(--slate-800, #1e293b);
}

body.dark-mode .cal-week-event-row {
  background: var(--slate-800, #1e293b);
}

body.dark-mode .cal-week-event-row:hover {
  background: var(--slate-700, #334155);
}

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

body.dark-mode .cal-week-event-row .event-time .all-day-label {
  background: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}

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

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

/* Responsive - Agenda View */
@media (max-width: 768px) {
  .cal-week-agenda-wrapper {
    grid-template-columns: repeat(7, minmax(80px, 1fr));
    overflow-x: auto;
  }

  .cal-week-day-header-agenda {
    padding: 8px 4px;
  }

  .cal-week-day-header-agenda .day-num {
    font-size: 16px;
  }

  .cal-week-day-header-agenda .day-num.today-badge {
    width: 26px;
    height: 26px;
  }

  .cal-week-event-row {
    padding: 6px;
    gap: 4px;
  }

  .cal-week-event-row .event-time {
    min-width: 45px;
    font-size: 10px;
  }

  .cal-week-event-row .event-title {
    font-size: 11px;
  }
}

/* ============================================
   OLD WEEK VIEW (GRID STYLE) - KEPT FOR REFERENCE
   ============================================ */

.cal-week-view {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.cal-week-header {
  display: grid;
  grid-template-columns: 50px repeat(7, 1fr);
  border-bottom: 1px solid var(--border-color, #e2e8f0);
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface-primary, #ffffff);
}

.cal-week-gutter-header {
  border-right: 1px solid var(--border-color, #e2e8f0);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 2px;
}

.cal-week-day-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6px 4px;
  border-right: 1px solid var(--border-color, #e2e8f0);
}

.cal-week-day-header.cal-week-today {
  background: var(--accent-bg, #eff6ff);
}

.cal-week-day-name {
  font-size: 10px;
  color: var(--text-tertiary, #94a3b8);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.cal-week-day-num {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary, #1e293b);
}

.cal-week-today .cal-week-day-num {
  color: var(--accent, #3b82f6);
  background: var(--accent, #3b82f6);
  color: #ffffff;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cal-week-grid {
  display: grid;
  grid-template-columns: 50px repeat(7, 1fr);
  overflow-y: auto;
  flex: 1;
  position: relative;
}

/* All-day events strip */
.cal-week-allday-strip {
  display: grid;
  grid-template-columns: 50px repeat(7, 1fr);
  border-bottom: 2px solid var(--border-color, #e2e8f0);
  min-height: 28px;
  max-height: 80px;
  overflow: hidden;
  background: var(--surface-primary, #ffffff);
}

.cal-week-allday-gutter {
  font-size: 9px;
  color: var(--text-tertiary, #94a3b8);
  padding: 4px;
  border-right: 1px solid var(--border-color, #e2e8f0);
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}

.cal-week-allday-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 2px;
  border-right: 1px solid var(--border-color, #e2e8f0);
  min-height: 24px;
  align-content: flex-start;
  cursor: pointer;
  transition: background 0.1s;
}

.cal-week-allday-cell:hover {
  background: var(--accent-bg, #eff6ff);
}

.cal-week-allday-cell.cal-week-today-col {
  background: rgba(59, 130, 246, 0.03);
}

.cal-week-allday-chip {
  font-size: 9px;
  font-weight: 500;
  color: #ffffff;
  padding: 2px 6px;
  border-radius: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  cursor: pointer;
  transition: opacity 0.15s, box-shadow 0.15s;
}

.cal-week-allday-chip:hover {
  opacity: 0.9;
  box-shadow: 0 1px 4px rgba(0,0,0,0.15);
}

.cal-week-gutter {
  grid-column: 1;
  border-right: 1px solid var(--border-color, #e2e8f0);
  padding: 2px 4px;
  font-size: 10px;
  color: var(--text-tertiary, #94a3b8);
  text-align: right;
  height: 48px;
  box-sizing: border-box;
}

.cal-week-cell {
  border-right: 1px solid var(--border-color, #e2e8f0);
  border-bottom: 1px solid var(--border-color, #f1f5f9);
  height: 48px;
  box-sizing: border-box;
  cursor: pointer;
  transition: background 0.1s;
}

.cal-week-cell:hover {
  background: var(--accent-bg, #eff6ff);
}

.cal-week-cell.cal-week-today-col {
  background: rgba(59, 130, 246, 0.03);
}

/* Event blocks */
.cal-week-event {
  position: absolute;
  border-radius: 4px;
  padding: 2px 4px;
  font-size: 10px;
  color: #ffffff;
  cursor: pointer;
  overflow: hidden;
  z-index: 1;
  transition: box-shadow 0.15s;
  opacity: 0.9;
}

.cal-week-event:hover {
  opacity: 1;
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
  z-index: 2;
}

.cal-week-event.cal-week-dragging {
  opacity: 0.5;
}

.cal-week-event-time {
  font-weight: 600;
  font-size: 9px;
  display: block;
  white-space: nowrap;
}

.cal-week-event-title {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-week-event-dot {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

/* Shared/Friend calendar events */
.cal-week-event.shared-event {
  opacity: 0.75;
  border-style: dashed;
  border-width: 1px;
}

.cal-week-event.shared-event:hover {
  opacity: 0.9;
}

/* ⭐2026-08-04: hatched at +45deg (the MIRROR of the canonical -45deg) with a
   generic black wash rather than the busy slate — a third busy look. No JS
   emits `.shared-event.busy-only`, so this is currently unreachable, but it is
   left in place and corrected rather than deleted so that if the class is ever
   wired up it joins the one busy design instead of reintroducing the
   divergence. Angle and stops now match .timeline-event-marker.busy-block. */
.cal-week-event.shared-event.busy-only {
  background: repeating-linear-gradient(
    -45deg,
    rgba(120, 130, 150, 0.45) 0px,
    rgba(120, 130, 150, 0.45) 3px,
    rgba(148, 163, 184, 0.7) 3px,
    rgba(148, 163, 184, 0.7) 7px
  );
}

.shared-event-badge {
  position: absolute;
  bottom: 2px;
  right: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--surface-primary, #ffffff);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  font-weight: 700;
  color: var(--text-primary, #1e293b);
  border: 1px solid rgba(0,0,0,0.1);
  text-transform: uppercase;
}

/* Current time indicator — pink core + white ring, matching the main-board cell
   needle (.timeline-comparison-bar) and scanner tick (.scanner-now-tick) so "now"
   reads with one consistent colour across every surface (2026-07-14 needle work,
   extended to the week/month calendar 2026-07-16 at user request). Was red #ef4444,
   which collided with the red-tinted event blocks it crosses; the pink core sits
   outside the red/green/amber palette and the white ring detaches it from whatever
   event block it overlaps. */
/* ⭐ 2026-08-16: ring raised 0.75px -> 1.5px at full opacity, in lockstep with
   .timeline-comparison-bar. Event rows in this view now carry their own white
   edges (thin solid = confirmed, thin dashed = tentative), so the needle must
   be the boldest white mark here for exactly the same reason it must be on the
   board. The two needles are one design and must not drift. */
.cal-week-now-line {
  position: absolute;
  height: 2px;
  background: #ec4899;
  box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 1);
  z-index: 3;
  pointer-events: none;
}

.cal-week-now-line::before {
  content: '';
  position: absolute;
  left: -4px;
  top: -3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ec4899;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.9);
}

/* ============================================
   AGENDA VIEW
   ============================================ */

.cal-agenda-view {
  padding: 8px 0;
  overflow-y: auto;
  max-height: 400px;
}

.cal-agenda-empty {
  text-align: center;
  padding: 32px 16px;
  color: var(--text-tertiary, #94a3b8);
}

.cal-agenda-empty i {
  font-size: 28px;
  margin-bottom: 8px;
  display: block;
}

.cal-agenda-empty p {
  margin: 0 0 16px;
}

/* Empty state sync prompt */
.cal-agenda-empty .empty-sync-prompt {
  margin-top: 16px;
  padding: 16px;
  background: linear-gradient(135deg, rgba(13, 148, 136, 0.06), rgba(8, 145, 178, 0.06));
  border: 1px solid rgba(13, 148, 136, 0.12);
  border-radius: 10px;
}

.cal-agenda-empty .empty-sync-prompt p {
  font-size: 13px;
  color: var(--text-secondary, #64748b);
  margin: 0 0 12px;
}

.cal-agenda-empty .sync-buttons {
  display: flex;
  gap: 8px;
  justify-content: center;
}

/* Agenda empty-state buttons now use shared `.sync-action sync-action--provider-*`
   token defined further down in this file. The legacy `.sync-btn` rules
   lived here. */

body.dark-mode .cal-agenda-empty .empty-sync-prompt {
  background: linear-gradient(135deg, rgba(45, 212, 191, 0.08), rgba(34, 211, 238, 0.08));
  border-color: rgba(45, 212, 191, 0.15);
}

body.dark-mode .cal-agenda-empty .empty-sync-prompt p {
  color: var(--text-secondary, #94a3b8);
}

.cal-agenda-day {
  margin-bottom: 12px;
}

.cal-agenda-day-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 12px;
  background: var(--surface-secondary, #f8fafc);
  border-radius: 6px;
  margin-bottom: 4px;
  position: sticky;
  top: 0;
  z-index: 2;
}

.cal-agenda-day-header.cal-agenda-today {
  background: var(--accent-bg, #eff6ff);
  border: 1px solid var(--accent, #3b82f6);
}

.cal-agenda-day-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary, #1e293b);
}

.cal-agenda-day-count {
  font-size: 10px;
  color: var(--text-tertiary, #94a3b8);
}

.cal-agenda-event-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 4px;
}

.cal-agenda-event {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s;
}

.cal-agenda-event:hover {
  background: var(--surface-secondary, #f8fafc);
}

.cal-agenda-event-color {
  width: 4px;
  height: 32px;
  border-radius: 2px;
  flex-shrink: 0;
}

.cal-agenda-event-time {
  display: flex;
  flex-direction: column;
  min-width: 60px;
}

.cal-agenda-time-start {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary, #1e293b);
  font-variant-numeric: tabular-nums;
}

.cal-agenda-duration {
  font-size: 10px;
  color: var(--text-tertiary, #94a3b8);
}

.cal-agenda-event-body {
  flex: 1;
  min-width: 0;
}

.cal-agenda-event-title {
  font-size: 13px;
  color: var(--text-primary, #1e293b);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-agenda-event-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 2px;
}

.cal-agenda-fairness {
  font-size: 10px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.cal-agenda-fairness > i {
  font-size: 6px;
}

/* Neutral state when fairness can't be computed — slate dot, no label */
.cal-agenda-fairness[data-level="unknown"] {
  color: var(--text-tertiary, #94a3b8);
}

/* When no event in the visible range has fairness data (demo mode,
   Personal-only calendars), hide the placeholders entirely so the agenda
   doesn't read as a wall of "—" dashes. The container class is toggled by
   js/ui/calendar-agenda-view.js render(). */
.cal-agenda-view:not(.has-fairness-data) .cal-agenda-fairness[data-level="unknown"] {
  display: none;
}

.cal-agenda-attendees {
  font-size: 10px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--text-tertiary, #94a3b8);
}

.cal-agenda-attendees > i {
  font-size: 9px;
}

/* "Show N more" pagination toggle. Lives at the foot of a day section once
   the day has more than EVENTS_PER_DAY_INITIAL events; clicking expands the
   rest inline (no second render pass). */
.cal-agenda-show-more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 4px 10px 0;
  padding: 6px 10px;
  background: transparent;
  border: 1px dashed var(--border-color, #e2e8f0);
  border-radius: 6px;
  color: var(--text-secondary, #64748b);
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
  align-self: flex-start;
}

.cal-agenda-show-more:hover {
  background: var(--surface-secondary, #f8fafc);
  border-color: var(--primary-300, #5eead4);
  color: var(--primary-600, #0d9488);
}

.cal-agenda-show-more > i {
  font-size: 9px;
}

body.dark-mode .cal-agenda-show-more {
  border-color: var(--slate-700, #334155);
  color: var(--slate-400, #94a3b8);
}
body.dark-mode .cal-agenda-show-more:hover {
  background: var(--slate-800, #1e293b);
  border-color: var(--primary-500, #14b8a6);
  color: var(--primary-300, #5eead4);
}

.cal-agenda-join-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border-radius: 4px;
  background: var(--accent, #3b82f6);
  color: #ffffff;
  font-size: 10px;
  text-decoration: none;
  flex-shrink: 0;
  transition: background 0.15s;
}

.cal-agenda-join-btn:hover {
  background: #2563eb;
}

/* ============================================
   DARK MODE - WEEK VIEW
   ============================================ */

body.dark-mode .cal-view-switcher {
  background: var(--surface-secondary, #1e293b);
}

body.dark-mode .cal-view-btn {
  color: var(--text-secondary, #94a3b8);
}

body.dark-mode .cal-view-btn.active {
  background: var(--surface-primary, #0f172a);
  color: var(--text-primary, #f1f5f9);
}

body.dark-mode .cal-week-header {
  background: var(--surface-primary, #0f172a);
  border-bottom-color: var(--border-color, #334155);
}

body.dark-mode .cal-week-gutter-header,
body.dark-mode .cal-week-gutter {
  border-right-color: var(--border-color, #334155);
}

body.dark-mode .cal-week-day-header {
  border-right-color: var(--border-color, #334155);
}

body.dark-mode .cal-week-day-num {
  color: var(--text-primary, #f1f5f9);
}

body.dark-mode .cal-week-cell {
  border-right-color: var(--border-color, #334155);
  border-bottom-color: var(--border-color, #1e293b);
}

body.dark-mode .cal-week-cell:hover {
  background: rgba(59, 130, 246, 0.08);
}

/* Dark mode all-day strip */
body.dark-mode .cal-week-allday-strip {
  background: var(--surface-primary, #0f172a);
  border-bottom-color: var(--border-color, #334155);
}

body.dark-mode .cal-week-allday-gutter {
  border-right-color: var(--border-color, #334155);
}

body.dark-mode .cal-week-allday-cell {
  border-right-color: var(--border-color, #334155);
}

body.dark-mode .cal-week-allday-cell:hover {
  background: rgba(59, 130, 246, 0.08);
}

/* ============================================
   DARK MODE - AGENDA VIEW
   ============================================ */

body.dark-mode .cal-agenda-empty {
  color: var(--text-tertiary, #64748b);
}

body.dark-mode .cal-agenda-day-header {
  background: var(--surface-secondary, #1e293b);
}

body.dark-mode .cal-agenda-day-header.cal-agenda-today {
  background: rgba(59, 130, 246, 0.1);
  border-color: var(--accent, #3b82f6);
}

body.dark-mode .cal-agenda-day-label {
  color: var(--text-primary, #f1f5f9);
}

body.dark-mode .cal-agenda-event:hover {
  background: var(--surface-secondary, #1e293b);
}

body.dark-mode .cal-agenda-time-start {
  color: var(--text-primary, #f1f5f9);
}

body.dark-mode .cal-agenda-event-title {
  color: var(--text-primary, #f1f5f9);
}

/* ============================================
   TEAM AVAILABILITY OVERLAY
   ============================================ */

.team-availability-overlay {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px;
  background: var(--surface-secondary, #f8fafc);
  border-radius: 8px;
  margin: 8px;
  border: 1px solid var(--border-color, #e2e8f0);
}

.team-overlay-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px;
  color: var(--text-tertiary, #94a3b8);
  font-size: 12px;
}

.team-overlay-empty i {
  font-size: 16px;
}

.team-member-lane {
  display: grid;
  grid-template-columns: 80px repeat(7, 1fr);
  gap: 2px;
  align-items: center;
}

.team-member-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-secondary, #64748b);
  padding: 4px;
  overflow: hidden;
}

.team-member-label .member-color {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.team-member-label .member-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.team-day-cell {
  display: flex;
  gap: 1px;
  height: 20px;
}

.team-hour-block {
  flex: 1;
  border-radius: 2px;
  min-width: 4px;
  transition: opacity 0.15s;
}

.team-hour-block.status-available {
  background: var(--status-available, #22c55e);
}

/* BUSY IS SLATE (2026-08-16, user: "unusually large sections ie red"). This
   hardcoded #ef4444 bypassed the token entirely, so every busy hour painted a
   solid red bar across the week lane — read as an error state when it only
   means "booked". Red is reserved for conflicts and danger. */
.team-hour-block.status-busy {
  background: var(--status-busy, #64748b);
}

.team-hour-block.status-unknown {
  background: #94a3b8;
  opacity: 0.3;
}

.team-hour-block:hover {
  opacity: 0.8;
}

/* Heatmap row */
.team-heatmap-row {
  display: grid;
  grid-template-columns: 80px repeat(7, 1fr);
  gap: 2px;
  align-items: center;
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px solid var(--border-color, #e2e8f0);
}

.team-heatmap-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-primary, #1e293b);
  padding: 4px;
}

.team-heatmap-label i {
  color: var(--accent, #3b82f6);
}

.team-heatmap-day {
  display: flex;
  gap: 1px;
  height: 24px;
}

.team-heatmap-hour {
  flex: 1;
  border-radius: 2px;
  min-width: 4px;
  transition: transform 0.15s;
}

.team-heatmap-hour:hover {
  transform: scaleY(1.2);
}

/* Week Privacy Button - matching main calendar privacy indicator */
.week-privacy-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 8px);
  background: transparent;
  color: #22c55e; /* Default: green for "all" */
  cursor: pointer;
  transition: all 0.15s ease;
}

.week-privacy-btn:hover {
  background: rgba(0, 0, 0, 0.05);
}

.week-privacy-btn i {
  font-size: 14px;
}

/* Privacy button states - Purple-Amber-Green scale */
.week-privacy-btn[data-mode="private"],
.week-privacy-btn[data-mode="hidden"] {
  color: #8b5cf6; /* Purple */
}

.week-privacy-btn[data-mode="busy"],
.week-privacy-btn[data-mode="busy-only"] {
  color: #f59e0b; /* Amber */
}

.week-privacy-btn[data-mode="full"],
.week-privacy-btn[data-mode="shared"],
.week-privacy-btn[data-mode="all"] {
  color: #22c55e; /* Green */
}

.week-privacy-btn.has-override {
  background: rgba(0, 0, 0, 0.03);
  box-shadow: 0 0 0 2px currentColor;
}

body.dark-mode .week-privacy-btn:hover {
  background: rgba(255, 255, 255, 0.08);
}

body.dark-mode .week-privacy-btn.has-override {
  background: rgba(255, 255, 255, 0.05);
}

/* Toggle button */
.team-overlay-toggle {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border: 1px solid var(--border-color, #e2e8f0);
  border-radius: 4px;
  background: var(--surface-primary, #ffffff);
  color: var(--text-secondary, #64748b);
  font-size: 10px;
  cursor: pointer;
  transition: all 0.15s;
}

.team-overlay-toggle:hover {
  background: var(--accent-bg, #eff6ff);
  border-color: var(--accent, #3b82f6);
  color: var(--accent, #3b82f6);
}

.team-overlay-toggle.active {
  background: var(--accent, #3b82f6);
  border-color: var(--accent, #3b82f6);
  color: #ffffff;
}

.team-overlay-toggle i {
  font-size: 12px;
}

/* Dark mode */
body.dark-mode .team-availability-overlay {
  background: var(--surface-secondary, #1e293b);
  border-color: var(--border-color, #334155);
}

body.dark-mode .team-member-label {
  color: var(--text-secondary, #94a3b8);
}

body.dark-mode .team-heatmap-label {
  color: var(--text-primary, #f1f5f9);
}

body.dark-mode .team-heatmap-row {
  border-top-color: var(--border-color, #334155);
}

body.dark-mode .team-overlay-toggle {
  background: var(--surface-primary, #0f172a);
  border-color: var(--border-color, #334155);
}

body.dark-mode .team-overlay-toggle:hover {
  background: rgba(59, 130, 246, 0.1);
}

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

@media (max-width: 768px) {
  .cal-week-day-name { font-size: 9px; }
  .cal-week-day-num { font-size: 13px; }
  .cal-week-gutter { font-size: 9px; padding: 2px 2px; }
  .cal-week-header { grid-template-columns: 35px repeat(7, 1fr); }
  .cal-week-grid { grid-template-columns: 35px repeat(7, 1fr); }
}

/* ============================================
   SHARED SYNC-ACTION BUTTONS
   ============================================
   One vocabulary for every Sync/Connect button site-wide. Replaces the
   five-way split that previously had `.rdh-sync-btn` (Review Center) /
   `.sync-nudge-btn` (banner nudge) / `.sync-btn-google` (Agenda empty
   state) / `.btn btn-primary btn-sm` + `.btn btn-secondary btn-sm`
   (Settings → Integrations) each shipping their own paint job.

   Default treatment is a teal pill that derives from --primary-* so it
   stays in sync with the rest of the app's calls-to-action. Two
   modifiers:
     .sync-action--icon       — 28×28 round, label-less (Review Center)
     .sync-action--provider-* — provider-coloured Connect buttons
                                (Google blue, Microsoft blue, Apple slate)
   ============================================ */
.sync-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 12px;
  height: 28px;
  border-radius: var(--radius-full, 9999px);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  background: color-mix(in srgb, var(--primary-500, #14b8a6) 10%, transparent);
  color: var(--primary-600, #0d9488);
  border: 1px solid color-mix(in srgb, var(--primary-500, #14b8a6) 22%, transparent);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease,
              color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
  white-space: nowrap;
  text-decoration: none;
}

.sync-action:hover {
  background: color-mix(in srgb, var(--primary-500, #14b8a6) 18%, transparent);
  border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 35%, transparent);
  transform: translateY(-1px);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--primary-500, #14b8a6) 14%, transparent);
}

.sync-action:focus-visible {
  outline: 2px solid var(--focus-ring, #2dd4bf);
  outline-offset: 2px;
}

.sync-action:active {
  transform: translateY(0);
}

.sync-action[disabled],
.sync-action[aria-busy="true"] {
  opacity: 0.65;
  cursor: progress;
  pointer-events: none;
}

.sync-action[aria-busy="true"] i {
  animation: fa-spin 1s linear infinite;
}

.sync-action i {
  font-size: 11px;
  flex-shrink: 0;
}

/* Icon-only variant (Review Center header, banner status pill) */
.sync-action--icon {
  width: 28px;
  padding: 0;
  gap: 0;
}
.sync-action--icon i { font-size: 12px; }

/* Provider Connect buttons — keep brand color identity for the first-time
   connect step so the user recognises the destination, then revert to the
   neutral teal `.sync-action` once connected (the .sync-action--provider-*
   modifier is removed when Settings flips Connect→Sync). */
.sync-action--provider-google {
  /* Solid brand fill for the first-time Connect CTA — a 10% tint over the
     white card read as a washed-out/gray pill. This modifier is removed when
     Settings flips Connect→Sync, so the post-connect Sync button reverts to
     the calmer neutral teal `.sync-action`. */
  background: #1a73e8;
  color: #fff;
  border-color: #1a73e8;
}
.sync-action--provider-google:hover {
  background: #1669d6;
  border-color: #1669d6;
  box-shadow: 0 2px 8px color-mix(in srgb, #4285f4 32%, transparent);
}

.sync-action--provider-microsoft {
  background: #0067b8;
  color: #fff;
  border-color: #0067b8;
}
.sync-action--provider-microsoft:hover {
  background: #005ba1;
  border-color: #005ba1;
  box-shadow: 0 2px 8px color-mix(in srgb, #0078d4 32%, transparent);
}

.sync-action--provider-apple {
  background: color-mix(in srgb, #1d1d1f 8%, transparent);
  color: #1d1d1f;
  border-color: color-mix(in srgb, #1d1d1f 22%, transparent);
}
.sync-action--provider-apple:hover {
  background: color-mix(in srgb, #1d1d1f 14%, transparent);
  border-color: color-mix(in srgb, #1d1d1f 35%, transparent);
}

/* Unconfigured-provider state: visible, disabled, clearly "not yet". Replaces
   the old display:none gating so the card keeps its button row instead of
   collapsing to icon+text (which read as undeveloped). Overrides the washed
   `.sync-action[disabled]` look with an intentional neutral disabled pill. */
.sync-action--coming-soon,
.sync-action--coming-soon:hover {
  background: var(--surface-2, #f1f5f9);
  color: var(--text-tertiary, #94a3b8);
  border-color: var(--border-color, #cbd5e1);
  cursor: default;
  transform: none;
  box-shadow: none;
  opacity: 1;
}

/* Destructive variant — Disconnect buttons. Same pill shape as the other
   sync actions so they line up, red hue to keep the destructive signal. */
.sync-action--danger {
  background: color-mix(in srgb, #dc2626 8%, transparent);
  color: #b91c1c;
  border-color: color-mix(in srgb, #dc2626 22%, transparent);
}
.sync-action--danger:hover {
  background: color-mix(in srgb, #dc2626 16%, transparent);
  border-color: color-mix(in srgb, #dc2626 40%, transparent);
  box-shadow: 0 2px 6px color-mix(in srgb, #dc2626 16%, transparent);
}
/* Dark-mode override for .sync-action--danger lives further down so it wins
   over the generic `body.dark-mode .sync-action` rule (same specificity —
   source order decides). */

/* Compact density — used inside cramped contexts like the calendar nudge. */
.sync-action--sm {
  height: 24px;
  padding: 4px 10px;
  font-size: 11px;
}

/* Dark mode */
body.dark-mode .sync-action {
  background: color-mix(in srgb, var(--primary-500, #14b8a6) 16%, transparent);
  color: var(--primary-300, #5eead4);
  border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 32%, transparent);
}
body.dark-mode .sync-action:hover {
  background: color-mix(in srgb, var(--primary-500, #14b8a6) 28%, transparent);
  border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 50%, transparent);
}
body.dark-mode .sync-action--provider-google {
  background: color-mix(in srgb, #4285f4 18%, transparent);
  color: #8ab4f8;
  border-color: color-mix(in srgb, #4285f4 40%, transparent);
}
body.dark-mode .sync-action--provider-microsoft {
  background: color-mix(in srgb, #0078d4 18%, transparent);
  color: #6bb6ff;
  border-color: color-mix(in srgb, #0078d4 40%, transparent);
}
body.dark-mode .sync-action--provider-apple {
  background: color-mix(in srgb, #f5f5f7 12%, transparent);
  color: #f5f5f7;
  border-color: color-mix(in srgb, #f5f5f7 30%, transparent);
}
body.dark-mode .sync-action--danger {
  background: color-mix(in srgb, #dc2626 18%, transparent);
  color: #fca5a5;
  border-color: color-mix(in srgb, #dc2626 40%, transparent);
}
body.dark-mode .sync-action--danger:hover {
  background: color-mix(in srgb, #dc2626 28%, transparent);
  border-color: color-mix(in srgb, #dc2626 55%, transparent);
}

/* ============================================================
   CELL-STYLE EVENT BLOCKS (user 2026-07-04: "cell style event
   blocks" + "keep this look, apply everywhere")
   Make each month-cell event chip read as a distinct stacked
   BLOCK on every viewport: full-width, its own soft frame, a
   little vertical breathing room.

   2026-07-10 (user: "calendar colours should represent my
   canonical colours … bad event visibility on mobile"): the block
   now paints itself from the ONE canonical category colour the
   EventChip renderer already sets on the chip — `--event-chip-accent`
   (Work=blue #3b82f6, Personal=pink, External=teal, Time off=amber,
   Meeting=purple, Task=indigo; see css/event-chip.css). We derive a
   STRONGER tint fill (~22%), a bold 3px canonical colour bar, and
   canonical-tinted title/time text via color-mix off that single
   accent — so there is no second colour list to drift out of sync,
   and a faint 10% wash no longer disappears on a phone cell.
   The .work/.personal gradient legacy fallback (style.css ~37035) is
   unaffected — those chips only render if EventChip fails to load.
   ============================================================ */
#calendar-days .event-chip-mini,
.calendar-days .event-chip-mini {
  width: 100%;
  box-sizing: border-box;
  /* Border + fill both keyed to the canonical accent so the block reads as
     its category colour, not a neutral grey box. Fallback to the old slate
     frame for any chip that somehow lacks an accent (defensive). */
  border: 1px solid color-mix(in srgb, var(--event-chip-accent, var(--slate-400, #94a3b8)) 38%, transparent);
  border-radius: 5px;
  box-shadow: var(--shadow-xs);
}
/* Stronger canonical tint fill — only for real EventChip blocks that carry an
   accent (guards the fallback chips + availability's dashed-green treatment). */
#calendar-days .event-chip.event-chip-mini[data-category],
.calendar-days .event-chip.event-chip-mini[data-category] {
  background: color-mix(in srgb, var(--event-chip-accent) 22%, var(--surface-primary, #ffffff));
}
/* Bolder left colour bar (3px, fully saturated accent) so the category reads
   even at a glance on a dense month sheet. */
#calendar-days .event-chip.event-chip-mini .event-chip-bar,
.calendar-days .event-chip.event-chip-mini .event-chip-bar {
  width: 3px;
  background: var(--event-chip-accent);
}
/* Title + time pick up a dark, canonical-tinted ink so the label sits on the
   tint with real contrast instead of the default slate-800 on every kind. */
#calendar-days .event-chip.event-chip-mini .event-chip-title,
.calendar-days .event-chip.event-chip-mini .event-chip-title {
  color: color-mix(in srgb, var(--event-chip-accent) 72%, #0f172a);
  font-weight: 600;
}
#calendar-days .event-chip.event-chip-mini .event-chip-time,
.calendar-days .event-chip.event-chip-mini .event-chip-time {
  color: color-mix(in srgb, var(--event-chip-accent) 60%, #334155);
}
/* Slightly separate the stacked blocks so they don't read as one bar. */
#calendar-days .calendar-day-events,
.calendar-days .calendar-day-events {
  gap: 3px;
  padding-bottom: 2px;
}
body.dark-mode #calendar-days .event-chip-mini,
body.dark-mode .calendar-days .event-chip-mini {
  border-color: color-mix(in srgb, var(--event-chip-accent, var(--slate-500, #64748b)) 50%, transparent);
}
/* Dark mode: mix the tint into the dark surface, and lighten the ink so the
   canonical hue stays legible on a dark cell. */
body.dark-mode #calendar-days .event-chip.event-chip-mini[data-category],
body.dark-mode .calendar-days .event-chip.event-chip-mini[data-category] {
  background: color-mix(in srgb, var(--event-chip-accent) 30%, var(--slate-800, #1e293b));
}
body.dark-mode #calendar-days .event-chip.event-chip-mini .event-chip-title,
body.dark-mode .calendar-days .event-chip.event-chip-mini .event-chip-title {
  color: color-mix(in srgb, var(--event-chip-accent) 45%, #f1f5f9);
}
body.dark-mode #calendar-days .event-chip.event-chip-mini .event-chip-time,
body.dark-mode .calendar-days .event-chip.event-chip-mini .event-chip-time {
  color: color-mix(in srgb, var(--event-chip-accent) 40%, #cbd5e1);
}
