/* ═══════════════════════════════════════════════════════════════════
   MARKET CLOCK · Shadow Terminal premium world clock widget
   Features:
     - 7 financial hubs with live session danger coloring
     - Analog/Digital toggle (persisted to localStorage)
     - Auto day/night face per city: white face = daytime, dark = night
     - Session color glow ring on each clock bezel
     - Dubai (owner's local) always accented in blue
   Usage:
     <script type="text/babel" src="../_fx/market-clock.jsx?v=1"></script>
     <MarketClock overrideUtcHour={null} />
   ═══════════════════════════════════════════════════════════════════ */

/* ── Inject keyframes once ─────────────────────────────────────────── */
(function injectClockCSS() {
  if (document.getElementById('st-clock-css')) return;
  const s = document.createElement('style');
  s.id = 'st-clock-css';
  s.textContent = `
    @keyframes clock-digit-tick {
      0%   { opacity: 0.5; transform: translateY(-2px); }
      100% { opacity: 1;   transform: translateY(0); }
    }
    @keyframes session-pulse {
      0%, 100% { opacity: 1; }
      50%       { opacity: 0.68; }
    }
    @keyframes clock-fadein {
      0%   { opacity: 0; transform: translateY(6px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    @keyframes glow-pulse {
      0%, 100% { opacity: 0.6; }
      50%       { opacity: 1; }
    }
    .clock-digit-tick { animation: clock-digit-tick 0.15s ease; }
    .session-pulse    { animation: session-pulse 2s ease-in-out infinite; }
    .clock-card-enter { animation: clock-fadein 0.45s cubic-bezier(.2,.7,.3,1) both; }
    .st-clock-toggle {
      display: flex; gap: 2px; padding: 2px;
      background: #0B0D14;
      border: 1px solid #1E2130; border-radius: 5px;
      cursor: pointer; flex-shrink: 0;
    }
    .st-clock-toggle-btn {
      padding: 3px 7px;
      font-family: 'JetBrains Mono', monospace;
      font-size: 9px; font-weight: 600; letter-spacing: 0.1em;
      border: none; border-radius: 3px; cursor: pointer;
      transition: background 0.18s, color 0.18s, border-color 0.18s;
    }
    .st-clocks-row::-webkit-scrollbar { height: 3px; }
    .st-clocks-row::-webkit-scrollbar-track { background: transparent; }
    .st-clocks-row::-webkit-scrollbar-thumb { background: #1E2130; border-radius: 2px; }
  `;
  document.head.appendChild(s);
})();

/* ── Design tokens ────────────────────────────────────────────────── */
const CK = {
  bg:      '#0B0D14',
  panel:   '#13161F',
  panel2:  '#181C28',
  border:  '#1E2130',
  ink:     '#ECEFF6',
  muted:   '#8B93A6',
  muted2:  '#5A6276',
  amber:   '#F7A600',
  green:   '#2EE49B',
  red:     '#FF5C77',
  blue:    '#6EA8FF',
  gray:    '#6B7280',
};

/* ── Session logic ────────────────────────────────────────────────── */
function getSessionForHour(utcHour) {
  const h = ((utcHour % 24) + 24) % 24;
  if (h >= 13 && h < 17) return {
    key: 'OVERLAP', name: 'EU/US OVERLAP — DANGER ZONE', color: CK.red,
    threshold: '75%', cycleProb: '0.20',
    rec: 'Shadow threshold raised to 75% · Bot 2 conservative',
    dangerLevel: 'EXTREME',
  };
  if (h >= 17 && h < 22) return {
    key: 'US_SESSION', name: 'US SESSION', color: CK.amber,
    threshold: '60%', cycleProb: '0.30',
    rec: 'Shadow threshold 60% · Bot 2 moderate',
    dangerLevel: 'HIGH',
  };
  if (h >= 7 && h < 13) return {
    key: 'EU_SESSION', name: 'EU SESSION', color: CK.amber,
    threshold: '60%', cycleProb: '0.30',
    rec: 'Shadow threshold 60% · Bot 2 moderate',
    dangerLevel: 'MEDIUM',
  };
  if (h >= 0 && h < 7) return {
    key: 'ASIAN_SESSION', name: 'ASIAN SESSION — CALM', color: CK.green,
    threshold: '55%', cycleProb: '0.45',
    rec: 'Shadow threshold 55% · Bot 2 active — grids optimal',
    dangerLevel: 'LOW',
  };
  return {
    key: 'DEAD_ZONE', name: 'DEAD ZONE — LOW VOLUME', color: CK.gray,
    threshold: '65%', cycleProb: '0.10',
    rec: 'Hold positions · no new signals',
    dangerLevel: 'LOW',
  };
}

