/* shell/public/tracker/css/online-tracker.css
 * Single source of truth for tracker visual styles. Includes desktop layout +
 * mobile responsive (per the v1 styles-base.css mobile patches at line 623).
 * One bug-fix point — change here propagates to every consumer page.
 */

.ot-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid rgba(255,255,255,0.08);
  cursor: pointer; transition: background 0.05s;
  position: relative;
}
.ot-row:hover { background: rgba(255,255,255,0.03); }

.ot-name {
  width: 140px; min-width: 140px; font-size: 13px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--text);
}

.ot-bar-wrap {
  flex: 1 0 calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1));
  min-width: 0; height: 22px;
  position: relative; background: var(--bg2);
  border-radius: 4px;
  overflow: hidden;
}

/* Inner scaler — kept as a wrapper for backwards compatibility with render.js
 * markup. With the unified mobile-style scroll model (the .ot-drag-pan card
 * scrolls natively horizontally), the scaler no longer scales internally —
 * each .ot-bar-wrap is physically (450px × zoom) wide instead. */
.ot-bar-scaler {
  position: relative; height: 100%;
  width: 100%; transform: none;
}

.ot-seg {
  position: absolute; top: 0; bottom: 0;
  border-radius: 1px;
}

/* Header center cell ("24h Timeline" label). Class instead of inline flex:1
 * so the mobile media query can override it to match .ot-bar-wrap (which
 * grows with --ot-zoom). Without this, the header stays at 940px wide while
 * data rows widen to 1390/1840/2290 at zoom 2/3/4 and the layout drifts. */
.ot-header-bar { flex: 1 0 calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1)); text-align: center; line-height: 1.2; }

/* Vertical hour-tick lines — paint 12 ticks (every 2h: 00 02 04 ... 22 00)
 * across every .ot-bar-scaler so the hour-marker ruler + each model's main
 * bar + every open detail's 4 platform bars all show the same column
 * positions. Pseudo paints first in DOM order, real .ot-seg children paint
 * on top, so colored activity covers the line wherever there's data
 * (= "behind segments" per user pick). 1px ticks at ~12% white over the
 * dark var(--bg2) bar background. */
.ot-bar-scaler::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.12) 0, rgba(255,255,255,0.12) 1px, transparent 1px),
    repeating-linear-gradient(
      to right,
      transparent 0,
      transparent calc((100% / 12) - 1px),
      rgba(255, 255, 255, 0.12) calc((100% / 12) - 1px),
      rgba(255, 255, 255, 0.12) calc(100% / 12)
    );
  pointer-events: none;
}

/* Row-level vertical tick painters — paint the same 12-tick gradient in the
 * row's top/bottom padding + border area (where .ot-bar-scaler::before can't
 * reach because .ot-bar-wrap clips at 22px). Combined with the in-bar ticks,
 * the lines visually pass through every row's padding+border, looking like
 * one continuous vertical line top-to-bottom across hour ruler + main bar +
 * 4 detail bars. left/right inset matches the bar column (150 / 340).
 *
 * Caveat at zoom > 1 desktop: in-bar ticks slide via --ot-scroll-x while
 * these padding ticks stay fixed → they may visually disconnect at the bar
 * top/bottom edge at higher zoom. Aligned at zoom 1x. */
.ot-row::before, .ot-row::after,
.ot-detail-row::before, .ot-detail-row::after,
.ot-hour-markers::before {
  content: '';
  position: absolute;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.12) 0, rgba(255,255,255,0.12) 1px, transparent 1px),
    repeating-linear-gradient(
      to right,
      transparent 0,
      transparent calc((100% / 12) - 1px),
      rgba(255, 255, 255, 0.12) calc((100% / 12) - 1px),
      rgba(255, 255, 255, 0.12) calc(100% / 12)
    );
}
.ot-row::before { top: 0; height: 6px; left: 150px; right: 340px; }
.ot-row::after { bottom: 0; height: 7px; left: 150px; right: 340px; }
.ot-detail-row::before { top: 0; height: 3px; left: 150px; right: 340px; }
.ot-detail-row::after { bottom: 0; height: 3px; left: 150px; right: 340px; }
.ot-hour-markers::before { top: 0; bottom: 0; left: 0; right: 0; }

.ot-nums {
  display: flex; gap: 8px; align-items: center;
  font-family: 'DM Mono', monospace; font-size: 13px;
}

.ot-header {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 0; border-bottom: 1px solid rgba(255,255,255,0.08);
  font-size: 10px; color: var(--text3); user-select: none;
  position: relative;
}

.ot-detail {
  max-height: 0; overflow: hidden; transition: max-height 0.2s ease;
  background: var(--bg1);
}
.ot-detail.open { max-height: 600px; }

