/* ── Calendar — week view ──
   Hour grid, day-columns, all-day strip, busy overlays, now-pill,
   drag-create ghost, and the TZ picker (header button + modal). */

  /* ── Week view ── */
  .cal-week-wrap {
    display: flex; flex-direction: column;
    height: 100%; padding: 0 var(--space-lg) var(--space-lg);
    width: 100%; min-width: 0;
    /* Suppress text selection across the whole grid. Without this a
       click-drag on a day header / hour label / event title would
       paint a stray highlight (user-visible bug — every header,
       gutter and bar lit up blue during navigation). Description /
       title editing happens in the right side-panel, which sits
       outside this subtree and keeps native selection. */
    user-select: none; -webkit-user-select: none;
  }
  /* Single scroll container — see _renderTimeline. Header + all-day
     are sticky inside it so the body's vertical scroll keeps them
     pinned. Result: scrollbar lives on .cal-week-shell, eating one
     width from the right of all three rows uniformly → day-head
     columns line up with hour-grid columns to the pixel. */
  .cal-week-shell {
    display: flex; flex-direction: column;
    flex: 1; min-height: 0;
    overflow-y: auto;
    position: relative;
  }
  .cal-week-header {
    display: flex; flex-direction: row;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0; background: var(--deep);
    position: sticky; top: 0; z-index: 3;
    transition: box-shadow var(--transition);
  }
  .cal-week-allday {
    display: flex; flex-direction: row;
    flex-shrink: 0;
    background: var(--deep);
    position: sticky; top: var(--cal-header-h, 52px); z-index: 2;
    transition: box-shadow var(--transition);
  }
  /* Soft shadow under the sticky stack once the body has scrolled —
     Notion convention. Cue that the rows above are floating, not the
     edge of the viewport. _kcSyncShellScrolled (view-week.js) toggles
     .scrolled on the shell when scrollTop > 0. */
  .cal-week-shell.scrolled .cal-week-allday {
    box-shadow: var(--shadow-xs);
  }
  .cal-week-header .cal-week-gutter { flex: 0 0 60px; }
  .cal-week-header:has(.cal-week-gutter--dual) .cal-week-gutter { flex-basis: 96px; }
  /* border-box so the gutter's padding (4 6) + border-right (1) live
     INSIDE the 60/96 px flex-basis. Otherwise the gutter renders ~12-
     14px wider than the body's hour-gutter (no padding) and day-head
     columns drift to the right of hour-grid columns. */
  .cal-week-gutter {
    border-right: 1px solid var(--border);
    box-sizing: border-box;
    /* Default flex min-width:auto = min-content. With "+ MSK" buttons
       inside, that easily exceeds 60px and the gutter grew, breaking
       alignment with the body's hour-gutter. Lock to flex-basis. */
    min-width: 0;
    overflow: hidden;
  }
  .cal-week-gutter--dual {
    display: flex; align-items: flex-end; justify-content: space-between;
    padding: 4px 6px;
  }
  /* PR C2 — when the ISO week badge is visible, stack it above the
     TZ buttons inside the same 60-px gutter so we don't grow the
     column-width formulas (each day-col is `viewportWidth / 7`,
     gutter is `flex-basis: 60px`; widening would mis-align hour
     grid + day-heads). */
  .cal-week-gutter--weeknum {
    display: flex; flex-direction: column;
    align-items: stretch; justify-content: space-between;
    padding: 4px 6px;
  }
  .cal-week-gutter--weeknum.cal-week-gutter--dual {
    /* Re-apply dual padding override when both modifiers stack. */
    padding: 4px 6px;
  }
  .cal-week-gutter-weeknum {
    font-size: var(--font-2xs);
    font-weight: 700;
    color: var(--ink-muted);
    text-align: center;
    user-select: none;
  }
  .cal-week-gutter-weeknum::before {
    content: 'W'; margin-right: 2px; color: var(--ink-ghost);
  }
  .cal-week-gutter-tz-row {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: 2px;
  }

  .cal-week-gutter-label {
    font-size: 10px; font-weight: 700; color: var(--ink-muted);
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  /* Both TZ labels render with the same muted weight — Notion-style
     equality, so neither column reads as the "main" one. */
  .cal-week-gutter-label--secondary { color: var(--ink-muted); }

  /* TZ-trigger buttons inside the gutter top — replace the legacy
     `.cal-tz-btn` that lived in the header nav. Borderless, hover
     uses accent-soft. Both primary + secondary share styling so the
     two TZ columns read as siblings. */
  .cal-week-gutter-tz-trigger {
    display: inline-flex; align-items: center;
    height: 22px;
    padding: 0 6px;
    background: transparent; border: none;
    border-radius: var(--radius-s);
    color: var(--ink-muted);
    font: inherit; font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
    cursor: pointer;
    transition: background var(--transition);
  }
  .cal-week-gutter-tz-trigger:hover,
  .cal-week-gutter-tz-trigger:focus-visible {
    background: var(--accent-soft); color: var(--ink); outline: none;
  }
  /* `+` button shown when no secondary TZ exists. Square, slightly
     smaller, sits to the LEFT of the primary label. */
  .cal-week-gutter-tz-add {
    width: 18px; height: 18px;
    display: inline-flex; align-items: center; justify-content: center;
    margin-right: 4px;
    padding: 0;
    background: transparent; border: none;
    border-radius: var(--radius-s);
    color: var(--ink-muted);
    font: inherit; font-size: var(--font-md); line-height: 1;
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
  }
  .cal-week-gutter-tz-add:hover,
  .cal-week-gutter-tz-add:focus-visible {
    background: var(--accent-soft); color: var(--ink); outline: none;
  }
  /* Single-TZ gutter: line up `+` and primary label on a row. Tight
     padding so "+ MSK" fits in the 60px box (~47px content area). */
  .cal-week-gutter:not(.cal-week-gutter--dual) {
    display: flex; align-items: center; padding: 4px 4px;
    gap: 2px;
  }
  /* PR B2 — desaturate Sat/Sun headers when show_weekends is off.
     Matches the mini-month dim treatment (calendar-month.css). */
  body.cal-dim-weekends .cal-week-day-head.is-weekend {
    color: var(--ink-muted);
    opacity: 0.6;
  }
  body.cal-dim-weekends .cal-week-day-head.is-weekend.today {
    color: inherit; opacity: 1;
  }

  .cal-week-day-head {
    padding: 8px 0; text-align: center;
    border-right: 1px solid var(--border);
    cursor: pointer;
    transition: background var(--transition);
  }
  .cal-week-day-head:hover { background: var(--surface); }
  .cal-week-day-head:last-child { border-right: none; }
  .cal-week-day-head.today .cal-week-dom {
    color: var(--accent); font-weight: 700;
  }
  .cal-week-dow { font-size: var(--font-2xs); color: var(--ink-muted); text-transform: uppercase; }
  .cal-week-dom { font-size: var(--font-lg); color: var(--ink); margin-top: 2px; }
  .cal-week-body {
    /* No longer the scroll container — .cal-week-shell handles vertical
       scroll. Body is a normal-flow row inside the shell, sized by its
       lane's intrinsic 960px height. */
    display: flex; flex-direction: row;
    align-items: flex-start;
    flex-shrink: 0;
    position: relative;
    min-width: 0;
    /* Contained stacking context so the now-pill (z-index:4 inside the
       gutter-col) can't paint over the sticky .cal-week-allday row
       above it when the shell is scrolled. With isolation:isolate the
       whole body's paint stacks below the sticky allday's z-index:2. */
    isolation: isolate;
  }
  .cal-week-gutter-col {
    flex: 0 0 60px;
    border-right: 1px solid var(--border);
    position: relative;
    box-sizing: border-box;
    min-width: 0;
  }
  .cal-week-body:has(.cal-week-gutter-col--dual) .cal-week-gutter-col { flex-basis: 96px; }

  /* Viewport around the day-columns — clips horizontal pan so the lane
     can slide by translateX inside it. `contain` isolates lane DOM
     mutations from the rest of the page. */
  .cal-week-viewport {
    flex: 1; min-width: 0;
    position: relative; overflow: hidden;
    contain: layout paint;
  }
  /* One lane per row (header / all-day / body). Contains N day-cells
     side by side; width + grid-template-columns are set in JS in pixel
     values so day-columns are always viewport/7 wide exactly. */
  .cal-week-lane {
    display: grid;
    will-change: transform;
  }
  .cal-week-lane--body { height: 960px; }
  .cal-week-gutter-col--dual .cal-week-hour {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--space-xs);
  }
  .cal-week-hour {
    font-size: 10px; color: var(--ink-muted);
    padding: 2px 6px; text-align: right;
    box-sizing: border-box;
    border-bottom: 1px solid transparent;
  }
  .cal-week-hour-primary { color: var(--ink-muted); }
  /* Same muted color as primary — Notion-style equality between
     the two TZ columns. */
  .cal-week-hour-secondary { color: var(--ink-muted); font-variant-numeric: tabular-nums; }
  .cal-week-col {
    position: relative;
    border-right: 1px solid var(--border);
    cursor: crosshair;
    height: 960px;  /* 24 hours × 40 px */
    /* Off-screen day-columns in the 70-day pan buffer skip layout / paint
       until they enter the viewport — keeps the buffer extension cheap
       even when ~60 columns are off-screen at any moment. */
    content-visibility: auto;
    contain-intrinsic-size: auto 960px;
  }
  .cal-week-col:last-child { border-right: none; }
  .cal-week-col.today { background: rgba(var(--accent-rgb, 97, 97, 252), 0.04); }
  .cal-week-slot {
    position: absolute; left: 0; right: 0;
    border-bottom: 1px dashed transparent;
    pointer-events: none;
  }
  .cal-week-slot:nth-child(even) { border-bottom-color: var(--border); }
  .cal-week-off {
    position: absolute; left: 0; right: 0;
    background: rgba(0, 0, 0, 0.15);
    pointer-events: none;
  }
  .cal-week-event {
    position: absolute; left: 2px; right: 2px;
    padding: 4px 6px;
    border-radius: 6px;
    background: var(--accent); color: var(--on-accent);
    font-size: var(--font-2xs); line-height: 1.3;
    overflow: hidden; cursor: pointer;
    border: 1px solid rgba(0,0,0,0.15);
    transition: transform 0.08s ease;
  }
  .cal-week-event:hover { transform: translateY(-1px); filter: brightness(1.08); }
  .cal-week-event.type-audio { background: var(--event-type-audio); }
  .cal-week-event.type-offline { background: var(--event-type-offline); }
  /* PR D1 — Focus / OOO / Birthday kinds. */
  .cal-week-event.type-focus { background: var(--event-type-focus); }
  .cal-week-event.type-ooo { background: var(--event-type-ooo); }
  .cal-week-event.type-birthday { background: var(--event-type-birthday); }
  /* O.1 — per-event color override. Sits after the type-* rules so a
     coloured event paints with the explicit hue regardless of its
     kind. Border is the solid tone, fill is the soft variant — keeps
     the bar legible at any zoom level (Notion convention). */
  .cal-week-event.color-red    { background: var(--cal-color-red-soft);    border-color: var(--cal-color-red);    color: var(--ink); }
  .cal-week-event.color-orange { background: var(--cal-color-orange-soft); border-color: var(--cal-color-orange); color: var(--ink); }
  .cal-week-event.color-yellow { background: var(--cal-color-yellow-soft); border-color: var(--cal-color-yellow); color: var(--ink); }
  .cal-week-event.color-green  { background: var(--cal-color-green-soft);  border-color: var(--cal-color-green);  color: var(--ink); }
  .cal-week-event.color-blue   { background: var(--cal-color-blue-soft);   border-color: var(--cal-color-blue);   color: var(--ink); }
  .cal-week-event.color-purple { background: var(--cal-color-purple-soft); border-color: var(--cal-color-purple); color: var(--ink); }
  .cal-week-event.color-gray   { background: var(--cal-color-gray-soft);   border-color: var(--cal-color-gray);   color: var(--ink); }
  /* All-day bars mirror the timed-event coloring. */
  .cal-week-allday-bar.color-red    { background: var(--cal-color-red-soft);    border-color: var(--cal-color-red);    color: var(--ink); }
  .cal-week-allday-bar.color-orange { background: var(--cal-color-orange-soft); border-color: var(--cal-color-orange); color: var(--ink); }
  .cal-week-allday-bar.color-yellow { background: var(--cal-color-yellow-soft); border-color: var(--cal-color-yellow); color: var(--ink); }
  .cal-week-allday-bar.color-green  { background: var(--cal-color-green-soft);  border-color: var(--cal-color-green);  color: var(--ink); }
  .cal-week-allday-bar.color-blue   { background: var(--cal-color-blue-soft);   border-color: var(--cal-color-blue);   color: var(--ink); }
  .cal-week-allday-bar.color-purple { background: var(--cal-color-purple-soft); border-color: var(--cal-color-purple); color: var(--ink); }
  .cal-week-allday-bar.color-gray   { background: var(--cal-color-gray-soft);   border-color: var(--cal-color-gray);   color: var(--ink); }

  /* Epic N — buffer / travel-time halo. Striped semi-transparent band
     before / after the event, pointer-events:none so clicks pass to
     the event. Painted BELOW .cal-week-event (z-index 0 vs 1) so a
     drag preview / resize handle never gets covered. Diagonal stripes
     match the busy overlay's pattern but at a lower opacity so the
     halo reads as "softer" than another user's busy block. */
  .cal-week-event-buffer {
    position: absolute;
    z-index: 0;
    pointer-events: none;
    border-radius: 4px;
    /* Layer-E tokens — themed automatically (white-alpha in dark,
       black-alpha in light). Avoid hardcoded rgba per the token-gate
       ratchet in css_token_gate_test. */
    background:
      repeating-linear-gradient(
        45deg,
        var(--color-white-16) 0px,
        var(--color-white-16) 4px,
        transparent 4px,
        transparent 8px
      );
    border: 1px dashed var(--color-white-40);
  }
  .cal-week-event-buffer--before { border-bottom: 0; border-radius: 4px 4px 0 0; }
  .cal-week-event-buffer--after  { border-top: 0;    border-radius: 0 0 4px 4px; }
  /* Tinted halo: use the same colour token as the event itself so a
     red event has a red halo. Border = solid tone for the dashed edge. */
  .cal-week-event-buffer.color-red    { background-color: var(--cal-color-red-soft);    border-color: var(--cal-color-red); }
  .cal-week-event-buffer.color-orange { background-color: var(--cal-color-orange-soft); border-color: var(--cal-color-orange); }
  .cal-week-event-buffer.color-yellow { background-color: var(--cal-color-yellow-soft); border-color: var(--cal-color-yellow); }
  .cal-week-event-buffer.color-green  { background-color: var(--cal-color-green-soft);  border-color: var(--cal-color-green); }
  .cal-week-event-buffer.color-blue   { background-color: var(--cal-color-blue-soft);   border-color: var(--cal-color-blue); }
  .cal-week-event-buffer.color-purple { background-color: var(--cal-color-purple-soft); border-color: var(--cal-color-purple); }
  .cal-week-event-buffer.color-gray   { background-color: var(--cal-color-gray-soft);   border-color: var(--cal-color-gray); }

  /* P1-7 participant availability overlay. Striped half-transparent rectangle
     painted under the user's own events. --busy-color is set inline per user. */
  .cal-week-busy-overlay {
    position: absolute; z-index: 1;
    background:
      repeating-linear-gradient(
        45deg,
        var(--busy-color, var(--event-busy-default)) 0 3px,
        rgba(255,255,255,0) 3px 7px
      );
    opacity: 0.45;
    border-left: 2px solid var(--busy-color, var(--event-busy-default));
    border-radius: 3px;
    pointer-events: none;
  }
  .cal-week-event-time { font-size: 10px; opacity: 0.85; }
  .cal-week-event-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  /* Short events (< ~two-line height, e.g. a 30-min block) put title and
     time on ONE inline row instead of two clipped lines (Notion style).
     The title+time row wraps and is clipped to a single line: a short
     title leaves room so the time sits inline after it; a long title
     fills the row and the time wraps to the (clipped) second line,
     dropping out entirely — exactly how Notion handles it. The clip lives
     on the inner `cline`, not the chip, so the coloured block still fills
     the full event duration. */
  .cal-week-event--compact { padding-top: 2px; padding-bottom: 2px; }
  .cal-week-event--compact .cal-week-event-cline {
    display: flex;
    flex-flow: row wrap;
    align-items: baseline;
    align-content: flex-start;
    column-gap: 5px;
    line-height: 14px;
    max-height: 14px;
    overflow: hidden;
  }
  .cal-week-event--compact .cal-week-event-title { flex: 0 1 auto; min-width: 0; max-width: 100%; }
  .cal-week-event--compact .cal-week-event-time  { flex: 0 0 auto; }
  .cal-week-now {
    position: absolute; left: 0; right: 0; height: 2px;
    background: var(--coral); z-index: 3;
    pointer-events: none;
  }
  /* Thin coral line that runs across the entire body at the current time —
     visually links the left-side time pill to the highlighted now-line
     inside today's column. The thicker `.cal-week-now` paints over it. */
  .cal-week-now-thin {
    position: absolute; left: 0; right: 0; height: 1px;
    background: var(--coral); opacity: 0.5; z-index: 2;
    pointer-events: none;
  }
  .cal-week-now::before {
    content: ''; position: absolute; left: -4px; top: -3px;
    width: 8px; height: 8px; border-radius: 50%; background: var(--coral);
  }
  /* Pill-like time label sitting in the hour-gutter on the left, vertically
     aligned with the now-line. Stays pinned even when the grid scrolls
     horizontally because it's a child of `.cal-week-gutter-col`. */
  .cal-week-now-pill {
    position: absolute; right: 4px;
    transform: translateY(-50%);
    padding: 2px 6px; border-radius: var(--radius-pill);
    background: var(--coral); color: var(--on-accent);
    font-size: 10px; font-weight: 700; text-align: center;
    z-index: 4; pointer-events: none;
    box-shadow: var(--shadow-xs);
    font-variant-numeric: tabular-nums;
  }

  /* Drag-resize affordances on existing events (Notion parity):
     top edge resizes start time, bottom edge resizes end time, the
     middle drags the whole bar. 8px hit area is the sweet spot —
     wide enough for a trackpad, narrow enough not to swallow the
     title text underneath. Handles are invisible; the ns-resize
     cursor is the only visual cue, matching Notion / Google. */
  .cal-week-event { user-select: none; }
  .cal-week-event-resize,
  .cal-week-event-resize-top {
    position: absolute; left: 0; right: 0;
    height: 8px; cursor: ns-resize;
    z-index: 2; /* above the title so the cursor hits us first */
  }
  .cal-week-event-resize { bottom: 0; }
  .cal-week-event-resize-top { top: 0; }
  .cal-week-event.dragging {
    opacity: 0.6; z-index: 6;
  }

  /* Visual statuses. */
  .cal-week-event--tentative {
    border-style: dashed; opacity: 0.85;
  }
  .cal-week-event--cancelled {
    opacity: 0.55;
  }
  .cal-week-event--cancelled .cal-week-event-title {
    text-decoration: line-through;
  }
  /* Past events read as "already happened": tinted background, muted
     text, no left rail. Notion convention — separates done-deals
     from upcoming events at a glance. */
  .cal-week-event--past {
    background: var(--accent-soft);
    color: var(--ink-muted);
    border: 1px solid transparent;
  }
  .cal-week-event--past .cal-week-event-time,
  .cal-week-event--past .cal-week-event-title {
    color: var(--ink-muted);
    opacity: 1;
  }
  .cal-week-event--past:hover { filter: none; }

  /* Foreign events (not hosted by the current user) are read-only:
     no drag affordance, no resize handle. Click + right-click still
     open the detail panel — Notion convention. */
  .cal-week-event--readonly,
  .cal-week-allday-bar.cal-week-event--readonly {
    cursor: pointer;
  }
  .cal-week-event--readonly:hover {
    transform: none;
  }
  .cal-week-event--readonly .cal-week-event-resize,
  .cal-week-event--readonly .cal-week-event-resize-top {
    display: none;
  }
  .cal-week-allday-bar.cal-week-event--readonly::before,
  .cal-week-allday-bar.cal-week-event--readonly::after {
    cursor: default;
  }

  /* Drag-move "ghost original" — the source block stays in place,
     dimmed, while a preview clone follows the cursor at full opacity
     (Notion convention: user sees both the slot they're leaving and
     the slot they're considering). */
  .cal-week-event.drag-original {
    opacity: 0.35;
    pointer-events: none;
  }
  .cal-week-event.drag-preview {
    opacity: 0.92;
    pointer-events: none;
    z-index: 6;
    box-shadow: var(--shadow-s);
  }

  /* ── All-day strip above the hour grid ── */
  .cal-week-allday {
    display: flex; flex-direction: row;
    border-bottom: 1px solid var(--border);
    background: var(--deep); flex-shrink: 0;
  }
  .cal-week-allday .cal-week-allday-gutter { flex: 0 0 60px; }
  .cal-week-wrap:has(.cal-week-gutter--dual) .cal-week-allday .cal-week-allday-gutter {
    flex-basis: 96px;
  }
  .cal-week-allday-gutter {
    border-right: 1px solid var(--border);
    color: var(--ink-muted);
    /* Just the chevron toggle inside the gutter — Notion drops the
       "All-day" label here too. The tooltip on the toggle still
       advertises the section name. */
    padding: 4px;
    box-sizing: border-box;
    min-width: 0;
    overflow: hidden;
    display: flex; align-items: flex-start; justify-content: center;
  }
  .cal-week-allday-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px;
    background: transparent; border: none;
    color: var(--ink-muted); cursor: pointer;
    border-radius: var(--radius-s);
    transition: background var(--transition), color var(--transition);
    flex-shrink: 0;
  }
  .cal-week-allday-toggle:hover { background: var(--surface); color: var(--ink); }
  /* Static «Весь день» label — replaces the chevron in the gutter
     when there's ≤1 visible event (no toggle needed). At 10px with
     trimmed gutter padding (via the modifier below) the full label
     fits inside the 60px gutter without truncation. */
  .cal-week-allday-label {
    font-size: 10px;
    color: var(--ink-muted);
    line-height: 18px;
    white-space: nowrap;
  }
  /* When the gutter is hosting the static label (not the chevron),
     drop the side padding so the 9-char Cyrillic string isn't
     squeezed by the default 4px on each side. */
  .cal-week-allday-gutter:has(.cal-week-allday-label) {
    padding-left: 2px;
    padding-right: 2px;
  }
  /* Per-day "N событий" pill rendered inside each cell — visible
     only in the collapsed state (Notion convention). The expanded
     state hides it; cells then just serve as click + dblclick
     targets behind the bars. */
  .cal-week-allday-day-count {
    display: none;
    padding: 0 var(--space-sm);
    font-size: var(--font-2xs); color: var(--ink-muted);
    line-height: 22px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .cal-week-allday--collapsed .cal-week-allday-bar { display: none; }
  .cal-week-allday--collapsed .cal-week-allday-day-count { display: block; }
  /* In collapsed state, the lane only ever needs one row of cells
     (each carries its day's count); force grid-auto-rows back to a
     single 22px row so the strip doesn't pre-allocate buffer for
     the now-hidden bars. */
  .cal-week-allday--collapsed .cal-week-lane--allday {
    grid-auto-rows: 22px;
  }
  /* --single-row clips the lane to one row's height + the lane's
     own 3+3 padding. The lane is rendered off the 70-day pan buffer,
     so bars from off-screen weeks still occupy row 2..N in the grid;
     overflow:hidden hides them on weeks the user said should look
     empty, while keeping any row-0 visible bar in view. */
  .cal-week-allday--single-row .cal-week-lane--allday {
    max-height: 28px;
    overflow: hidden;
  }
  /* The cells carry an inline `grid-row: 1/${totalRows + 1}` so their
     right-border lines run the full row-pack height when expanded.
     In collapsed state bars are display:none — without an override
     the cells still hold open that multi-row span, leaving the
     section as tall as the original bar stack. Pin every cell to a
     single row so the lane (and its parent header) shrink to one
     22px row. !important is required to beat the inline style.

     The same shrink applies when the visible 7-day window has ≤1
     event but the lane was rendered off the 70-day pan buffer (its
     totalRows reflects bars elsewhere in the buffer). The
     --single-row modifier collapses the section to one row so the
     gutter's «Весь день» label sits next to a normal-height row. */
  .cal-week-allday--collapsed .cal-week-allday-cell,
  .cal-week-allday--single-row .cal-week-allday-cell {
    grid-row: 1 !important;
  }
  .cal-week-allday-cell {
    position: relative;
    border-right: 1px solid var(--border);
    padding: 0;
    box-sizing: border-box;
  }
  .cal-week-allday-cell:last-child { border-right: none; }
  /* The lane stacks bars vertically with grid-auto-rows. Each row is
     a fixed height so the empty cell with no events still draws its
     right border at the height of one row. */
  .cal-week-lane--allday {
    grid-auto-rows: 22px;
    row-gap: 2px;
    padding: 3px 0;
    min-height: 22px;
  }
  /* Multi-day bar (Notion-style). Spans grid-column from start day to
     end day; rounded ends unless the event continues beyond the
     visible buffer (then that side is square + slight inner gap so
     the eye reads it as "extends past the edge"). */
  .cal-week-allday-bar {
    align-self: center;
    margin: 1px 2px;
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--accent); color: var(--on-accent);
    font-size: var(--font-2xs); font-weight: 600; line-height: 1.3;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    cursor: pointer;
    z-index: 1;
    transition: filter var(--transition);
  }
  .cal-week-allday-bar:hover { filter: brightness(1.08); }
  /* D3.1 — Shift-click multi-selection. Distinct visual from the
     single-bar `.kc-cal-selected` (accent ring used when the side-
     panel is open): multi-select uses accent fill weight + an
     inner-shadow ring so a stack of selected bars reads as a clear
     group without changing per-kind colours. */
  .cal-week-allday-bar.kc-multi-selected,
  .cal-week-event.kc-multi-selected,
  .calendar-event.kc-multi-selected {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
    box-shadow: inset 0 0 0 9999px var(--accent-soft);
    z-index: 3;
  }
  /* Month bars are ~18-20px tall — outline-offset bleeds into the
     next bar's row. Tuck the outline flush so the highlight stays
     contained inside the chip. */
  .calendar-event.kc-multi-selected {
    outline-offset: 0;
  }

  /* D3.3 — floating action bar. Mounts at <body> when ≥2 events are
     selected; sits centered along the bottom edge of the viewport
     so it never collides with the side-panel (which is right-
     aligned). Pure CSS-positioned; visibility flips via a class so
     transitions stay smooth. */
  .cal-multi-action-bar {
    position: fixed;
    left: 50%;
    bottom: var(--space-lg);
    transform: translateX(-50%) translateY(6px);
    display: none;
    align-items: center;
    gap: var(--space-md);
    padding: 8px 12px;
    background: var(--raised);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-m);
    box-shadow: var(--shadow-m);
    z-index: 200;
    opacity: 0;
    transition: opacity var(--transition), transform var(--transition);
  }
  .cal-multi-action-bar.visible {
    display: inline-flex;
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  .cal-multi-action-count {
    color: var(--ink-secondary);
    font-size: var(--font-sm);
    font-weight: 500;
  }
  .cal-multi-action-btn {
    padding: 5px 12px;
    border-radius: var(--radius-s);
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--ink);
    font: inherit; font-size: var(--font-sm); font-weight: 500;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
  }
  .cal-multi-action-btn:hover {
    background: var(--elevated);
    border-color: var(--border-mid);
  }
  .cal-multi-action-btn--danger {
    color: var(--coral);
    border-color: var(--coral-soft);
    background: transparent;
  }
  .cal-multi-action-btn--danger:hover {
    background: var(--coral-soft);
    border-color: var(--coral);
  }
  .cal-multi-action-close {
    width: 22px; height: 22px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: none;
    color: var(--ink-muted);
    border-radius: var(--radius-s);
    cursor: pointer;
    transition: color var(--transition), background var(--transition);
  }
  .cal-multi-action-close:hover {
    color: var(--ink);
    background: var(--surface);
  }
  /* D3.4 — «Тип» dropdown inside the action bar. Same shape as the
     conferencing menu in the create-event panel for visual parity. */
  .cal-multi-action-kind {
    position: relative;
  }
  .cal-multi-action-kind-trigger {
    display: inline-flex; align-items: center; gap: 4px;
  }
  .cal-multi-action-kind-menu {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 6px);
    transform: translateX(-50%);
    min-width: 200px;
    padding: 4px;
    background: var(--raised);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-m);
    box-shadow: var(--shadow-m);
    display: flex;
    flex-direction: column;
    gap: 2px;
    z-index: 201;
  }
  .cal-multi-action-kind-menu[hidden] { display: none; }
  .cal-multi-action-kind-menu button {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 6px 10px;
    background: transparent; border: none;
    border-radius: var(--radius-s);
    color: var(--ink); font: inherit; font-size: var(--font-sm);
    cursor: pointer;
    text-align: left;
    transition: background var(--transition);
  }
  .cal-multi-action-kind-menu button:hover {
    background: var(--surface);
  }
  .cal-multi-action-kind-dot {
    width: 10px; height: 10px;
    border-radius: 50%;
    background: var(--accent);
    flex-shrink: 0;
  }
  .cal-multi-action-kind-dot.type-focus    { background: var(--event-type-focus); }
  .cal-multi-action-kind-dot.type-ooo      { background: var(--event-type-ooo); }
  .cal-multi-action-kind-dot.type-birthday { background: var(--event-type-birthday); }
  /* O.4 — bulk colour dropdown. Trigger sits next to the «Тип» button
     in the floating action bar; menu is a horizontal swatch strip
     instead of a vertical menu (saves a popover line in the busy
     toolbar zone). */
  .cal-multi-action-color { position: relative; }
  .cal-multi-action-color-trigger {
    display: inline-flex; align-items: center; gap: 4px;
  }
  .cal-multi-action-color-menu {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 6px);
    transform: translateX(-50%);
    padding: 8px;
    background: var(--raised);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-m);
    box-shadow: var(--shadow-m);
    display: flex;
    align-items: center;
    gap: 6px;
    z-index: 201;
  }
  .cal-multi-action-color-menu[hidden] { display: none; }
  .cal-multi-color-swatch {
    width: 22px; height: 22px;
    padding: 0;
    background: var(--cal-color-gray);
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
    transition: var(--transition);
  }
  .cal-multi-color-swatch:hover { transform: scale(1.08); }
  /* Solid hue — colour SELECTION matches the other two pickers, not the
     softened grid fill. */
  .cal-multi-color-swatch.color-red    { background: var(--cal-color-red); }
  .cal-multi-color-swatch.color-orange { background: var(--cal-color-orange); }
  .cal-multi-color-swatch.color-yellow { background: var(--cal-color-yellow); }
  .cal-multi-color-swatch.color-green  { background: var(--cal-color-green); }
  .cal-multi-color-swatch.color-blue   { background: var(--cal-color-blue); }
  .cal-multi-color-swatch.color-purple { background: var(--cal-color-purple); }
  .cal-multi-color-swatch.color-gray   { background: var(--cal-color-gray); }
  .cal-multi-color-swatch--default {
    background: transparent;
    border: 1px dashed var(--border-mid);
    color: var(--ink-muted);
    font-size: 13px; line-height: 1;
  }
  .cal-multi-color-swatch--default:hover {
    color: var(--ink); border-color: var(--ink-secondary);
  }

  /* Selected event — bar / block whose detail panel is currently open
     gets a 2px ring in the accent color so the user sees the link
     between the panel on the right and its source on the grid. */
  .cal-week-allday-bar.kc-cal-selected,
  .cal-week-event.kc-cal-selected {
    outline: 2px solid var(--ink);
    outline-offset: 1px;
    z-index: 2;
  }
  .cal-week-allday-bar.type-audio { background: var(--event-type-audio); }
  .cal-week-allday-bar.type-offline { background: var(--event-type-offline); }
  .cal-week-allday-bar.type-focus { background: var(--event-type-focus); }
  .cal-week-allday-bar.type-ooo { background: var(--event-type-ooo); }
  .cal-week-allday-bar.type-birthday { background: var(--event-type-birthday); }
  .cal-week-allday-bar.continues-left {
    border-top-left-radius: 0; border-bottom-left-radius: 0;
    margin-left: 0;
  }
  .cal-week-allday-bar.continues-right {
    border-top-right-radius: 0; border-bottom-right-radius: 0;
    margin-right: 0;
  }
  .cal-week-allday-bar.cal-week-event--tentative {
    border: 1px dashed rgba(255,255,255,0.6);
  }
  .cal-week-allday-bar.cal-week-event--cancelled {
    text-decoration: line-through; opacity: 0.55;
  }
  /* Resize affordance — last 6px on either edge of the bar gets the
     col-resize cursor so it telegraphs the drag-to-resize gesture.
     Implemented via `cursor: col-resize` on a thin pseudo overlay so
     the bar's internal click target stays cursor:pointer. */
  .cal-week-allday-bar::before,
  .cal-week-allday-bar::after {
    content: '';
    position: absolute;
    top: 0; bottom: 0;
    width: 6px;
    cursor: col-resize;
  }
  .cal-week-allday-bar { position: relative; }
  .cal-week-allday-bar::before { left: 0; }
  .cal-week-allday-bar::after { right: 0; }
  .cal-week-allday-bar.continues-left::before,
  .cal-week-allday-bar.continues-right::after { display: none; }
  .cal-week-allday-bar.resizing { opacity: 0.7; }

  /* "+N more" badge inside an .cal-week-allday-cell — appears on
     days that have all-day events stacking into rows >=1 (the strip
     is fixed-height single-row, so anything beyond row 0 is hidden
     behind this badge). Click → popover listing every event for
     the day. Notion convention. */
  .cal-week-allday-more {
    position: absolute;
    right: 4px; bottom: 1px;
    padding: 0 4px; height: 14px;
    border-radius: 4px;
    background: var(--surface);
    color: var(--ink-secondary);
    font-size: var(--font-2xs); font-weight: 600;
    line-height: 14px;
    cursor: pointer; z-index: 2;
    transition: background var(--transition), color var(--transition);
  }
  .cal-week-allday-more:hover {
    background: var(--accent); color: var(--on-accent);
  }
  .cal-allday-more-popover {
    position: fixed;
    z-index: 100;
    min-width: 220px; max-width: 320px;
    padding: 6px;
    background: var(--raised);
    border: 1px solid var(--border-mid);
    border-radius: var(--radius-m);
    box-shadow: var(--shadow-m);
    display: flex; flex-direction: column; gap: 2px;
  }
  .cal-allday-more-head {
    font-size: var(--font-2xs); color: var(--ink-muted);
    padding: 4px 8px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  .cal-allday-more-row {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px;
    background: transparent; border: none;
    border-radius: var(--radius-s);
    color: var(--ink); font: inherit; font-size: var(--font-sm);
    cursor: pointer; text-align: left;
    transition: background var(--transition);
  }
  .cal-allday-more-row:hover { background: var(--surface); }
  .cal-allday-more-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--accent); flex-shrink: 0;
  }
  .cal-allday-more-dot.type-audio { background: var(--event-type-audio); }
  .cal-allday-more-dot.type-offline { background: var(--event-type-offline); }
  .cal-allday-more-dot.type-focus { background: var(--event-type-focus); }
  .cal-allday-more-dot.type-ooo { background: var(--event-type-ooo); }
  .cal-allday-more-dot.type-birthday { background: var(--event-type-birthday); }
  .cal-allday-more-title {
    flex: 1; min-width: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }

  /* Subtle "you're about to convert this to all-day" hint while the
     user drags a timed event with the cursor over the all-day strip.
     The block stays in its column visually but goes translucent so
     the user notices the drop will reshape it. R2.3. */
  .cal-week-event.drag-into-allday {
    opacity: 0.4;
  }
  /* Notion-style drop preview rendered inside the hovered
     .cal-week-allday-cell — dashed accent rectangle pinned to the
     top of the cell so the user sees exactly where the event will
     land if they release here. Pointer-events:none so the mouseup
     still resolves against the real cell underneath. */
  .cal-allday-drop-ghost {
    position: absolute;
    top: 3px; left: 2px; right: 2px;
    height: 20px;
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--accent-soft);
    border: 1px dashed var(--accent);
    color: var(--accent);
    font-size: var(--font-2xs); font-weight: 600;
    line-height: 18px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    pointer-events: none;
    z-index: 3;
    box-sizing: border-box;
  }

  /* Drag-create ghost in the all-day strip — dashed accent bar that
     stretches across grid columns as the user drags from start day
     to end day. Same skin as .cal-event-preview / .cal-allday-preview
     so the visual reads as "in-progress event". */
  .cal-allday-create-ghost {
    align-self: center;
    margin: 1px 2px;
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--accent-soft);
    border: 1px dashed var(--accent);
    pointer-events: none;
    z-index: 2;
    min-height: 18px;
  }

  /* Floating ghost shown while dragging an all-day bar across the
     timeline. Lives at document.body, positioned by JS at cursor +
     6px offset. Drops the cursor pointer-events so document.element
     FromPoint sees the underlying day-column on mouseup. */
  .cal-allday-drag-ghost {
    position: fixed; z-index: 1000;
    pointer-events: none;
    padding: 2px 8px; border-radius: 4px;
    background: var(--accent); color: var(--on-accent);
    font-size: var(--font-2xs); font-weight: 600;
    box-shadow: var(--shadow-m);
    opacity: 0.85;
    max-width: 200px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }

  /* Drag-to-create ghost — week-grid only. */
  .cal-week-ghost {
    position: absolute; left: 2px; right: 2px;
    background: color-mix(in srgb, var(--accent) 35%, transparent);
    border: 2px dashed color-mix(in srgb, var(--accent) 70%, transparent);
    border-radius: 6px; pointer-events: none;
    z-index: 5;
    padding: 4px 6px;
    color: var(--ink);
    font-size: 11px;
    line-height: 1.2;
    transition: background var(--transition), border-color var(--transition);
  }
  /* Live HH:MM–HH:MM подпись внутри ghost'а (drag-to-create) и внутри
     full event-block при resize. Класс совпадает с .cal-week-event-time
     чтобы стиль не дублировать; здесь только override для opacity
     (chip более заметный в активном drag'е). */
  .cal-week-ghost .cal-week-event-time {
    opacity: 1;
    font-weight: 600;
  }
  /* Conflict tint — added by drag-create when the ghost's range
     overlaps an existing event in the same column. The user gets an
     immediate visual signal that the slot is busy without preventing
     them from creating anyway. */
  .cal-week-ghost--conflict {
    background: var(--coral-soft);
    border-color: var(--coral);
  }

  /* ── TZ picker header button + modal (P1-8) ─────────────────── */
  .cal-tz-btn.active {
    background: var(--accent); color: var(--on-accent); border-color: var(--accent);
  }
  /* ── TZ picker — Notion-style combobox ─────────────────────────
     Search input on top, scrollable IANA list below. Click any row =
     apply that tz; the modal closes itself. Esc / backdrop click
     close without applying. */
  .cal-tz-picker {
    display: none; position: fixed; inset: 0; z-index: 70;
    background: rgba(0, 0, 0, 0.5);
    align-items: flex-start; justify-content: center;
    padding-top: 12vh;
  }
  .cal-tz-picker.visible { display: flex; }
  .cal-tz-picker-box {
    display: flex; flex-direction: column;
    background: var(--deep); border: 1px solid var(--border);
    border-radius: var(--radius-m);
    width: min(420px, 92vw);
    max-height: 70vh;
    box-shadow: var(--shadow-l);
    overflow: hidden;
  }
  .cal-tz-picker-search {
    flex-shrink: 0;
    padding: 12px 14px;
    background: var(--surface); border: none;
    border-bottom: 1px solid var(--border);
    color: var(--ink); font: inherit; font-size: var(--font-md);
    outline: none;
  }
  .cal-tz-picker-search::placeholder { color: var(--ink-ghost); }
  .cal-tz-picker-clear {
    flex-shrink: 0;
    display: flex; align-items: center; gap: 8px;
    padding: 10px 14px;
    background: transparent; border: none;
    border-bottom: 1px solid var(--border);
    color: var(--coral);
    font: inherit; font-size: var(--font-sm);
    cursor: pointer;
    transition: background var(--transition);
  }
  .cal-tz-picker-clear:hover { background: var(--coral-soft); }
  .cal-tz-picker-list {
    flex: 1; overflow-y: auto;
  }
  .cal-tz-picker-section {
    border-bottom: 1px solid var(--border);
  }
  .cal-tz-picker-section:last-child { border-bottom: none; }
  .cal-tz-picker-row {
    width: 100%;
    display: grid;
    grid-template-columns: 88px 1fr 16px;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: transparent; border: none;
    color: var(--ink); font: inherit; font-size: var(--font-sm);
    text-align: left;
    cursor: pointer;
    transition: background var(--transition);
  }
  .cal-tz-picker-row:hover { background: var(--accent-soft); }
  .cal-tz-picker-row--current { background: var(--accent-soft); }
  .cal-tz-picker-row-gmt {
    color: var(--ink-muted); font-variant-numeric: tabular-nums;
    font-size: var(--font-xs);
  }
  .cal-tz-picker-row-label { color: var(--ink); }
  .cal-tz-picker-row-city { color: var(--ink-muted); }
  .cal-tz-picker-row-recent {
    color: var(--ink-muted); font-size: var(--font-md); justify-self: end;
  }
  .cal-tz-picker-empty {
    padding: 20px; text-align: center;
    color: var(--ink-muted); font-size: var(--font-sm);
  }