/* ── DST helpers ─────────────────────────────────────────────────── */
function lastSunday(year, month) {
  const last = new Date(Date.UTC(year, month + 1, 0));
  return new Date(Date.UTC(year, month + 1, 0 - last.getUTCDay()));
}
function nthSunday(year, month, n) {
  const d   = new Date(Date.UTC(year, month, 1));
  const off = (7 - d.getUTCDay()) % 7;
  return new Date(Date.UTC(year, month, 1 + off + (n - 1) * 7));
}
function ukOffset(now)  {
  const y = now.getUTCFullYear();
  return (now >= lastSunday(y, 2) && now < lastSunday(y, 9)) ? 1 : 0;
}
function euOffset(now)  {
  const y = now.getUTCFullYear();
  return (now >= lastSunday(y, 2) && now < lastSunday(y, 9)) ? 2 : 1;
}
function usOffset(now)  {
  const y = now.getUTCFullYear();
  return (now >= nthSunday(y, 2, 2) && now < nthSunday(y, 10, 1)) ? -4 : -5;
}

/* ── Cities definition ───────────────────────────────────────────── */
function getCities(now) {
  return [
    { id: 'tokyo',     flag: '🇯🇵', city: 'TOKYO',     offset: 9,             sessionOpen: [0,6],   sessionPeak: [1,4]   },
    { id: 'seoul',     flag: '🇰🇷', city: 'SEOUL',     offset: 9,             sessionOpen: [0,6],   sessionPeak: [1,5]   },
    { id: 'shanghai',  flag: '🇨🇳', city: 'SHANGHAI',  offset: 8,             sessionOpen: [1,7],   sessionPeak: [2,5]   },
    { id: 'dubai',     flag: '🇦🇪', city: 'DUBAI',     offset: 4,             sessionOpen: [5,14],  sessionPeak: [8,12],  isLocal: true },
    { id: 'frankfurt', flag: '🇩🇪', city: 'FRANKFURT', offset: euOffset(now), sessionOpen: [7,16],  sessionPeak: [8,12]  },
    { id: 'london',    flag: '🇬🇧', city: 'LONDON',    offset: ukOffset(now), sessionOpen: [7,17],  sessionPeak: [8,12]  },
    { id: 'newyork',   flag: '🇺🇸', city: 'NEW YORK',  offset: usOffset(now), sessionOpen: [13,22], sessionPeak: [14,20] },
  ];
}

/* ── Per-city status ─────────────────────────────────────────────── */
function getCityStatus(utcH, city) {
  if (city.isLocal) return 'LOCAL';
  const [os, oe] = city.sessionOpen;
  const [ps, pe] = city.sessionPeak;
  if (utcH >= ps && utcH < pe) return 'PEAK';
  if (utcH >= os && utcH < oe) return 'OPEN';
  return 'CLOSED';
}

/* ── Helpers ─────────────────────────────────────────────────────── */
function pad2(n) { return String(n).padStart(2, '0'); }

function localTime(now, offsetHours) {
  const ms    = now.getTime() + offsetHours * 3_600_000;
  const local = new Date(ms);
  return {
    hh:        pad2(local.getUTCHours()),
    mm:        pad2(local.getUTCMinutes()),
    ss:        pad2(local.getUTCSeconds()),
    date:      local,
    localHour: local.getUTCHours(),
  };
}