.ot-detail-inner { padding: 8px 0; position: relative; }
.ot-detail-inner::before, .ot-detail-inner::after {
  content: '';
  position: absolute;
  left: 150px; right: 340px;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.12) 0, rgba(255,255,255,0.12) 1px, transparent 1px),
    repeating-linear-gradient(
      to right,
      transparent 0,
      transparent calc((100% / 12) - 1px),
      rgba(255, 255, 255, 0.12) calc((100% / 12) - 1px),
      rgba(255, 255, 255, 0.12) calc(100% / 12)
    );
}
.ot-detail-inner::before { top: 0; height: 8px; }
.ot-detail-inner::after { bottom: 0; height: 8px; }

/* Detail rows must align minute-by-minute with the main .ot-row global bar:
 *   - label width matches .ot-name (140px)
 *   - row gap matches .ot-row (10px)
 *   - right padding reserves the .ot-nums counters column width
 *     (shift 68 + total 55 + conf 55 + unconf 65 + break 55 + 4 gaps × 8 = 330px,
 *      plus the 10px gap between .ot-bar-wrap and .ot-nums = 340px)
 */
.ot-detail-row {
  display: flex; align-items: center; gap: 10px;
  padding: 3px 0 3px 0;
  padding-right: 340px;
  position: relative;
}
.ot-detail-label {
  width: 140px; min-width: 140px; font-size: 10px;
  color: var(--text3); text-align: right;
}
.ot-detail-bar {
  flex: 1 0 calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1));
  height: 14px; position: relative;
  background: var(--bg2); border-radius: 3px;
  overflow: hidden;
}

.ot-detail-summary {
  margin: 6px 0 0 150px; font-size: 11px; line-height: 1.5;
  color: var(--text2);
}

.ot-hour-markers {
  /* Aligned to the global bar position: name(140) + gap(10) on the left,
   * counters(330) + gap(10) on the right.
   * margin-bottom 0 so the ruler's tick lines butt up against the first row's
   * tick lines for a continuous vertical-line look.
   * min-width: 450px × zoom locks the ruler width to the bar width so all
   * tick layers align. */
  position: relative; height: 16px;
  margin: 0 340px 0 150px;
  min-width: calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1));
  font-size: 9px; color: var(--text3);
  font-family: 'DM Mono', monospace;
  overflow: hidden;
}
.ot-hour-mark {
  position: absolute; top: 0; transform: translateX(-50%);
  white-space: nowrap;
}

#ot-tip {
  position: fixed; z-index: 9999; pointer-events: none;
  background: #1a1a2e; border: 1px solid rgba(255,255,255,0.15);
  color: var(--text); font-size: 12px; padding: 5px 10px;
  border-radius: 6px; opacity: 0;
  transition: opacity 0.05s;
  font-family: 'DM Mono', monospace;
  max-width: 320px;
}
#ot-tip.show { opacity: 1; }

/* Unified scroll model (desktop + mobile): the .ot-drag-pan card is the
 * native horizontal scroll container; bars are physically (450px × zoom)
 * wide via flex-basis, NOT scaled internally via transform. The user pans
 * by dragging anywhere in the card OR by using the top/bottom phantom
 * scrollbars (kept on desktop, hidden on mobile in favour of the card's
 * own scrollbar).
 *
 * width: max-content on rows + #ot-container ensures the row's
 * border-bottom divider extends across the full widened row at any zoom,
 * not just the original 940px viewport width. */
.ot-row, .ot-header, .ot-detail-row { min-width: calc(490px + var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1)); }
#ot-container { width: max-content; min-width: 100%; }

/* Desktop default: hide the .ot-drag-pan card's native horizontal
 * scrollbar (the user uses the top/bottom phantom scrollbars instead).
 * Mobile @media block below re-enables the green native scrollbar. */
.ot-drag-pan { scrollbar-width: none; }
.ot-drag-pan::-webkit-scrollbar { display: none; }

/* Tick gradient for all 4 layers — absolute pixel cycle of (450 × zoom)/12
 * = 37.5px at zoom 1, 150px at zoom 4. Same math as bar-wrap's flex-basis
 * so every tick layer aligns pixel-perfect. .ot-header::before extends the
 * lines through the header row that sits between the hour ruler and the
 * first data row. */
.ot-bar-scaler::before,
.ot-row::before, .ot-row::after,
.ot-detail-row::before, .ot-detail-row::after,
.ot-detail-inner::before, .ot-detail-inner::after,
.ot-hour-markers::before,
.ot-header::before {
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.12) 0, rgba(255,255,255,0.12) 1px, transparent 1px),
    repeating-linear-gradient(
      to right,
      transparent 0,
      transparent calc((var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1)) / 12 - 1px),
      rgba(255, 255, 255, 0.12) calc((var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1)) / 12 - 1px),
      rgba(255, 255, 255, 0.12) calc((var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1)) / 12)
    );
}
/* Row-level pseudo-elements pinned to exact bar pixel width so they cannot
 * inherit sub-pixel drift from the row's max-content arithmetic. */
