Stock-Tool/ui_mockup.html

1246 lines
80 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verimund — UI Mockup</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0a0a0a;
--bg2: #111111;
--bg3: #181818;
--border: #222222;
--fg: #ffffff;
--fg2: #888888;
--fg3: #3a3a3a;
--positive: #4ade80;
--negative: #f87171;
--warning: #fbbf24;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg); color: var(--fg);
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
font-size: 13px; height: 100vh; overflow: hidden;
-webkit-font-smoothing: antialiased;
}
.app { display: flex; height: 100vh; }
/* ── SIDEBAR ─────────────────────────────────── */
.sidebar {
width: 72px; background: var(--bg2);
border-right: 1px solid var(--border);
display: flex; flex-direction: column; align-items: center;
padding: 16px 0 12px; flex-shrink: 0; z-index: 10;
}
.sidebar-logo {
width: 36px; height: 36px; background: var(--fg); color: var(--bg);
border-radius: 8px; display: flex; align-items: center; justify-content: center;
font-weight: 900; font-size: 15px; margin-bottom: 28px;
letter-spacing: -0.03em; user-select: none;
}
.sidebar-nav { display: flex; flex-direction: column; gap: 2px; width: 100%; padding: 0 8px; flex: 1; }
.nav-item {
display: flex; flex-direction: column; align-items: center; gap: 5px;
padding: 9px 0; border-radius: 8px; cursor: pointer; color: var(--fg3);
transition: color 0.15s; position: relative; user-select: none;
}
.nav-item:hover { color: var(--fg2); }
.nav-item.active { color: var(--fg); }
.nav-item.active::before {
content: ''; position: absolute; left: -8px; top: 50%; transform: translateY(-50%);
width: 3px; height: 22px; background: var(--fg); border-radius: 0 2px 2px 0;
}
.nav-icon { font-size: 17px; line-height: 1; }
.nav-label { font-size: 10px; font-weight: 500; letter-spacing: 0.02em; }
.sidebar-bottom { padding: 0 8px; width: 100%; }
/* ── MAIN ──────────────────────────────────────── */
.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.page { display: none; flex: 1; flex-direction: column; overflow: hidden; min-height: 0; }
.page.active { display: flex; }
/* ── TOOLBAR ───────────────────────────────────── */
.toolbar {
padding: 10px 16px; border-bottom: 1px solid var(--border);
background: var(--bg2); flex-shrink: 0;
display: flex; align-items: center; gap: 8px;
}
.toolbar-row { display: contents; }
/* Pill groups */
.pill-group {
display: inline-flex; align-items: stretch;
border: 1px solid var(--border); border-radius: 8px;
overflow: hidden;
}
.pill-btn {
display: flex; align-items: center; gap: 6px;
padding: 6px 14px; font-size: 12px; font-weight: 600;
cursor: pointer; border: none; background: transparent;
color: var(--fg2); white-space: nowrap; font-family: inherit;
border-right: 1px solid var(--border); transition: background 0.12s, color 0.12s;
}
.pill-btn:last-child { border-right: none; }
.pill-btn:hover { background: rgba(255,255,255,0.04); color: var(--fg); }
.pill-btn.run {
background: var(--fg); color: var(--bg); font-weight: 700; letter-spacing: 0.01em;
}
.pill-btn.run:hover { opacity: 0.88; background: var(--fg); }
.pill-btn.stop { color: var(--fg3); cursor: not-allowed; opacity: 0.4; }
select.pill-sel {
-webkit-appearance: none; appearance: none;
background: transparent;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%23555'/%3E%3C/svg%3E");
background-repeat: no-repeat; background-position: right 9px center;
color: var(--fg2); border: none;
border-right: 1px solid var(--border);
padding: 6px 26px 6px 12px; font-size: 12px;
cursor: pointer; outline: none; font-family: inherit;
min-width: 80px; transition: color 0.12s;
}
select.pill-sel:last-child { border-right: none; }
select.pill-sel:hover { color: var(--fg); }
select.pill-sel option { background: #1a1a1a; color: var(--fg); }
.pill-solo {
display: inline-flex; align-items: center; gap: 6px;
padding: 6px 13px; border: 1px solid var(--border); border-radius: 8px;
font-size: 12px; font-weight: 500; color: var(--fg2); cursor: pointer;
white-space: nowrap; transition: color 0.12s, border-color 0.12s;
}
.pill-solo:hover { color: var(--fg); border-color: #444; }
.toolbar-spacer { flex: 1; }
.toolbar-ts { font-size: 11px; color: var(--fg3); white-space: nowrap; margin-left: auto; }
/* ── PROGRESS ──────────────────────────────────── */
.progress-wrap { height: 2px; background: var(--border); flex-shrink: 0; }
.progress-fill { height: 100%; background: var(--fg); }
/* ── CONTENT SPLIT ─────────────────────────────── */
.content-split { display: flex; flex: 1; overflow: hidden; min-height: 0; }
/* ── STOCK LIST ────────────────────────────────── */
.stock-list {
width: 310px; flex-shrink: 0; border-right: 1px solid var(--border);
display: flex; flex-direction: column; overflow: hidden;
}
.list-header {
padding: 10px 16px 8px; display: flex; align-items: center; justify-content: space-between;
flex-shrink: 0; border-bottom: 1px solid var(--border);
}
.list-header-title { font-size: 10px; font-weight: 700; color: var(--fg2); text-transform: uppercase; letter-spacing: 0.08em; }
.list-header-count { font-size: 11px; color: var(--fg3); }
.stock-table-scroll { flex: 1; overflow-y: auto; }
.stock-table-scroll::-webkit-scrollbar { width: 4px; }
.stock-table-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
table.stocks { width: 100%; border-collapse: collapse; }
table.stocks thead th {
padding: 6px 14px; text-align: left; font-size: 10px; font-weight: 700;
color: var(--fg3); text-transform: uppercase; letter-spacing: 0.06em;
border-bottom: 1px solid var(--border); background: var(--bg); position: sticky; top: 0; z-index: 1;
}
table.stocks thead th.r { text-align: right; }
table.stocks tbody tr { cursor: pointer; transition: background 0.1s; }
table.stocks tbody tr:nth-child(even) { background: rgba(255,255,255,0.02); }
table.stocks tbody tr:hover { background: #1c1c1c; }
table.stocks tbody tr.selected { background: #1a1a1a; }
table.stocks tbody tr.selected td:first-child { border-left: 2px solid var(--fg); padding-left: 12px; }
table.stocks tbody td { padding: 8px 14px; font-size: 12px; vertical-align: middle; }
table.stocks tbody td.num { color: var(--fg3); font-size: 11px; width: 28px; }
table.stocks tbody td.ticker { font-weight: 700; font-size: 13px; width: 52px; }
table.stocks tbody td.name { color: var(--fg2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px; }
table.stocks tbody td.score-cell { text-align: right; width: 36px; font-weight: 700; font-size: 13px; }
.score-hi { color: var(--positive); }
.score-mid { color: var(--fg); }
.score-lo { color: var(--fg2); }
/* ── DETAIL PANEL ──────────────────────────────── */
.detail-panel { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.detail-empty { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--fg3); font-size: 14px; }
.detail-filled { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
.detail-header { padding: 14px 20px 0; flex-shrink: 0; }
.detail-ticker-row { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.detail-ticker { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; }
.detail-name { font-size: 14px; color: var(--fg2); }
.detail-sector { font-size: 12px; color: var(--fg3); }
.detail-tabs {
display: flex; padding: 0 20px; border-bottom: 1px solid var(--border);
margin-top: 10px; flex-shrink: 0; overflow-x: auto;
}
.detail-tabs::-webkit-scrollbar { display: none; }
.dtab {
padding: 8px 13px; font-size: 12px; font-weight: 500; color: var(--fg3);
cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px;
transition: color 0.15s; white-space: nowrap; user-select: none;
}
.dtab:hover { color: var(--fg2); }
.dtab.active { color: var(--fg); border-bottom-color: var(--fg); }
.detail-body { flex: 1; overflow-y: auto; padding: 16px 20px; }
.detail-body::-webkit-scrollbar { width: 4px; }
.detail-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
.tab-pane { display: none; }
.tab-pane.active { display: block; }
/* Chart tab fills all available height, no scroll needed */
.tab-pane.chart-tab { display: none; flex-direction: column; height: 100%; }
.tab-pane.chart-tab.active { display: flex; }
.detail-body:has(.chart-tab.active) { padding: 0; overflow: hidden; }
.chart-wrap { display: flex; flex-direction: column; flex: 1; height: 100%; }
.chart-wrap canvas { display: block; width: 100%; flex: 1; min-height: 0; }
/* ── METRICS GRID ──────────────────────────────── */
.metrics-grid {
display: grid; grid-template-columns: 1fr 1fr;
gap: 1px; background: var(--border);
border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
margin-bottom: 2px;
}
.metrics-grid.cols3 { grid-template-columns: 1fr 1fr 1fr; }
.mc { background: var(--bg2); padding: 12px 14px; }
.mc-label { font-size: 10px; color: var(--fg3); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 5px; }
.mc-val { font-size: 15px; font-weight: 600; cursor: default; }
.mc-val.pos { color: var(--positive); }
.mc-val.neg { color: var(--negative); }
.mc-val.muted { color: var(--fg2); }
.mc-sub { font-size: 11px; color: var(--fg3); margin-top: 2px; }
.mc-sub.pos { color: var(--positive); }
.mc-sub.neg { color: var(--negative); }
/* Span full row in a 2-col grid */
.mc.span2 { grid-column: 1 / -1; }
.section-hd { font-size: 10px; font-weight: 700; color: var(--fg3); text-transform: uppercase; letter-spacing: 0.08em; margin: 0 0 10px; }
/* ── TOOLTIP ───────────────────────────────────── */
#tooltip {
position: fixed; z-index: 9999; pointer-events: none;
background: #1c1c1c; border: 1px solid #333;
border-radius: 8px; padding: 10px 13px;
max-width: 210px; opacity: 0; transition: opacity 0.1s;
box-shadow: 0 8px 32px rgba(0,0,0,0.6);
}
#tooltip.visible { opacity: 1; }
.tip-title { font-size: 12px; font-weight: 700; color: var(--fg); margin-bottom: 5px; }
.tip-divider { height: 1px; background: var(--border); margin-bottom: 7px; }
.tip-desc { font-size: 11px; color: var(--fg2); line-height: 1.55; margin-bottom: 4px; }
.tip-context { display: none !important; }
.tip-context span.hi { color: var(--positive); }
.tip-context span.lo { color: var(--negative); }
.tip-context span.warn { color: var(--warning); }
/* ── STATUS BAR ────────────────────────────────── */
.status-bar {
display: flex; align-items: center; justify-content: space-between;
padding: 5px 20px; border-top: 1px solid var(--border);
background: var(--bg2); flex-shrink: 0;
}
.status-l, .status-r { font-size: 11px; color: var(--fg3); }
/* ── ANALYST COMMENTARY ────────────────────────── */
.commentary-box {
background: var(--bg3); border: 1px solid var(--border);
border-radius: 8px; padding: 14px 16px; margin-top: 16px;
}
.commentary-hd {
font-size: 10px; font-weight: 700; color: var(--fg3);
text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 12px;
display: flex; align-items: center; gap: 8px;
}
.verdict-pill {
display: inline-block; background: rgba(74,222,128,0.12); color: var(--positive);
padding: 2px 10px; border-radius: 4px; font-size: 11px; font-weight: 700; text-transform: none;
}
.comm-section { margin-bottom: 12px; }
.comm-title { font-size: 11px; font-weight: 700; color: var(--fg); margin-bottom: 4px; }
.comm-text { font-size: 12px; color: var(--fg2); line-height: 1.65; }
.comm-text ul { margin-left: 14px; }
.comm-text li { margin-bottom: 2px; }
.comm-link { color: var(--fg2); text-decoration: underline; cursor: pointer; }
.comm-pos { color: var(--positive); }
.comm-neg { color: var(--negative); }
/* ── CHART ─────────────────────────────────────── */
.chart-wrap { background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.chart-wrap canvas { cursor: crosshair; }
.chart-period-bar { display: flex; gap: 4px; padding: 10px 14px; border-bottom: 1px solid var(--border); }
/* Chart hover tooltip */
#chart-tip {
position: fixed; z-index: 9998; pointer-events: none;
background: #1c1c1c; border: 1px solid #333; border-radius: 8px;
padding: 9px 13px; min-width: 148px;
box-shadow: 0 8px 24px rgba(0,0,0,0.7);
opacity: 0; transition: opacity 0.08s;
}
#chart-tip.visible { opacity: 1; }
.ctip-date { font-size: 11px; color: var(--fg3); margin-bottom: 5px; }
.ctip-price { font-size: 14px; font-weight: 700; color: var(--fg); }
.ctip-chg { font-size: 11px; margin-top: 2px; }
.ctip-vol { font-size: 11px; color: var(--fg3); margin-top: 3px; }
.period-btn {
padding: 3px 10px; border-radius: 4px; font-size: 11px; cursor: pointer;
border: 1px solid var(--border); color: var(--fg3); background: transparent; transition: all 0.1s;
}
.period-btn:hover { color: var(--fg2); }
.period-btn.active { border-color: var(--fg2); color: var(--fg); background: rgba(255,255,255,0.05); }
/* ── SEARCH PAGE ───────────────────────────────── */
.search-idle {
flex: 1; display: flex; flex-direction: column;
align-items: center; justify-content: center;
}
.search-title { font-size: 26px; font-weight: 800; letter-spacing: -0.03em; margin-bottom: 28px; }
.search-bar-row { display: flex; gap: 8px; width: 480px; max-width: 90%; }
.search-input {
flex: 1; background: var(--bg3); color: var(--fg); border: 1px solid var(--border);
border-radius: 8px; padding: 11px 16px; font-size: 14px; outline: none; font-family: inherit;
}
.search-input:focus { border-color: var(--fg3); }
.btn-search {
padding: 11px 22px; background: var(--fg); color: var(--bg);
border: none; border-radius: 8px; font-size: 13px; font-weight: 600;
cursor: pointer; font-family: inherit;
}
.search-hint { margin-top: 10px; font-size: 12px; color: var(--fg3); }
/* ── TRACKING ──────────────────────────────────── */
.tracking-subnav {
display: flex; gap: 8px; padding: 11px 16px;
border-bottom: 1px solid var(--border); background: var(--bg2); flex-shrink: 0;
}
.snav-btn {
padding: 5px 16px; border-radius: 6px; font-size: 12px; font-weight: 500;
cursor: pointer; border: 1px solid var(--border); color: var(--fg3);
background: transparent; transition: all 0.1s; font-family: inherit;
}
.snav-btn.active { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.tracking-toolbar {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
padding: 9px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.tr-label { font-size: 12px; font-weight: 600; color: var(--fg2); margin-right: 4px; }
.tr-sep { width: 1px; height: 16px; background: var(--border); margin: 0 4px; }
.tperiod-btn {
padding: 3px 9px; border-radius: 4px; font-size: 11px; cursor: pointer;
border: 1px solid transparent; color: var(--fg3); background: transparent;
}
.tperiod-btn.active { border-color: var(--fg3); color: var(--fg); }
.btn-refresh {
margin-left: auto; padding: 4px 12px; border-radius: 4px; font-size: 11px;
cursor: pointer; border: 1px solid var(--border); color: var(--fg2);
background: transparent; font-family: inherit;
}
.tr-status { font-size: 11px; color: var(--fg3); }
.tracking-table-scroll { flex: 1; overflow-y: auto; }
.tracking-table-scroll::-webkit-scrollbar { width: 4px; }
.tracking-table-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
table.tr-table { width: 100%; border-collapse: collapse; }
table.tr-table thead th {
padding: 6px 14px; text-align: left; font-size: 10px; font-weight: 700; color: var(--fg3);
text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--border);
background: var(--bg); position: sticky; top: 0; z-index: 1;
}
table.tr-table thead th.r { text-align: right; }
table.tr-table tbody tr { cursor: pointer; }
table.tr-table tbody tr:nth-child(even) { background: rgba(255,255,255,0.02); }
table.tr-table tbody tr:hover { background: #1c1c1c; }
table.tr-table tbody td { padding: 8px 14px; font-size: 12px; }
table.tr-table tbody td.r { text-align: right; }
table.tr-table tbody td.muted { color: var(--fg2); }
table.tr-table tbody td.dimmed { color: var(--fg3); }
.type-buy { color: var(--positive); font-weight: 600; }
.type-sale { color: var(--negative); font-weight: 600; }
.type-award { color: var(--warning); font-weight: 600; }
.tpage { display: none; flex: 1; flex-direction: column; overflow: hidden; min-height: 0; }
.tpage.active { display: flex; }
</style>
</head>
<body>
<!-- ── TOOLTIP ──────────────────────────────────── -->
<div id="tooltip">
<div class="tip-title" id="tip-title"></div>
<div class="tip-divider"></div>
<div class="tip-desc" id="tip-desc"></div>
<div class="tip-context" id="tip-context"></div>
</div>
<!-- ── CHART HOVER TIP ───────────────────────────── -->
<div id="chart-tip">
<div class="ctip-date" id="ctip-date"></div>
<div class="ctip-price" id="ctip-price"></div>
<div class="ctip-chg" id="ctip-chg"></div>
<div class="ctip-vol" id="ctip-vol"></div>
</div>
<div class="app">
<!-- ── SIDEBAR ────────────────────────────────── -->
<div class="sidebar">
<div class="sidebar-logo">V</div>
<div class="sidebar-nav">
<div class="nav-item active" onclick="setPage('screener',this)">
<span class="nav-icon"></span><span class="nav-label">Screener</span>
</div>
<div class="nav-item" onclick="setPage('search',this)">
<span class="nav-icon"></span><span class="nav-label">Search</span>
</div>
<div class="nav-item" onclick="setPage('tracking',this)">
<span class="nav-icon"></span><span class="nav-label">Tracking</span>
</div>
</div>
<div class="sidebar-bottom">
<div class="nav-item" onclick="setPage('settings',this)">
<span class="nav-icon"></span><span class="nav-label">Settings</span>
</div>
</div>
</div>
<!-- ── MAIN ───────────────────────────────────── -->
<div class="main">
<!-- ══════════════ SCREENER PAGE ══════════════ -->
<div class="page active" id="page-screener">
<div class="toolbar">
<!-- Row 1: actions + universe filters -->
<div class="toolbar-row">
<div class="pill-group">
<button class="pill-btn run">&nbsp; Run</button>
<button class="pill-btn stop">&nbsp; Stop</button>
</div>
<div class="pill-group">
<select class="pill-sel">
<option>S&amp;P 500</option><option>Russell 2000</option>
<option>Nasdaq 100</option><option>Dow Jones 30</option>
</select>
<select class="pill-sel">
<option>All Sectors</option><option>Technology</option>
<option>Financials</option><option>Healthcare</option>
<option>Energy</option><option>Industrials</option>
</select>
</div>
</div>
<!-- Row 2: strategy + display + filters -->
<div class="toolbar-row">
<div class="pill-group">
<select class="pill-sel" style="min-width:110px">
<option>Balanced</option><option>Value</option>
<option>Growth</option><option>Momentum</option>
<option>Quality</option><option>Dividend</option>
<option>Custom…</option>
</select>
<select class="pill-sel" style="min-width:68px">
<option>100</option><option>200</option>
<option>300</option><option>500</option><option>All</option>
</select>
</div>
<div class="pill-solo">&nbsp; Filters</div>
<span class="toolbar-ts">Last run: 4 mins ago</span>
</div>
</div>
<div class="progress-wrap"><div class="progress-fill" style="width:100%"></div></div>
<div class="content-split">
<!-- Stock list -->
<div class="stock-list">
<div class="list-header">
<span class="list-header-title">Results</span>
<span class="list-header-count">87 stocks</span>
</div>
<div class="stock-table-scroll">
<table class="stocks">
<thead><tr><th>#</th><th>Ticker</th><th>Name</th><th class="r">Score</th></tr></thead>
<tbody id="stock-tbody"></tbody>
</table>
</div>
</div>
<!-- Detail panel -->
<div class="detail-panel">
<div class="detail-empty" id="detail-empty">← Select a stock to view details</div>
<div class="detail-filled" id="detail-filled" style="display:none">
<div class="detail-header">
<div class="detail-ticker-row">
<span class="detail-ticker" id="d-ticker"></span>
<span class="detail-name" id="d-name"></span>
<span class="detail-sector" id="d-sector"></span>
</div>
</div>
<div class="detail-tabs" id="detail-tabs">
<div class="dtab active" onclick="setTab('scores',this,'detail-tabs','detail-body')">Scores</div>
<div class="dtab" onclick="setTab('valuation',this,'detail-tabs','detail-body')">Valuation</div>
<div class="dtab" onclick="setTab('growth',this,'detail-tabs','detail-body')">Growth</div>
<div class="dtab" onclick="setTab('momentum',this,'detail-tabs','detail-body')">Momentum</div>
<div class="dtab" onclick="setTab('quality',this,'detail-tabs','detail-body')">Quality &amp; Profit</div>
<div class="dtab" onclick="setTab('analyst',this,'detail-tabs','detail-body')">Analyst</div>
<div class="dtab" onclick="setTab('chart',this,'detail-tabs','detail-body')">Chart</div>
</div>
<div class="detail-body" id="detail-body">
<!-- SCORES -->
<div class="tab-pane active" id="tab-scores">
<div class="metrics-grid span-first" style="grid-template-columns:1fr">
<div class="mc"
data-tip="Composite Score|Weighted aggregate of all 8 scoring factors — value, growth, momentum, quality, profitability, sentiment, analyst, and risk.|Higher is always better. 80+ = strong buy candidate. 50 = sector median."
>
<div class="mc-label">Composite Score</div>
<div class="mc-val pos" id="sc-composite">82</div>
<div class="mc-sub pos" id="sc-composite-tier">Excellent</div>
</div>
</div>
<div style="height:1px"></div>
<div class="metrics-grid" id="scores-grid">
<div class="mc" data-tip="Value Score|How cheaply the stock trades relative to its fundamentals — P/E, P/B, EV/EBITDA, EV/Revenue — all normalized against sector peers.|50 = sector median. Above 70 = attractively priced. Below 40 = expensive vs. peers.">
<div class="mc-label">Value</div>
<div class="mc-val" id="sc-value">54</div>
<div class="mc-sub" id="sc-value-tier">Moderate</div>
</div>
<div class="mc" data-tip="Growth Score|Revenue growth, earnings growth, and EPS expansion — all z-scored against sector peers and blended by strategy weight.|50 = sector median. Above 70 = top-quartile grower.">
<div class="mc-label">Growth</div>
<div class="mc-val" id="sc-growth">73</div>
<div class="mc-sub pos" id="sc-growth-tier">Strong</div>
</div>
<div class="mc" data-tip="Momentum Score|Price returns over 1M, 3M, 6M, and 12M, each weighted and z-scored against sector. Captures trend persistence.|50 = sector median. Scores above 75 indicate sustained relative outperformance.">
<div class="mc-label">Momentum</div>
<div class="mc-val" id="sc-momentum">62</div>
<div class="mc-sub" id="sc-momentum-tier">Moderate</div>
</div>
<div class="mc" data-tip="Quality Score|Balance sheet strength: ROA, ROE, debt-to-equity ratio, current ratio, and Piotroski F-Score (09 binary checklist).|50 = sector median. Piotroski 89 = financially sound. D/E normalized against sector type.">
<div class="mc-label">Quality</div>
<div class="mc-val" id="sc-quality">79</div>
<div class="mc-sub pos" id="sc-quality-tier">Strong</div>
</div>
<div class="mc" data-tip="Profitability Score|Operating margin, profit margin, FCF yield, and Sloan accruals ratio (measures earnings quality — cash-backed vs. accrual-based income).|50 = sector median. Negative accruals ratio = earnings well-backed by cash flow.">
<div class="mc-label">Profitability</div>
<div class="mc-val" id="sc-profit">65</div>
<div class="mc-sub" id="sc-profit-tier">Moderate</div>
</div>
<div class="mc" data-tip="Sentiment Score|News sentiment score (NLP on recent headlines) weighted by headline volume, combined with analyst consensus direction.|Low headline count reduces score confidence. Score above 70 = broadly positive narrative.">
<div class="mc-label">Sentiment</div>
<div class="mc-val" id="sc-sentiment">71</div>
<div class="mc-sub pos" id="sc-sentiment-tier">Strong</div>
</div>
<div class="mc" data-tip="Analyst Score|Analyst consensus recommendation strength, number of covering analysts, and % upside to consensus price target.|More analysts = higher confidence. Upside > 15% with Buy consensus = high score.">
<div class="mc-label">Analyst</div>
<div class="mc-val muted" id="sc-analyst">55</div>
<div class="mc-sub" id="sc-analyst-tier">Moderate</div>
</div>
<div class="mc" data-tip="Risk Score|Inverse of volatility and market beta. Higher score = lower risk profile. Short interest % of float also penalizes score.|Score above 70 = low-volatility, low-beta profile. Below 40 = elevated risk / high short interest.">
<div class="mc-label">Risk</div>
<div class="mc-val" id="sc-risk">68</div>
<div class="mc-sub" id="sc-risk-tier">Moderate</div>
</div>
</div>
</div>
<!-- VALUATION -->
<div class="tab-pane" id="tab-valuation">
<p class="section-hd">Valuation Metrics</p>
<div class="metrics-grid">
<div class="mc" data-tip="Price|Current last-traded market price per share.">
<div class="mc-label">Price</div><div class="mc-val">$213.49</div></div>
<div class="mc" data-tip="Market Capitalization|Total shares outstanding × current price. Determines index eligibility and institutional coverage.">
<div class="mc-label">Market Cap</div><div class="mc-val">$3.28T</div></div>
<div class="mc" data-tip="P/E Forward|Price divided by consensus forward 12-month EPS estimate. Primary valuation metric used in scoring.|Lower = cheaper. Sector median shown in score context.">
<div class="mc-label">P/E Forward</div><div class="mc-val">28.4×</div></div>
<div class="mc" data-tip="P/E Trailing|Price divided by trailing 12-month (TTM) actual earnings per share.|Useful for comparing to forward P/E — a large gap suggests analyst optimism.">
<div class="mc-label">P/E Trailing</div><div class="mc-val muted">32.1×</div></div>
<div class="mc" data-tip="P/B Ratio|Price divided by book value per share. High P/B is common for asset-light businesses with strong intangibles.">
<div class="mc-label">P/B Ratio</div><div class="mc-val">47.2×</div></div>
<div class="mc" data-tip="Book Value Per Share|Total shareholder equity divided by shares outstanding. Theoretical liquidation value per share.">
<div class="mc-label">Book Value</div><div class="mc-val muted">$4.52</div></div>
<div class="mc" data-tip="EV / EBITDA|Enterprise value divided by EBITDA. Capital-structure-neutral valuation — better than P/E for comparing companies with different leverage.">
<div class="mc-label">EV / EBITDA</div><div class="mc-val">22.3×</div></div>
<div class="mc" data-tip="EV / Revenue|Enterprise value divided by trailing revenue. Used for early-stage or low-margin companies where EBITDA is small or negative.">
<div class="mc-label">EV / Revenue</div><div class="mc-val">8.4×</div></div>
<div class="mc" data-tip="52-Week High|Highest intraday price over the trailing 52 weeks. Current price at 90% of 52W high.">
<div class="mc-label">52W High</div><div class="mc-val muted">$237.23</div></div>
<div class="mc" data-tip="52-Week Low|Lowest intraday price over the trailing 52 weeks. Current price is 30% above the 52W low.">
<div class="mc-label">52W Low</div><div class="mc-val muted">$164.08</div></div>
</div>
</div>
<!-- GROWTH -->
<div class="tab-pane" id="tab-growth">
<p class="section-hd">Growth Metrics</p>
<div class="metrics-grid">
<div class="mc" data-tip="Revenue Growth|Year-over-year change in trailing 12-month revenue. Sourced from EDGAR XBRL frames.|Above sector median contributes to a higher Growth score.">
<div class="mc-label">Revenue Growth</div><div class="mc-val pos">+4.2%</div></div>
<div class="mc" data-tip="Earnings Growth|Year-over-year change in trailing 12-month net income.|Compared against sector peers in z-score normalization.">
<div class="mc-label">Earnings Growth</div><div class="mc-val pos">+8.7%</div></div>
<div class="mc" data-tip="EPS Forward|Consensus analyst estimate for earnings per share over the next 12 months.|Used in forward P/E calculation and growth trajectory assessment.">
<div class="mc-label">EPS Forward</div><div class="mc-val">$7.52</div></div>
<div class="mc" data-tip="EPS Trailing|Actual earnings per share over the trailing 12 months (TTM).|Comparing to forward EPS: +13% implied growth expected by analysts.">
<div class="mc-label">EPS Trailing</div><div class="mc-val muted">$6.65</div></div>
</div>
</div>
<!-- MOMENTUM -->
<div class="tab-pane" id="tab-momentum">
<p class="section-hd">Price Returns</p>
<div class="metrics-grid">
<div class="mc" data-tip="1-Month Return|Total price return over the trailing 1 calendar month.|Short-term momentum signal. Weighted at 15% of the Momentum score.">
<div class="mc-label">1-Month Return</div><div class="mc-val pos">+3.2%</div></div>
<div class="mc" data-tip="3-Month Return|Total price return over the trailing 3 months.|Medium-term momentum. Weighted at 25% of the Momentum score.">
<div class="mc-label">3-Month Return</div><div class="mc-val neg">1.4%</div></div>
<div class="mc" data-tip="6-Month Return|Total price return over the trailing 6 months.|Primary momentum window. Weighted at 35% of the Momentum score.">
<div class="mc-label">6-Month Return</div><div class="mc-val pos">+8.9%</div></div>
<div class="mc" data-tip="12-Month Return|Total price return over the trailing 12 months.|Long-term momentum. Weighted at 25% of the Momentum score.">
<div class="mc-label">12-Month Return</div><div class="mc-val pos">+18.3%</div></div>
</div>
</div>
<!-- QUALITY & PROFIT -->
<div class="tab-pane" id="tab-quality">
<p class="section-hd">Income &amp; Cash Flow</p>
<div class="metrics-grid" style="margin-bottom:1px">
<div class="mc" data-tip="Revenue (TTM)|Trailing 12-month total revenue. Sum of 4 most recent quarters from EDGAR XBRL.|Minimum 4 quarters required — partial-year totals excluded to avoid distortion.">
<div class="mc-label">Revenue (TTM)</div><div class="mc-val">$391.0B</div></div>
<div class="mc" data-tip="Net Income|Trailing 12-month net income after tax. Revenue × net profit margin.">
<div class="mc-label">Net Income</div><div class="mc-val">$93.7B</div></div>
<div class="mc" data-tip="Operating Income|Earnings before interest and taxes (EBIT) over trailing 12 months.|Excludes one-time items. Better measure of recurring business profitability.">
<div class="mc-label">Operating Income</div><div class="mc-val">$108.9B</div></div>
<div class="mc" data-tip="Total Cash|Cash and short-term investments on the most recent balance sheet.|Apple holds $61.8B cash vs. $96.8B debt — net debt of $35.0B.">
<div class="mc-label">Total Cash</div><div class="mc-val">$61.8B</div></div>
</div>
<p class="section-hd" style="margin-top:14px">Balance Sheet</p>
<div class="metrics-grid" style="margin-bottom:1px">
<div class="mc" data-tip="Total Debt|Total short-term + long-term debt obligations from the most recent balance sheet.">
<div class="mc-label">Total Debt</div><div class="mc-val muted">$96.8B</div></div>
<div class="mc" data-tip="Total Equity|Total shareholder equity (assets minus liabilities). Derived from D/E ratio.|Note: Apple's equity is low relative to its earnings power — common for buyback-heavy companies.">
<div class="mc-label">Total Equity</div><div class="mc-val muted">$67.0B</div></div>
<div class="mc" data-tip="Current Ratio|Current assets divided by current liabilities. Below 1.0 means more short-term liabilities than assets.|Apple's 0.87 is below 1 — normal for a company with large supplier payables and predictable cash generation.">
<div class="mc-label">Current Ratio</div><div class="mc-val neg">0.87</div></div>
<div class="mc" data-tip="Debt / Equity Ratio|Total debt divided by total equity. Higher = more leveraged. Normalized against sector median in Quality scoring.|yFinance D/E is scaled (÷100) to match EDGAR ratio format before comparison.">
<div class="mc-label">D/E Ratio</div><div class="mc-val muted">1.44</div></div>
</div>
<p class="section-hd" style="margin-top:14px">Margins &amp; Returns</p>
<div class="metrics-grid">
<div class="mc" data-tip="Return on Equity|Net income divided by average shareholder equity. Apple's 147% reflects both high profitability and aggressive buybacks reducing equity base.">
<div class="mc-label">ROE</div><div class="mc-val pos">147.3%</div></div>
<div class="mc" data-tip="Return on Assets|Net income divided by total assets. Measures how efficiently management uses assets to generate profit.">
<div class="mc-label">ROA</div><div class="mc-val pos">22.1%</div></div>
<div class="mc" data-tip="Profit Margin|Net income as a percentage of revenue (TTM). Used in Profitability score z-scoring vs. sector.|$93.7B net income on $391.0B revenue.">
<div class="mc-label">Profit Margin</div><div class="mc-val pos">23.97%</div><div class="mc-sub">$93.7B net</div></div>
<div class="mc" data-tip="Operating Margin|Operating income as a percentage of revenue. Excludes tax and interest — pure business efficiency.|$108.9B operating income on $391.0B revenue.">
<div class="mc-label">Operating Margin</div><div class="mc-val pos">27.84%</div><div class="mc-sub">$108.9B op.</div></div>
<div class="mc" data-tip="Free Cash Flow Yield|Free cash flow (operating CF capex) divided by market cap. Measures cash generation relative to price.|3.8% FCF yield is moderate for a mega-cap. Sector median ~2.4%.">
<div class="mc-label">FCF Yield</div><div class="mc-val">3.8%</div></div>
<div class="mc" data-tip="Dividend Yield|Annual dividend per share divided by current price.|Apple pays $1.00/share annually. Yield is intentionally low — capital return is primarily via buybacks ($90B+ annually).">
<div class="mc-label">Dividend Yield</div><div class="mc-val muted">0.51%</div></div>
</div>
</div>
<!-- ANALYST -->
<div class="tab-pane" id="tab-analyst">
<p class="section-hd">Analyst &amp; Market Data</p>
<div class="metrics-grid">
<div class="mc" data-tip="Analyst Recommendation|Consensus buy/hold/sell rating aggregated across all covering analysts.|Buy consensus with 34 analysts = high-confidence signal.">
<div class="mc-label">Recommendation</div><div class="mc-val pos">Buy</div></div>
<div class="mc" data-tip="Analyst Count|Number of sell-side analysts actively covering this stock.|More analysts = higher signal confidence. &lt;5 analysts reduces the Analyst score weight.">
<div class="mc-label"># Analysts</div><div class="mc-val">34</div></div>
<div class="mc" data-tip="Consensus Price Target|Median analyst 12-month price target across all covering analysts.|$241.00 vs current $213.49 = 12.9% implied upside.">
<div class="mc-label">Price Target</div><div class="mc-val">$241.00</div></div>
<div class="mc" data-tip="Upside to Target|Percentage difference between consensus price target and current price.|(target / price 1) × 100. Positive = underpriced vs. analyst consensus.">
<div class="mc-label">Upside to Target</div><div class="mc-val pos">+12.9%</div></div>
<div class="mc" data-tip="News Sentiment|NLP sentiment score derived from recent news headlines, weighted by headline volume.|Range 01. Above 0.6 = broadly positive narrative. Score confidence scales with headline count.">
<div class="mc-label">News Sentiment</div><div class="mc-val">0.72</div></div>
<div class="mc" data-tip="Short Interest|Percentage of float currently sold short (shortPercentOfFloat from yFinance).|Low short interest (0.8%) = limited bearish positioning. Above 10% = meaningful headwind.">
<div class="mc-label">Short Interest</div><div class="mc-val muted">0.8%</div></div>
<div class="mc" data-tip="Beta|Sensitivity of the stock's returns to the broader market (S&P 500 = 1.0).|1.24 = ~24% more volatile than the market. Used in Risk score calculation.">
<div class="mc-label">Beta</div><div class="mc-val muted">1.24</div></div>
<div class="mc" data-tip="30-Day Volatility|Annualized standard deviation of daily returns over the trailing 30 calendar days.|22.4% annualized = roughly 1.4% expected daily move (±1 std dev).">
<div class="mc-label">30D Volatility</div><div class="mc-val muted">22.4%</div></div>
</div>
<div class="commentary-box">
<div class="commentary-hd">Analyst Commentary <span class="verdict-pill">Strong Buy</span></div>
<div class="comm-section">
<div class="comm-title">SUMMARY</div>
<div class="comm-text">Apple is a dominant consumer-tech franchise with exceptional cash generation and expanding services margin. Near-term headwinds from China exposure and a stretched P/E are offset by the compounding services flywheel and consistent capital return program.</div>
</div>
<div class="comm-section">
<div class="comm-title">INVESTMENT THESIS</div>
<div class="comm-text"><ul>
<li><span class="comm-pos">Services revenue accelerating</span> — App Store, Apple TV+, iCloud growing at 1215% YoY</li>
<li><span class="comm-pos">FCF machine</span> — $100B+ annual free cash flow funds buybacks and dividends</li>
<li><span class="comm-pos">ROE of 147%</span> indicates exceptional capital efficiency relative to peers</li>
<li>iPhone installed base of 1.4B provides structural defensibility</li>
</ul></div>
</div>
<div class="comm-section">
<div class="comm-title">RISK FACTORS</div>
<div class="comm-text"><ul>
<li><span class="comm-neg">China revenue (17% of total)</span> — regulatory and tariff exposure</li>
<li><span class="comm-neg">P/E of 32×</span> leaves limited margin of safety at current price</li>
<li>Hardware saturation risk in mature iPhone markets</li>
</ul></div>
</div>
<div class="comm-section">
<div class="comm-title">NEWS HIGHLIGHTS</div>
<div class="comm-text">
<span class="comm-pos">+</span> <span class="comm-link">Apple Intelligence features drive record upgrade cycle — Bloomberg</span><br>
<span class="comm-pos">+</span> <span class="comm-link">Services segment posts 14% growth beating estimates — Reuters</span><br>
<span class="comm-neg"></span> <span class="comm-link">DOJ widens antitrust probe into App Store fees — WSJ</span>
</div>
</div>
</div>
</div>
<!-- CHART -->
<div class="tab-pane chart-tab" id="tab-chart">
<div class="chart-wrap">
<div class="chart-period-bar" id="cpbar1">
<div class="period-btn">1M</div><div class="period-btn">3M</div>
<div class="period-btn active">6M</div><div class="period-btn">1Y</div>
<div class="period-btn">2Y</div><div class="period-btn">5Y</div>
</div>
<canvas id="price-chart"></canvas>
</div>
</div>
</div><!-- /detail-body -->
</div><!-- /detail-filled -->
</div><!-- /detail-panel -->
</div><!-- /content-split -->
<div class="status-bar">
<span class="status-l">Showing 87 of 500 stocks · Click a ticker to see details</span>
<span class="status-r">Cache: 4,200 stocks · updated 4 mins ago</span>
</div>
</div><!-- /screener page -->
<!-- ══════════════ SEARCH PAGE ══════════════ -->
<div class="page" id="page-search">
<div class="search-idle" id="search-idle">
<div class="search-title">Verimund Stock Tool</div>
<div class="search-bar-row">
<input class="search-input" type="text" placeholder="Search by ticker or company name…"
id="search-inp" onkeydown="if(event.key==='Enter')doSearch()">
<button class="btn-search" onclick="doSearch()">Search</button>
</div>
<div class="search-hint">Try: AAPL, NVDA, Microsoft, Tesla…</div>
</div>
<div class="detail-filled" id="search-result" style="display:none">
<div class="detail-header">
<div class="detail-ticker-row">
<span class="detail-ticker">NVDA</span>
<span class="detail-name">Nvidia Corp</span>
<span class="detail-sector">· Technology</span>
</div>
<div style="margin-bottom:4px">
<span style="font-size:11px;color:var(--fg3);cursor:pointer;border:1px solid var(--border);padding:3px 10px;border-radius:5px"
onclick="document.getElementById('search-idle').style.display='flex';document.getElementById('search-result').style.display='none'">← Back</span>
</div>
</div>
<div class="detail-tabs" id="search-tabs">
<div class="dtab active" onclick="setTab('scores2',this,'search-tabs','search-body')">Scores</div>
<div class="dtab" onclick="setTab('valuation2',this,'search-tabs','search-body')">Valuation</div>
<div class="dtab" onclick="setTab('growth2',this,'search-tabs','search-body')">Growth</div>
<div class="dtab" onclick="setTab('momentum2',this,'search-tabs','search-body')">Momentum</div>
<div class="dtab" onclick="setTab('quality2',this,'search-tabs','search-body')">Quality &amp; Profit</div>
<div class="dtab" onclick="setTab('analyst2',this,'search-tabs','search-body')">Analyst</div>
<div class="dtab" onclick="setTab('chart2',this,'search-tabs','search-body')">Chart</div>
</div>
<div class="detail-body" id="search-body">
<div class="tab-pane active" id="tab-scores2">
<div class="metrics-grid" style="grid-template-columns:1fr">
<div class="mc" data-tip="Composite Score|Weighted aggregate of all 8 scoring factors.|91/100 — Excellent. Top 5% of S&P 500 by composite rank.">
<div class="mc-label">Composite Score</div>
<div class="mc-val pos">91</div>
<div class="mc-sub pos">Excellent</div>
</div>
</div>
<div style="height:1px"></div>
<div class="metrics-grid">
<div class="mc" data-tip="Value Score|P/E, P/B, EV/EBITDA vs. sector peers.|42 — Below sector median. NVDA trades at a significant premium to the tech sector average, reflecting growth expectations.">
<div class="mc-label">Value</div><div class="mc-val neg">42</div><div class="mc-sub neg">Weak</div></div>
<div class="mc" data-tip="Growth Score|Revenue +122% YoY, earnings +581% YoY — extreme outlier vs. sector.|94 — Exceptional. Top 2% of universe.">
<div class="mc-label">Growth</div><div class="mc-val pos">94</div><div class="mc-sub pos">Exceptional</div></div>
<div class="mc" data-tip="Momentum Score|12M return +89.3%, 6M +38.7% — sustained outperformance.|88 — Strong. Multi-timeframe momentum alignment.">
<div class="mc-label">Momentum</div><div class="mc-val pos">88</div><div class="mc-sub pos">Strong</div></div>
<div class="mc" data-tip="Quality Score|ROE 123%, ROA 55%, low D/E ratio, strong Piotroski F-Score.|85 — Excellent balance sheet and capital efficiency.">
<div class="mc-label">Quality</div><div class="mc-val pos">85</div><div class="mc-sub pos">Excellent</div></div>
<div class="mc" data-tip="Profitability Score|48.9% profit margin, FCF yield 2.1%, strong accruals quality.|91 — Top-quartile profitability in the technology sector.">
<div class="mc-label">Profitability</div><div class="mc-val pos">91</div><div class="mc-sub pos">Exceptional</div></div>
<div class="mc" data-tip="Sentiment Score|Broadly positive news cycle, 62 analysts covering, strong buy consensus.|86 — Very positive sentiment across news and analyst community.">
<div class="mc-label">Sentiment</div><div class="mc-val pos">86</div><div class="mc-sub pos">Strong</div></div>
<div class="mc" data-tip="Analyst Score|62 analysts, Strong Buy consensus, $1,050 target = +19.9% upside.|92 — Deep coverage with very strong conviction.">
<div class="mc-label">Analyst</div><div class="mc-val pos">92</div><div class="mc-sub pos">Excellent</div></div>
<div class="mc" data-tip="Risk Score|Beta 1.71, elevated 30D volatility, significant drawdown risk if AI sentiment shifts.|44 — High-beta, high-volatility profile. Elevated risk for conservative portfolios.">
<div class="mc-label">Risk</div><div class="mc-val neg">44</div><div class="mc-sub neg">Elevated</div></div>
</div>
</div>
<div class="tab-pane" id="tab-valuation2">
<p class="section-hd">Valuation Metrics</p>
<div class="metrics-grid">
<div class="mc" data-tip="Price|Current last-traded market price per share."><div class="mc-label">Price</div><div class="mc-val">$875.40</div></div>
<div class="mc" data-tip="Market Capitalization|Total shares outstanding × current price."><div class="mc-label">Market Cap</div><div class="mc-val">$2.15T</div></div>
<div class="mc" data-tip="P/E Forward|38.2× — premium to sector but supported by +122% revenue growth."><div class="mc-label">P/E Forward</div><div class="mc-val">38.2×</div></div>
<div class="mc" data-tip="P/E Trailing|56.4× trailing — high, reflecting how fast earnings have grown."><div class="mc-label">P/E Trailing</div><div class="mc-val muted">56.4×</div></div>
<div class="mc" data-tip="EV / EBITDA|46.7× — elevated, justified by dominant AI accelerator position."><div class="mc-label">EV / EBITDA</div><div class="mc-val">46.7×</div></div>
<div class="mc" data-tip="P/B Ratio|54.1× — asset-light GPU design company; book value understates true value."><div class="mc-label">P/B Ratio</div><div class="mc-val">54.1×</div></div>
<div class="mc" data-tip="52-Week High|$974.00 — current price is 10% below 52W high."><div class="mc-label">52W High</div><div class="mc-val muted">$974.00</div></div>
<div class="mc" data-tip="52-Week Low|$462.17 — current price is 89% above 52W low."><div class="mc-label">52W Low</div><div class="mc-val muted">$462.17</div></div>
</div>
</div>
<div class="tab-pane" id="tab-growth2"><p class="section-hd">Growth Metrics</p><div class="metrics-grid"><div class="mc" data-tip="Revenue Growth|+122.4% YoY — driven by H100/H200 GPU data center demand."><div class="mc-label">Revenue Growth</div><div class="mc-val pos">+122.4%</div></div><div class="mc" data-tip="Earnings Growth|+581% YoY net income growth on operating leverage."><div class="mc-label">Earnings Growth</div><div class="mc-val pos">+581%</div></div><div class="mc" data-tip="EPS Forward|Consensus FY2025 estimate. Implies continued strong GPU demand."><div class="mc-label">EPS Forward</div><div class="mc-val">$22.89</div></div><div class="mc" data-tip="EPS Trailing|TTM actual. Forward/trailing gap implies 47% expected EPS growth."><div class="mc-label">EPS Trailing</div><div class="mc-val muted">$15.52</div></div></div></div>
<div class="tab-pane" id="tab-momentum2"><p class="section-hd">Price Returns</p><div class="metrics-grid"><div class="mc" data-tip="1-Month Return|+6.8% — short-term momentum intact."><div class="mc-label">1-Month Return</div><div class="mc-val pos">+6.8%</div></div><div class="mc" data-tip="3-Month Return|+14.2% — sustained medium-term strength."><div class="mc-label">3-Month Return</div><div class="mc-val pos">+14.2%</div></div><div class="mc" data-tip="6-Month Return|+38.7% — primary momentum window."><div class="mc-label">6-Month Return</div><div class="mc-val pos">+38.7%</div></div><div class="mc" data-tip="12-Month Return|+89.3% — one of the best performers in the S&P 500."><div class="mc-label">12-Month Return</div><div class="mc-val pos">+89.3%</div></div></div></div>
<div class="tab-pane" id="tab-quality2"><p class="section-hd">Quality &amp; Profitability</p><div class="metrics-grid"><div class="mc" data-tip="Revenue (TTM)|Trailing 12M revenue sourced from EDGAR XBRL."><div class="mc-label">Revenue (TTM)</div><div class="mc-val">$60.9B</div></div><div class="mc" data-tip="Net Income|TTM net income — 48.9% profit margin."><div class="mc-label">Net Income</div><div class="mc-val pos">$29.8B</div></div><div class="mc" data-tip="Return on Equity|123.4% — exceptional capital efficiency."><div class="mc-label">ROE</div><div class="mc-val pos">123.4%</div></div><div class="mc" data-tip="Return on Assets|55.2% — among highest in large-cap tech."><div class="mc-label">ROA</div><div class="mc-val pos">55.2%</div></div><div class="mc" data-tip="Profit Margin|48.9% net margin — premium fabless semiconductor margin."><div class="mc-label">Profit Margin</div><div class="mc-val pos">48.9%</div></div><div class="mc" data-tip="FCF Yield|2.1% — moderate given market cap size."><div class="mc-label">FCF Yield</div><div class="mc-val">2.1%</div></div></div></div>
<div class="tab-pane" id="tab-analyst2"><p class="section-hd">Analyst &amp; Market Data</p><div class="metrics-grid"><div class="mc" data-tip="Analyst Recommendation|Strong Buy consensus with 62 covering analysts — among the widest coverage in tech."><div class="mc-label">Recommendation</div><div class="mc-val pos">Strong Buy</div></div><div class="mc" data-tip="Analyst Count|62 covering analysts. Very high coverage depth = high signal confidence."><div class="mc-label"># Analysts</div><div class="mc-val">62</div></div><div class="mc" data-tip="Consensus Price Target|Median 12-month target. Implies 19.9% upside from current price."><div class="mc-label">Price Target</div><div class="mc-val">$1,050</div></div><div class="mc" data-tip="Upside to Target|+19.9% — analysts see meaningful upside despite YTD gains."><div class="mc-label">Upside to Target</div><div class="mc-val pos">+19.9%</div></div><div class="mc" data-tip="Short Interest|1.2% of float — minimal short positioning."><div class="mc-label">Short Interest</div><div class="mc-val muted">1.2%</div></div><div class="mc" data-tip="Beta|1.71 — significantly more volatile than the broader market."><div class="mc-label">Beta</div><div class="mc-val muted">1.71</div></div></div></div>
<div class="tab-pane chart-tab" id="tab-chart2">
<div class="chart-wrap">
<div class="chart-period-bar" id="cpbar2">
<div class="period-btn">1M</div><div class="period-btn">3M</div>
<div class="period-btn active">6M</div><div class="period-btn">1Y</div>
<div class="period-btn">2Y</div><div class="period-btn">5Y</div>
</div>
<canvas id="price-chart2"></canvas>
</div>
</div>
</div>
</div>
<div class="status-bar">
<span class="status-l">Search for any stock by ticker or name</span>
<span class="status-r">Cache: 4,200 stocks · updated 4 mins ago</span>
</div>
</div><!-- /search page -->
<!-- ══════════════ TRACKING PAGE ══════════════ -->
<div class="page" id="page-tracking">
<div class="tracking-subnav">
<button class="snav-btn active" onclick="setTrackingTab('insider',this)">Insider Trades</button>
<button class="snav-btn" onclick="setTrackingTab('hedgefund',this)">Hedge Funds</button>
</div>
<!-- INSIDER TRADES -->
<div class="tpage active" id="tpage-insider">
<div class="tracking-toolbar">
<span class="tr-label">Insider Transactions</span>
<div class="tr-sep"></div>
<div class="tperiod-btn">Today</div><div class="tperiod-btn active">1W</div>
<div class="tperiod-btn">2W</div><div class="tperiod-btn">1M</div>
<div class="tr-sep"></div>
<div class="tperiod-btn active">All</div><div class="tperiod-btn">Buys</div><div class="tperiod-btn">Sales</div>
<button class="btn-refresh">↻ Refresh</button>
<span class="tr-status">24 transactions loaded</span>
</div>
<div class="tracking-table-scroll">
<table class="tr-table">
<thead><tr>
<th>Date</th><th>Ticker</th><th>Company</th><th>Insider</th><th>Title</th>
<th>Type</th><th class="r">Shares</th><th class="r">Price</th><th class="r">Value</th><th class="r">After</th>
</tr></thead>
<tbody>
<tr><td class="dimmed">Mar 28</td><td style="font-weight:700">NVDA</td><td class="muted">Nvidia Corp</td><td>Jensen Huang</td><td class="muted">CEO</td><td><span class="type-sale">Sale</span></td><td class="r">120,000</td><td class="r">$878.40</td><td class="r">$105.4M</td><td class="r dimmed">887,432</td></tr>
<tr><td class="dimmed">Mar 27</td><td style="font-weight:700">MSFT</td><td class="muted">Microsoft Corp</td><td>Satya Nadella</td><td class="muted">CEO</td><td><span class="type-sale">Sale</span></td><td class="r">14,500</td><td class="r">$424.10</td><td class="r">$6.2M</td><td class="r dimmed">1,234,000</td></tr>
<tr><td class="dimmed">Mar 27</td><td style="font-weight:700">META</td><td class="muted">Meta Platforms</td><td>Mark Zuckerberg</td><td class="muted">CEO</td><td><span class="type-sale">Sale</span></td><td class="r">85,000</td><td class="r">$513.20</td><td class="r">$43.6M</td><td class="r dimmed">342,110,009</td></tr>
<tr><td class="dimmed">Mar 26</td><td style="font-weight:700">JPM</td><td class="muted">JPMorgan Chase</td><td>Daniel Pinto</td><td class="muted">President</td><td><span class="type-buy">Buy</span></td><td class="r">22,000</td><td class="r">$196.30</td><td class="r">$4.3M</td><td class="r dimmed">214,500</td></tr>
<tr><td class="dimmed">Mar 26</td><td style="font-weight:700">AMZN</td><td class="muted">Amazon.com</td><td>Andy Jassy</td><td class="muted">CEO</td><td><span class="type-award">Award</span></td><td class="r">62,500</td><td class="r">$183.22</td><td class="r">$11.5M</td><td class="r dimmed">1,840,000</td></tr>
<tr><td class="dimmed">Mar 25</td><td style="font-weight:700">GOOGL</td><td class="muted">Alphabet Inc</td><td>Sundar Pichai</td><td class="muted">CEO</td><td><span class="type-sale">Sale</span></td><td class="r">41,200</td><td class="r">$168.40</td><td class="r">$6.9M</td><td class="r dimmed">928,100</td></tr>
<tr><td class="dimmed">Mar 25</td><td style="font-weight:700">XOM</td><td class="muted">Exxon Mobil</td><td>Darren Woods</td><td class="muted">CEO</td><td><span class="type-buy">Buy</span></td><td class="r">15,000</td><td class="r">$112.80</td><td class="r">$1.7M</td><td class="r dimmed">473,200</td></tr>
<tr><td class="dimmed">Mar 24</td><td style="font-weight:700">UNH</td><td class="muted">UnitedHealth Group</div></td><td>Andrew Witty</td><td class="muted">CEO</td><td><span class="type-buy">Buy</span></td><td class="r">5,000</td><td class="r">$493.10</td><td class="r">$2.5M</td><td class="r dimmed">88,400</td></tr>
<tr><td class="dimmed">Mar 24</td><td style="font-weight:700">TSLA</td><td class="muted">Tesla Inc</td><td>Elon Musk</td><td class="muted">CEO</td><td><span class="type-award">Award</span></td><td class="r">304,000</td><td class="r">$174.50</td><td class="r">$53.1M</td><td class="r dimmed">411,062,512</td></tr>
<tr><td class="dimmed">Mar 23</td><td style="font-weight:700">AAPL</td><td class="muted">Apple Inc</td><td>Luca Maestri</td><td class="muted">CFO</td><td><span class="type-sale">Sale</span></td><td class="r">18,300</td><td class="r">$211.90</td><td class="r">$3.9M</td><td class="r dimmed">106,200</td></tr>
</tbody>
</table>
</div>
<div class="status-bar">
<span class="status-l">24 transactions · last 7 days · click any row to view SEC filing</span>
<span class="status-r">Data: SEC EDGAR Form 4</span>
</div>
</div>
<!-- HEDGE FUNDS -->
<div class="tpage" id="tpage-hedgefund">
<div class="tracking-toolbar">
<span class="tr-label">Hedge Fund Holdings (13F-HR)</span>
<div class="tr-sep"></div>
<div class="tperiod-btn">30D</div><div class="tperiod-btn">60D</div>
<div class="tperiod-btn active">90D</div><div class="tperiod-btn">180D</div>
<div class="tr-sep"></div>
<div class="tperiod-btn active">All</div><div class="tperiod-btn">$1M+</div>
<div class="tperiod-btn">$10M+</div><div class="tperiod-btn">$100M+</div>
<button class="btn-refresh">↻ Refresh</button>
<span class="tr-status">156 holdings loaded</span>
</div>
<div class="tracking-table-scroll">
<table class="tr-table">
<thead><tr>
<th>Filed</th><th>Fund</th><th>Company</th>
<th class="r">Shares</th><th class="r">Value</th><th>Class</th><th>Opt</th>
</tr></thead>
<tbody>
<tr><td class="dimmed">Mar 15</td><td style="font-weight:600">Pershing Square Capital</td><td class="muted">Alphabet Inc (GOOGL)</td><td class="r">18,500,000</td><td class="r" style="color:var(--positive)">$3.11B</td><td class="dimmed">A</td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 15</td><td style="font-weight:600">Bridgewater Associates</td><td class="muted">Apple Inc (AAPL)</td><td class="r">12,400,000</td><td class="r" style="color:var(--positive)">$2.65B</td><td class="dimmed"></td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 14</td><td style="font-weight:600">Tiger Global Mgmt</td><td class="muted">Microsoft Corp (MSFT)</td><td class="r">4,200,000</td><td class="r">$1.78B</td><td class="dimmed"></td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 14</td><td style="font-weight:600">Third Point LLC</td><td class="muted">Nvidia Corp (NVDA)</td><td class="r">1,850,000</td><td class="r">$1.62B</td><td class="dimmed"></td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 12</td><td style="font-weight:600">Renaissance Technologies</td><td class="muted">Meta Platforms (META)</td><td class="r">3,100,000</td><td class="r">$1.59B</td><td class="dimmed">A</td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 12</td><td style="font-weight:600">Baupost Group</td><td class="muted">Amazon.com (AMZN)</td><td class="r">7,800,000</td><td class="r">$1.43B</td><td class="dimmed"></td><td class="dimmed">Call</td></tr>
<tr><td class="dimmed">Mar 11</td><td style="font-weight:600">D.E. Shaw Group</td><td class="muted">Tesla Inc (TSLA)</td><td class="r">9,200,000</td><td class="r">$1.31B</td><td class="dimmed"></td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 10</td><td style="font-weight:600">Citadel Advisors</td><td class="muted">JPMorgan Chase (JPM)</td><td class="r">6,400,000</td><td class="r">$1.26B</td><td class="dimmed"></td><td class="dimmed"></td></tr>
<tr><td class="dimmed">Mar 10</td><td style="font-weight:600">Appaloosa Mgmt</td><td class="muted">Nvidia Corp (NVDA)</td><td class="r">1,100,000</td><td class="r">$964M</td><td class="dimmed"></td><td class="dimmed">Put</td></tr>
<tr><td class="dimmed">Mar 8</td><td style="font-weight:600">Lone Pine Capital</td><td class="muted">UnitedHealth Group (UNH)</td><td class="r">1,920,000</td><td class="r">$947M</td><td class="dimmed"></td><td class="dimmed"></td></tr>
</tbody>
</table>
</div>
<div class="status-bar">
<span class="status-l">156 holdings · last 90 days · click any row to view SEC 13F filing</span>
<span class="status-r">Data: SEC EDGAR 13F-HR</span>
</div>
</div>
</div><!-- /tracking page -->
</div><!-- /main -->
</div><!-- /app -->
<script>
// ── Stock data ──────────────────────────────────────────────────────────────
const stocks = [
{ rank:1, ticker:'NVDA', name:'Nvidia Corp', score:91, sector:'Technology' },
{ rank:2, ticker:'AAPL', name:'Apple Inc', score:82, sector:'Technology' },
{ rank:3, ticker:'MSFT', name:'Microsoft Corp', score:79, sector:'Technology' },
{ rank:4, ticker:'META', name:'Meta Platforms', score:77, sector:'Comm. Services' },
{ rank:5, ticker:'GOOGL', name:'Alphabet Inc', score:74, sector:'Technology' },
{ rank:6, ticker:'AMZN', name:'Amazon.com', score:71, sector:'Cons. Discret.' },
{ rank:7, ticker:'JPM', name:'JPMorgan Chase', score:68, sector:'Financials' },
{ rank:8, ticker:'UNH', name:'UnitedHealth Group', score:65, sector:'Healthcare' },
{ rank:9, ticker:'LLY', name:'Eli Lilly & Co', score:63, sector:'Healthcare' },
{ rank:10, ticker:'V', name:'Visa Inc', score:61, sector:'Financials' },
{ rank:11, ticker:'XOM', name:'Exxon Mobil', score:59, sector:'Energy' },
{ rank:12, ticker:'JNJ', name:'Johnson & Johnson', score:57, sector:'Healthcare' },
{ rank:13, ticker:'WMT', name:'Walmart Inc', score:55, sector:'Cons. Staples' },
{ rank:14, ticker:'TSLA', name:'Tesla Inc', score:52, sector:'Cons. Discret.' },
{ rank:15, ticker:'PG', name:'Procter & Gamble', score:50, sector:'Cons. Staples' },
];
// ── Build stock table ───────────────────────────────────────────────────────
const tbody = document.getElementById('stock-tbody');
let selectedIdx = 1;
stocks.forEach((s, i) => {
const tr = document.createElement('tr');
if (i === selectedIdx) tr.classList.add('selected');
const cls = s.score >= 80 ? 'score-hi' : s.score >= 60 ? 'score-mid' : 'score-lo';
tr.innerHTML = `
<td class="num">${s.rank}</td>
<td class="ticker">${s.ticker}</td>
<td class="name">${s.name}</td>
<td class="score-cell ${cls}">${s.score}</td>
`;
tr.onclick = () => selectStock(i);
tbody.appendChild(tr);
});
function selectStock(idx) {
document.querySelectorAll('#stock-tbody tr').forEach((r,i) => r.classList.toggle('selected', i===idx));
const s = stocks[idx];
document.getElementById('detail-empty').style.display = 'none';
document.getElementById('detail-filled').style.display = 'flex';
document.getElementById('d-ticker').textContent = s.ticker;
document.getElementById('d-name').textContent = s.name;
document.getElementById('d-sector').textContent = '· ' + s.sector;
selectedIdx = idx;
// Reset to Scores tab
document.querySelectorAll('#detail-tabs .dtab').forEach((t,i) => t.classList.toggle('active', i===0));
document.querySelectorAll('#detail-body .tab-pane').forEach((p,i) => p.classList.toggle('active', i===0));
}
selectStock(selectedIdx);
// ── Page navigation ─────────────────────────────────────────────────────────
function setPage(name, el) {
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
const p = document.getElementById('page-'+name);
if (p) p.classList.add('active');
el.classList.add('active');
}
// ── Tab switching ───────────────────────────────────────────────────────────
function setTab(name, el, tabsId, bodyId) {
const tabsEl = document.getElementById(tabsId);
const bodyEl = document.getElementById(bodyId);
tabsEl.querySelectorAll('.dtab').forEach(t => t.classList.remove('active'));
bodyEl.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
el.classList.add('active');
const pane = document.getElementById('tab-'+name);
if (pane) {
pane.classList.add('active');
if (name === 'chart') { requestAnimationFrame(() => drawChart('price-chart', chartData['price-chart'])); }
if (name === 'chart2') { requestAnimationFrame(() => drawChart('price-chart2', chartData['price-chart2'])); }
}
}
// ── Tracking sub-nav ────────────────────────────────────────────────────────
function setTrackingTab(name, el) {
document.querySelectorAll('.tpage').forEach(p => p.classList.remove('active'));
document.querySelectorAll('.snav-btn').forEach(b => b.classList.remove('active'));
document.getElementById('tpage-'+name).classList.add('active');
el.classList.add('active');
}
// ── Search ──────────────────────────────────────────────────────────────────
function doSearch() {
document.getElementById('search-idle').style.display = 'none';
document.getElementById('search-result').style.display = 'flex';
}
// ── Chart drawing ───────────────────────────────────────────────────────────
function genChartData(days, start, end) {
const prices = [start], volumes = [];
const baseVol = start * 2e5;
for (let i = 1; i < days; i++) {
const trend = (end - start) / days;
const noise = (Math.random() - 0.45) * start * 0.025;
prices.push(Math.max(start * 0.7, prices[i-1] + trend + noise));
}
for (let i = 0; i < days; i++) {
volumes.push(Math.max(baseVol * 0.2, baseVol * (0.5 + Math.random())));
}
return { prices, volumes };
}
// X-axis month labels for 120-day range
const _MONTH_LABELS = ['Oct','Nov','Dec','Jan','Feb','Mar'];
function drawChart(id, data, hoverIdx = -1) {
const canvas = document.getElementById(id);
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;
const w = Math.round(rect.width) || canvas.parentElement.offsetWidth || 600;
const h = Math.round(rect.height) || canvas.parentElement.offsetHeight || 300;
canvas.width = w * dpr;
canvas.height = h * dpr;
canvas.style.width = w + 'px';
canvas.style.height = h + 'px';
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);
const { prices, volumes } = data;
const n = prices.length;
// Split canvas: 68% price, 32% volume
const pad = { top:20, right:20, bottom:32, left:56 };
const gap = 10; // gap between price and volume panels
const volH = Math.round((h - pad.top - pad.bottom - gap) * 0.30);
const priceH = h - pad.top - pad.bottom - gap - volH;
const cw = w - pad.left - pad.right;
ctx.clearRect(0,0,w,h);
ctx.fillStyle = '#181818'; ctx.fillRect(0,0,w,h);
const xOf = i => pad.left + (i / (n-1)) * cw;
// ── Price panel ────────────────────────────────
const pTop = pad.top;
const pBot = pad.top + priceH;
const mn = Math.min(...prices)*0.98, mx = Math.max(...prices)*1.02, rng = mx - mn;
const yP = v => pTop + (1 - (v - mn) / rng) * priceH;
// Price grid
for (let g = 0; g <= 4; g++) {
const y = pTop + (g/4)*priceH;
ctx.strokeStyle='#222'; ctx.lineWidth=1;
ctx.beginPath(); ctx.moveTo(pad.left,y); ctx.lineTo(w-pad.right,y); ctx.stroke();
ctx.fillStyle='#555'; ctx.font='10px Segoe UI,sans-serif'; ctx.textAlign='right';
ctx.fillText('$'+(mx-(g/4)*rng).toFixed(0), pad.left-6, y+4);
}
// Area fill
const grad = ctx.createLinearGradient(0,pTop,0,pBot);
grad.addColorStop(0,'rgba(255,255,255,0.07)'); grad.addColorStop(1,'rgba(255,255,255,0)');
ctx.beginPath(); ctx.moveTo(xOf(0),yP(prices[0]));
prices.forEach((v,i)=>{ if(i>0) ctx.lineTo(xOf(i),yP(v)); });
ctx.lineTo(xOf(n-1),pBot); ctx.lineTo(xOf(0),pBot);
ctx.closePath(); ctx.fillStyle=grad; ctx.fill();
// Price line
ctx.beginPath(); ctx.moveTo(xOf(0),yP(prices[0]));
prices.forEach((v,i)=>{ if(i>0) ctx.lineTo(xOf(i),yP(v)); });
ctx.strokeStyle='#fff'; ctx.lineWidth=1.5; ctx.stroke();
// Endpoint dot
ctx.beginPath(); ctx.arc(xOf(n-1),yP(prices[n-1]),4,0,Math.PI*2);
ctx.fillStyle='#fff'; ctx.fill();
// ── Volume panel ───────────────────────────────
const vTop = pBot + gap;
const vBot = vTop + volH;
const maxVol = Math.max(...volumes);
const barW = Math.max(1, cw / n - 1);
volumes.forEach((v,i) => {
const bh = (v / maxVol) * volH;
const bx = pad.left + (i/(n-1))*cw - barW/2;
const isUp = i === 0 || prices[i] >= prices[i-1];
ctx.fillStyle = isUp ? 'rgba(74,222,128,0.55)' : 'rgba(248,113,113,0.55)';
ctx.fillRect(bx, vBot - bh, barW, bh);
});
// Volume baseline
ctx.strokeStyle='#333'; ctx.lineWidth=1;
ctx.beginPath(); ctx.moveTo(pad.left,vBot); ctx.lineTo(w-pad.right,vBot); ctx.stroke();
// ── X labels ─────────────────────────────────
_MONTH_LABELS.forEach((l,i,a) => {
ctx.fillStyle='#555'; ctx.font='10px Segoe UI,sans-serif'; ctx.textAlign='center';
ctx.fillText(l, pad.left+(i/(a.length-1))*cw, h - 8);
});
// ── Hover crosshair ───────────────────────────
if (hoverIdx >= 0 && hoverIdx < n) {
const hx = xOf(hoverIdx);
// Vertical line spanning both panels
ctx.setLineDash([3,3]);
ctx.strokeStyle = 'rgba(255,255,255,0.25)'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(hx, pTop); ctx.lineTo(hx, vBot); ctx.stroke();
ctx.setLineDash([]);
// Price dot
const hy = yP(prices[hoverIdx]);
ctx.beginPath(); ctx.arc(hx, hy, 5, 0, Math.PI*2);
ctx.fillStyle='#fff'; ctx.fill();
ctx.beginPath(); ctx.arc(hx, hy, 3, 0, Math.PI*2);
ctx.fillStyle='#181818'; ctx.fill();
}
}
// ── Chart hover interaction ─────────────────────────────────────────────────
const _chartTip = document.getElementById('chart-tip');
const _ctipDate = document.getElementById('ctip-date');
const _ctipPrice = document.getElementById('ctip-price');
const _ctipChg = document.getElementById('ctip-chg');
const _ctipVol = document.getElementById('ctip-vol');
function _fmtVol(v) {
if (v >= 1e9) return (v/1e9).toFixed(2)+'B';
if (v >= 1e6) return (v/1e6).toFixed(1)+'M';
if (v >= 1e3) return (v/1e3).toFixed(0)+'K';
return v.toFixed(0);
}
function setupChartHover(canvasId, data) {
const canvas = document.getElementById(canvasId);
if (!canvas) return;
const { prices, volumes } = data;
const n = prices.length;
canvas.addEventListener('mousemove', e => {
const rect = canvas.getBoundingClientRect();
const mx = e.clientX - rect.left;
const pad = { left: 56, right: 20 };
const cw = rect.width - pad.left - pad.right;
const frac = (mx - pad.left) / cw;
const idx = Math.min(n-1, Math.max(0, Math.round(frac * (n-1))));
drawChart(canvasId, data, idx);
// Compute date label (fake: 120 days ending today)
const msPerDay = 86400000;
const endDate = new Date(); endDate.setHours(0,0,0,0);
const d = new Date(endDate.getTime() - (n - 1 - idx) * msPerDay);
const dateStr = d.toLocaleDateString('en-US', { month:'short', day:'numeric', year:'numeric' });
const pct = ((prices[idx] - prices[0]) / prices[0] * 100);
const pctStr = (pct >= 0 ? '+' : '') + pct.toFixed(2) + '%';
_ctipDate.textContent = dateStr;
_ctipPrice.textContent = '$' + prices[idx].toFixed(2);
_ctipChg.textContent = pctStr;
_ctipChg.style.color = pct >= 0 ? '#4ade80' : '#f87171';
_ctipVol.textContent = 'Vol ' + _fmtVol(volumes[idx]);
// Position tip
const vw = window.innerWidth, vh = window.innerHeight;
let tx = e.clientX + 16, ty = e.clientY - 60;
if (tx + 170 > vw) tx = e.clientX - 170;
if (ty < 8) ty = 8;
if (ty + 100 > vh) ty = vh - 108;
_chartTip.style.left = tx + 'px';
_chartTip.style.top = ty + 'px';
_chartTip.classList.add('visible');
});
canvas.addEventListener('mouseleave', () => {
_chartTip.classList.remove('visible');
drawChart(canvasId, data);
});
}
// ── Period button interaction ───────────────────────────────────────────────
document.querySelectorAll('.chart-period-bar').forEach(bar => {
bar.querySelectorAll('.period-btn').forEach(btn => {
btn.onclick = () => {
bar.querySelectorAll('.period-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
};
});
});
// ── Resize observer — redraw charts whenever container changes size ──────────
const chartData = {
'price-chart': genChartData(120, 170, 213),
'price-chart2': genChartData(120, 450, 875),
};
const ro = new ResizeObserver(() => {
['price-chart', 'price-chart2'].forEach(id => {
const c = document.getElementById(id);
if (c && c.closest('.chart-tab.active')) drawChart(id, chartData[id]);
});
});
document.querySelectorAll('.chart-tab').forEach(el => ro.observe(el));
// Set up hover on both charts
setupChartHover('price-chart', chartData['price-chart']);
setupChartHover('price-chart2', chartData['price-chart2']);
// ── Tooltip system ──────────────────────────────────────────────────────────
const tip = document.getElementById('tooltip');
const tipTitle = document.getElementById('tip-title');
const tipDesc = document.getElementById('tip-desc');
const tipCtx = document.getElementById('tip-context');
let tipTimeout;
document.addEventListener('mouseover', e => {
const cell = e.target.closest('.mc[data-tip]');
if (!cell) return;
const parts = cell.getAttribute('data-tip').split('|');
tipTitle.textContent = parts[0] || '';
tipDesc.textContent = parts[1] || '';
tipCtx.innerHTML = parts[2] || '';
clearTimeout(tipTimeout);
tip.classList.add('visible');
});
document.addEventListener('mousemove', e => {
if (!tip.classList.contains('visible')) return;
const vw = window.innerWidth, vh = window.innerHeight;
const tw = tip.offsetWidth + 16, th = tip.offsetHeight + 16;
let x = e.clientX + 14, y = e.clientY - 10;
if (x + tw > vw) x = e.clientX - tw;
if (y + th > vh) y = e.clientY - th;
if (y < 0) y = 8;
tip.style.left = x + 'px';
tip.style.top = y + 'px';
});
document.addEventListener('mouseout', e => {
if (!e.target.closest('.mc[data-tip]')) return;
tipTimeout = setTimeout(() => tip.classList.remove('visible'), 80);
});
</script>
</body>
</html>