function dayDiff(nowUtc, localDate) {
  const um = Date.UTC(nowUtc.getUTCFullYear(),   nowUtc.getUTCMonth(),    nowUtc.getUTCDate());
  const lm = Date.UTC(localDate.getUTCFullYear(), localDate.getUTCMonth(), localDate.getUTCDate());
  const d  = (lm - um) / 86_400_000;
  if (d > 0) return 'TOMORROW';
  if (d < 0) return 'YESTERDAY';
  return null;
}

function isDay(localHour) { return localHour >= 6 && localHour < 20; }

/* ══════════════════════════════════════════════════════════════════
   ANALOG CLOCK — premium SVG bezel
   White face = daytime · Dark face = nighttime
   Session color ring around the bezel
   ══════════════════════════════════════════════════════════════════ */
function AnalogClock({ hh, mm, ss, localHour, ringColor, size = 80 }) {
  const day = isDay(localHour);
  const W   = size;
  const CX  = W / 2;
  const CY  = W / 2;
  const R   = W / 2 - 6;

  const secAngle  = parseInt(ss) * 6;
  const minAngle  = (parseInt(mm) + parseInt(ss) / 60) * 6;
  const hourAngle = ((parseInt(hh) % 12) + parseInt(mm) / 60 + parseInt(ss) / 3600) * 30;

  function pt(angleDeg, len) {
    const rad = (angleDeg - 90) * Math.PI / 180;
    return [CX + len * Math.cos(rad), CY + len * Math.sin(rad)];
  }

  const [hx, hy]   = pt(hourAngle, R * 0.50);
  const [mx, my]   = pt(minAngle,  R * 0.70);
  const [sx, sy]   = pt(secAngle,  R * 0.83);
  const [stx, sty] = pt(secAngle + 180, R * 0.20);

  const faceFill  = day ? '#EEF1FA' : '#0C0E18';
  const faceGrad1 = day ? '#F9FAFF' : '#13161F';
  const tickMajor = day ? '#1E2130' : '#4A5068';
  const tickMinor = day ? '#AAB0C0' : '#252840';
  const hourHand  = day ? '#0D0F18' : '#ECEFF6';
  const minHand   = day ? '#2A3050' : '#9AAABE';
  const numeralC  = day ? '#2A3050' : '#4A5068';
  const bezelC    = day ? '#C8D0E0' : '#1E2130';
  const gradId    = `fg-${day?'d':'n'}-${Math.round(R)}`;
  const shadowId  = `hs-${Math.round(R)}`;
  const shadowC   = day ? 'rgba(0,0,0,0.15)' : 'rgba(0,0,0,0.55)';

  const ticks = Array.from({ length: 60 }, (_, i) => {
    const a      = i * 6;
    const rad    = (a - 90) * Math.PI / 180;
    const isHour = i % 5 === 0;
    const isQtr  = i % 15 === 0;
    const outer  = R - 1;
    const inner  = isQtr ? R - 8 : isHour ? R - 5 : R - 3;
    return { ox: CX + outer*Math.cos(rad), oy: CY + outer*Math.sin(rad),
             ix: CX + inner*Math.cos(rad), iy: CY + inner*Math.sin(rad),
             isHour, isQtr };
  });

  const qtrLabels = [
    { a: 0,   label: '12' },
    { a: 90,  label: '3'  },
    { a: 180, label: '6'  },
    { a: 270, label: '9'  },
  ];

  return (
    <svg width={W} height={W} viewBox={`0 0 ${W} ${W}`} style={{ display: 'block', flexShrink: 0 }}>
      <defs>
        <radialGradient id={gradId} cx="36%" cy="30%" r="70%">
          <stop offset="0%"   stopColor={faceGrad1} />
          <stop offset="100%" stopColor={faceFill}  />
        </radialGradient>
        <filter id={shadowId} x="-30%" y="-30%" width="160%" height="160%">
          <feDropShadow dx="0" dy="1" stdDeviation="1" floodColor={shadowC} />
        </filter>
        <radialGradient id={`glow-${Math.round(R)}`} cx="50%" cy="50%" r="50%">
          <stop offset="0%"   stopColor={ringColor} stopOpacity="0.30" />
          <stop offset="100%" stopColor={ringColor} stopOpacity="0"    />
        </radialGradient>
      </defs>

      {/* Ambient glow */}
      <circle cx={CX} cy={CY} r={R + 11} fill={`url(#glow-${Math.round(R)})`} />

      {/* Outer glow rings */}
      <circle cx={CX} cy={CY} r={R + 4.5} fill="none" stroke={ringColor} strokeWidth="0.4" opacity="0.20" />
      <circle cx={CX} cy={CY} r={R + 2.5} fill="none" stroke={ringColor} strokeWidth="0.9" opacity="0.45" />
      <circle cx={CX} cy={CY} r={R + 1}   fill="none" stroke={ringColor} strokeWidth="1.5" opacity="0.70" />

      {/* Bezel ring */}
      <circle cx={CX} cy={CY} r={R + 0.3} fill="none" stroke={bezelC} strokeWidth="0.8" />

      {/* Face */}
      <circle cx={CX} cy={CY} r={R} fill={`url(#${gradId})`} />

      {/* Inner shadow ring */}
      <circle cx={CX} cy={CY} r={R - 0.5} fill="none"
        stroke={day ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.02)'} strokeWidth="2" />

      {/* Tick marks */}
      {ticks.map((t, i) => (
        <line key={i}
          x1={t.ix} y1={t.iy} x2={t.ox} y2={t.oy}
          stroke={t.isQtr ? ringColor : t.isHour ? tickMajor : tickMinor}
          strokeWidth={t.isQtr ? 1.8 : t.isHour ? 1.2 : 0.65}
          strokeLinecap="round"
        />
      ))}

      {/* Quarter numerals */}
      {qtrLabels.map(({ a, label }) => {
        const rad = (a - 90) * Math.PI / 180;
        const nr  = R - 12;
        return (
          <text key={a}
            x={CX + nr * Math.cos(rad)}
            y={CY + nr * Math.sin(rad) + 3}
            textAnchor="middle"
            fill={numeralC}
            fontFamily="JetBrains Mono, monospace"
            fontSize={W <= 80 ? 6 : 7}
            fontWeight="600"
          >
            {label}
          </text>
        );
      })}

      {/* Hour hand */}
      <line x1={CX} y1={CY} x2={hx} y2={hy}
        stroke={hourHand} strokeWidth={2.8} strokeLinecap="round"
        filter={`url(#${shadowId})`} />

      {/* Minute hand */}
      <line x1={CX} y1={CY} x2={mx} y2={my}
        stroke={minHand} strokeWidth={2} strokeLinecap="round"
        filter={`url(#${shadowId})`} />

      {/* Second hand */}
      <line x1={stx} y1={sty} x2={sx} y2={sy}
        stroke={CK.amber} strokeWidth="0.9" strokeLinecap="round" />

      {/* Center cap */}
      <circle cx={CX} cy={CY} r={4} fill={ringColor} />
      <circle cx={CX} cy={CY} r={2.2} fill={day ? '#0D0F18' : '#ECEFF6'} />
    </svg>
  );
}