.ot-row::before, .ot-row::after,
.ot-detail-row::before, .ot-detail-row::after,
.ot-detail-inner::before, .ot-detail-inner::after {
  left: 150px; right: auto;
  width: calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1));
}
.ot-hour-markers::before {
  left: 0; right: auto;
  width: calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1));
}
.ot-header::before {
  top: 0; bottom: 0; left: 150px; right: auto;
  width: calc(var(--ot-bar-fill-width, 450px) * var(--ot-zoom, 1));
}

/* Mobile (≤720px) — card uses its own custom green scrollbar; phantom bars
 * hidden. Click-drag-pan + zoom buttons all use the same scroll mechanism
 * as desktop now (the card's native horizontal scroll). */
@media (max-width: 720px) {
  .ot-drag-pan {
    overflow-x: auto !important;
    overflow-y: visible !important;
    -webkit-overflow-scrolling: touch;
    padding-top: 28px !important;
    scrollbar-color: var(--accent) rgba(0,229,160,0.10);
    scrollbar-width: thin;
  }
  .ot-drag-pan::-webkit-scrollbar { height: 10px; -webkit-appearance: none; }
  .ot-drag-pan::-webkit-scrollbar-track { background: rgba(0,229,160,0.10); border-radius: 6px; }
  .ot-drag-pan::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 6px; min-width: 40px; }
  /* Sticky "← swipe →" cue — same pattern as models/team-members pages. */
  .ot-drag-pan::before {
    content: '← swipe →';
    position: sticky; top: 0; left: 0;
    display: block; width: max-content;
    background: var(--accent); color: #000;
    font-family: 'DM Mono', monospace;
    font-size: 10px; font-weight: 700; letter-spacing: .5px;
    padding: 2px 8px; border-radius: 0 0 6px 0;
    z-index: 2; pointer-events: none;
    margin: -24px 0 6px 0;
  }
  /* Counters slightly tighter on mobile but stay on one line with the bar. */
  .ot-nums { font-size: 12px; gap: 6px; }
  .ot-name { font-size: 13px; }
}

/* Zoom button row — 1×/2×/3×/4× + reset. Active button uses --accent.
 * State lives in module-level _otZoom; CSS variable --ot-zoom is set on the
 * page root and survives detail expand/collapse and auto-refresh. */
.ot-zoom-btn {
  background: var(--bg3); border: 1px solid var(--border);
  color: var(--text2); font-family: 'DM Mono', monospace;
  font-size: 11px; padding: 4px 10px; cursor: pointer;
  border-radius: 0;
}
.ot-zoom-btn:first-child { border-radius: 6px 0 0 6px; }
.ot-zoom-btn:last-of-type { border-radius: 0 6px 6px 0; border-right: 1px solid var(--border); }
.ot-zoom-btn.active { background: var(--accent); color: #000; border-color: var(--accent); font-weight: 700; }
.ot-zoom-reset {
  background: var(--bg3); border: 1px solid var(--border);
  color: var(--text2); font-family: 'DM Mono', monospace;
  font-size: 11px; padding: 4px 10px; cursor: pointer;
  border-radius: 6px; margin-left: 4px;
}
.ot-zoom-reset:hover { background: var(--bg4); color: var(--text); }

/* Shared scrollbar (top + bottom phantom). Both have overflow-x:auto on a
 * narrow strip, with an inner spacer sized to ot-zoom * viewport so the user
 * can drag a single scrollbar that drives every timeline row in unison via
 * --ot-scroll-x. Aligned to the same left/right inset as the global bar
 * (matches the .ot-hour-markers margin). */
.ot-shared-scrollbar {
  margin: 0 340px 0 150px;
  height: 20px;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-color: var(--accent) var(--bg2);
  scrollbar-width: auto;            /* "auto" = full thickness, was "thin" before */
}
.ot-shared-scrollbar-top { margin-bottom: 4px; }
.ot-shared-scrollbar-bottom { margin-top: 4px; }
.ot-shared-scrollbar::-webkit-scrollbar { height: 20px; }
.ot-shared-scrollbar::-webkit-scrollbar-track {
  background: var(--bg2); border-radius: 6px;
}
.ot-shared-scrollbar::-webkit-scrollbar-thumb {
  background: var(--accent); border-radius: 6px;
  border: 2px solid var(--bg2); /* gives a "padded thumb" look on green */
}
.ot-shared-scrollbar::-webkit-scrollbar-thumb:hover { background: var(--accent2, #007e5a); }
.ot-shared-scrollbar-spacer { height: 1px; min-width: 100%; }

@media (max-width: 720px) {
  /* On phones the card scrolls natively (see .ot-drag-pan above), so the
   * phantom shared scrollbars become a confusing duplicate — hide them. */
  .ot-shared-scrollbar { display: none; }
}

/* 2D drag-to-pan area — desktop mouse only. Touch devices keep native
 * scroll (was: touch-action:none + setPointerCapture killed phone momentum
 * scroll — ~1/20 speed with no fling). */
.ot-drag-pan { user-select: none; -webkit-user-select: none; }
.ot-drag-pan.dragging { cursor: grabbing; }