/* ══════════════════════════════════════════════════════════════════
   DAY/NIGHT BADGE — small sun/moon icon
   ══════════════════════════════════════════════════════════════════ */
function DayNightBadge({ localHour }) {
  const day = isDay(localHour);
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 2,
      fontFamily: 'JetBrains Mono, monospace',
      fontSize: 7.5, color: day ? CK.amber : CK.muted2,
      fontWeight: 600, letterSpacing: '0.06em',
    }}>
      {day
        ? <svg width="8" height="8" viewBox="0 0 24 24" fill="none">
            <circle cx="12" cy="12" r="4" fill={CK.amber} />
            {[0,45,90,135,180,225,270,315].map((a,i) => {
              const r = Math.PI * a / 180;
              return <line key={i}
                x1={12+7*Math.cos(r)} y1={12+7*Math.sin(r)}
                x2={12+10*Math.cos(r)} y2={12+10*Math.sin(r)}
                stroke={CK.amber} strokeWidth="2" strokeLinecap="round" />;
            })}
          </svg>
        : <svg width="8" height="8" viewBox="0 0 24 24" fill="none">
            <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" fill={CK.muted2} />
          </svg>
      }
      {day ? 'DAY' : 'NIGHT'}
    </div>
  );
}

/* ══════════════════════════════════════════════════════════════════
   CLOCK CARD
   ══════════════════════════════════════════════════════════════════ */
function ClockCard({ city, now, utcHour, index, analogMode }) {
  const { hh, mm, ss, date, localHour } = localTime(now, city.offset);
  const status  = getCityStatus(utcHour, city);
  const diff    = dayDiff(now, date);
  const session = getSessionForHour(utcHour);

  let ringColor, pillColor, pillLabel;
  if (city.isLocal) {
    ringColor = CK.blue; pillColor = CK.blue; pillLabel = 'YOUR TIME';
  } else {
    switch (status) {
      case 'PEAK':
        pillLabel = 'PEAK';
        ringColor = session.key === 'OVERLAP' ? CK.red : CK.amber;
        pillColor = ringColor;
        break;
      case 'OPEN':
        pillLabel = 'OPEN';
        ringColor = CK.green; pillColor = CK.green;
        break;
      default:
        pillLabel = 'CLOSED';
        ringColor = CK.gray; pillColor = CK.gray;
    }
  }

  /* Compact sizes */
  const minW = city.isLocal
    ? (analogMode ? 106 : 96)
    : (analogMode ? 96  : 86);

  return (
    <div
      className="clock-card-enter"
      style={{
        minWidth: minW,
        padding: analogMode ? '7px 8px 9px' : '7px 10px',
        background: CK.panel,
        borderRadius: 10,
        border: `1px solid ${ringColor}30`,
        boxShadow: `0 0 0 1px ${ringColor}18, 0 0 14px -4px ${ringColor}22`,
        transition: 'box-shadow 0.5s ease, border-color 0.5s ease',
        display: 'flex', flexDirection: 'column', alignItems: 'center',
        gap: analogMode ? 4 : 3,
        flexShrink: 0,
        animationDelay: `${index * 50}ms`,
        position: 'relative',
      }}
    >
      {/* Day/night badge — top-right */}
      <div style={{ position: 'absolute', top: 4, right: 5 }}>
        <DayNightBadge localHour={localHour} />
      </div>

      {/* Flag */}
      <span style={{ fontSize: analogMode ? 12 : 14, lineHeight: 1, marginTop: 1 }}>
        {city.flag}
      </span>

      {/* Clock face */}
      {analogMode ? (
        <AnalogClock
          hh={hh} mm={mm} ss={ss}
          localHour={localHour}
          ringColor={city.isLocal ? CK.blue : ringColor}
          size={city.isLocal ? 84 : 76}
        />
      ) : (
        <div
          key={`${hh}${mm}${ss}`}
          className="clock-digit-tick"
          style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 17, fontWeight: 600,
            color: city.isLocal ? CK.blue : CK.ink,
            letterSpacing: '-0.02em',
            lineHeight: 1,
            marginTop: 1,
          }}
        >
          {hh}:{mm}
          <span style={{ fontSize: 10, opacity: 0.5, color: CK.muted }}>:{ss}</span>
        </div>
      )}

      {/* Day diff */}
      {diff && (
        <div style={{
          fontFamily: 'JetBrains Mono, monospace',
          fontSize: 7, color: CK.muted2,
          letterSpacing: '0.06em', lineHeight: 1,
          background: CK.muted2 + '12',
          border: `1px solid ${CK.muted2}18`,
          borderRadius: 2, padding: '1px 4px',
        }}>
          {diff}
        </div>
      )}

      {/* City name */}
      <div style={{
        fontFamily: 'JetBrains Mono, monospace',
        fontSize: 8, color: CK.muted,
        letterSpacing: '0.12em', textTransform: 'uppercase', lineHeight: 1,
      }}>
        {city.city}
      </div>

      {/* Status pill */}
      <div style={{
        fontFamily: 'JetBrains Mono, monospace',
        fontSize: 8, fontWeight: 600, letterSpacing: '0.08em',
        color: pillColor,
        background: pillColor + '14',
        border: `1px solid ${pillColor}28`,
        padding: '1px 5px', borderRadius: 3,
        lineHeight: 1.4, textTransform: 'uppercase',
      }}>
        {pillLabel}
      </div>
    </div>
  );
}

/* ══════════════════════════════════════════════════════════════════
   SESSION BANNER + MODE TOGGLE
   ══════════════════════════════════════════════════════════════════ */
function SessionBanner({ session, analogMode, onToggle }) {
  const isRed = session.key === 'OVERLAP';
  const c     = session.color;

  const bgMap = {
    OVERLAP:       'rgba(255,92,119,0.09)',
    US_SESSION:    'rgba(247,166,0,0.05)',
    EU_SESSION:    'rgba(247,166,0,0.05)',
    ASIAN_SESSION: 'rgba(46,228,155,0.05)',
    DEAD_ZONE:     'rgba(107,114,128,0.04)',
  };
  const borderMap = {
    OVERLAP:       'rgba(255,92,119,0.25)',
    US_SESSION:    'rgba(247,166,0,0.16)',
    EU_SESSION:    'rgba(247,166,0,0.16)',
    ASIAN_SESSION: 'rgba(46,228,155,0.16)',
    DEAD_ZONE:     'rgba(107,114,128,0.10)',
  };

  return (
    <div
      className={isRed ? 'session-pulse' : ''}
      style={{
        width: '100%',
        padding: '5px 16px',
        background: bgMap[session.key] || bgMap.DEAD_ZONE,
        borderBottom: `1px solid ${borderMap[session.key] || borderMap.DEAD_ZONE}`,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        gap: 12, flexWrap: 'wrap',
        transition: 'background 0.8s ease',
      }}
    >
      {/* Left: dot + name */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
        <div style={{
          width: 5, height: 5, borderRadius: 2.5,
          background: c, boxShadow: `0 0 7px ${c}`,
          flexShrink: 0,
          animation: isRed ? 'glow-pulse 1.4s ease-in-out infinite' : 'none',
        }} />
        <span style={{
          fontFamily: 'JetBrains Mono, monospace',
          fontSize: 11, fontWeight: 700, color: c, letterSpacing: '-0.01em',
        }}>
          {session.name}
        </span>
      </div>

      {/* Right: rec + toggle */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
        <span style={{
          fontFamily: 'JetBrains Mono, monospace',
          fontSize: 10, color: CK.muted, letterSpacing: '0.02em',
        }}>
          {session.rec}
        </span>

        <div className="st-clock-toggle" onClick={onToggle} title="Toggle analog / digital">
          {['ANA', 'DIG'].map(mode => {
            const active = (mode === 'ANA') === analogMode;
            return (
              <button key={mode} className="st-clock-toggle-btn" style={{
                background: active ? `${CK.amber}1E` : 'transparent',
                color:      active ? CK.amber : CK.muted2,
                border:     active ? `1px solid ${CK.amber}44` : '1px solid transparent',
              }}>
                {mode}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

/* ══════════════════════════════════════════════════════════════════
   MARKET CLOCK — root component
   Props:
     overrideUtcHour  {number|null}  — force UTC hour (test only)
   ══════════════════════════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════════════════
   NEXT FUNDING — countdown to Bybit's 8h funding (00 / 08 / 16 UTC).
   Funding flips move the whole perp market, so it's a real signal.
   ══════════════════════════════════════════════════════════════════ */
function FundingCell({ now }) {
  const secsNow = now.getUTCHours() * 3600 + now.getUTCMinutes() * 60 + now.getUTCSeconds();
  const period  = 8 * 3600;
  const diff    = period - (secsNow % period);   // seconds to next 8h boundary
  const hh = Math.floor(diff / 3600), mm = Math.floor((diff % 3600) / 60), ss = diff % 60;
  const soon = diff < 1800;                       // within 30 min
  const c = soon ? CK.red : CK.green;
  return (
    <div style={{
      marginLeft: 'auto',
      display: 'flex', flexDirection: 'column', alignItems: 'flex-end',
      justifyContent: 'center', gap: 3,
      paddingLeft: 12, borderLeft: `1px solid ${CK.border}`,
      flexShrink: 0, alignSelf: 'center',
    }}>
      <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 8, color: CK.muted2, letterSpacing: '0.14em', textTransform: 'uppercase' }}>
        NEXT FUNDING
      </div>
      <div className={soon ? 'session-pulse' : ''} style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 15, fontWeight: 600, color: c, letterSpacing: '-0.01em', lineHeight: 1 }}>
        {pad2(hh)}:{pad2(mm)}:{pad2(ss)}
      </div>
      <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 7.5, color: CK.muted2, letterSpacing: '0.06em' }}>
        8H CYCLE · 00/08/16 UTC
      </div>
    </div>
  );
}

function MarketClock({ overrideUtcHour = null }) {
  const [now, setNow] = React.useState(() => new Date());

  const [analogMode, setAnalogMode] = React.useState(() => {
    try { return localStorage.getItem('st_clock_mode') === 'analog'; }
    catch (_) { return false; }
  });

  React.useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);

  const toggleMode = React.useCallback(() => {
    setAnalogMode(prev => {
      const next = !prev;
      try { localStorage.setItem('st_clock_mode', next ? 'analog' : 'digital'); }
      catch (_) {}
      return next;
    });
  }, []);

  const displayNow = React.useMemo(() => {
    if (overrideUtcHour == null) return now;
    const d = new Date(now);
    d.setUTCHours(overrideUtcHour, d.getUTCMinutes(), d.getUTCSeconds(), 0);
    return d;
  }, [now, overrideUtcHour]);

  const utcHour = displayNow.getUTCHours();
  const session = getSessionForHour(utcHour);
  const cities  = getCities(displayNow);

  const utcStr = `${pad2(displayNow.getUTCHours())}:${pad2(displayNow.getUTCMinutes())}:${pad2(displayNow.getUTCSeconds())}`;

  return (
    <div style={{
      background: CK.bg,
      borderBottom: `1px solid ${CK.border}`,
      fontFamily: 'Geist, system-ui, sans-serif',
      userSelect: 'none',
      flexShrink: 0,   /* ← never compress the chart below */
    }}>
      {/* Session banner */}
      <SessionBanner session={session} analogMode={analogMode} onToggle={toggleMode} />

      {/* Clocks row */}
      <div
        className="st-clocks-row"
        style={{
          padding: '5px 16px 7px',
          display: 'flex', alignItems: 'flex-start',
          gap: 6,
          overflowX: 'auto',
          scrollbarWidth: 'thin',
          scrollbarColor: `${CK.border} transparent`,
        }}
      >
        {cities.map((city, i) => (
          <ClockCard
            key={city.id}
            city={city}
            now={displayNow}
            utcHour={utcHour}
            index={i}
            analogMode={analogMode}
          />
        ))}

        {/* NEXT FUNDING countdown — fills the gap before UTC */}
        <FundingCell now={displayNow} />

        {/* UTC reference — far right */}
        <div style={{
          marginLeft: 14,
          display: 'flex', flexDirection: 'column', alignItems: 'flex-end',
          justifyContent: 'center', gap: 3,
          paddingLeft: 12,
          borderLeft: `1px solid ${CK.border}`,
          flexShrink: 0,
          alignSelf: 'center',
        }}>
          <div style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 8, color: CK.muted2, letterSpacing: '0.14em',
            textTransform: 'uppercase',
          }}>
            UTC · LIVE
          </div>
          <div style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 15, fontWeight: 600, color: CK.amber,
            letterSpacing: '-0.01em', lineHeight: 1,
          }}>
            {utcStr}
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <div style={{
              width: 4, height: 4, borderRadius: 2,
              background: session.color, boxShadow: `0 0 5px ${session.color}`,
            }} />
            <span style={{
              fontFamily: 'JetBrains Mono, monospace',
              fontSize: 8, color: session.color,
              fontWeight: 600, letterSpacing: '0.06em',
            }}>
              {session.dangerLevel}
            </span>
          </div>
          <div style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 7.5, color: CK.muted2, letterSpacing: '0.08em',
          }}>
            threshold {session.threshold}
          </div>
        </div>
      </div>
    </div>
  );
}

window.MarketClock    = MarketClock;
window.getSessionForHour = getSessionForHour;
