utkarshpathak48 commited on
Commit
ba64247
·
1 Parent(s): 65c73d3

UI: fix featured-card proportions to match v2 mockup

Browse files

- lvl-grid: repeat(3,1fr) -> repeat(6,1fr) on desktop so Entry/Stop/RR/TP1/TP2/TP3 render in one row like the mockup's grid6 (was wrapping to 2 rows)
- Featured card left rail widened 220px->280px and confidence ring enlarged 110px->148px to match mockup's proportions
- Left rail now shows only simple HMM/MK state pills (matching mockup) instead of the full bordered state-strip+forecast panel, which was making the rail look cluttered/cramped
- Full detailed state-strip (forecast bars, conflict note, etc.) relocated to the right column in its original position - no data lost, just moved to where there's room for it
- Verified locally against live scan data before redeploying

Files changed (1) hide show
  1. static/index.html +85 -23
static/index.html CHANGED
@@ -1139,7 +1139,7 @@ nav {
1139
 
1140
  /* ── Levels grid ── */
1141
  /* Color-coded: each box tells a story at a glance (trading convention) */
1142
- .lvl-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:7px; margin-bottom:10px; }
1143
  .lvl-pnl { font-size:10px; font-weight:700; font-variant-numeric:tabular-nums; margin-top:2px; }
1144
  .lvl-pnl.pos { color:var(--profit); }
1145
  .lvl-pnl.neg { color:var(--loss); }
@@ -1560,6 +1560,28 @@ nav {
1560
  .conf-ring-center span { font-size:8px; font-weight:700; letter-spacing:0.1em; color:var(--t3); }
1561
  .featured-tag { display:inline-flex; align-items:center; gap:6px; font-family:var(--font-display); font-size:11px; font-weight:700; letter-spacing:0.06em; color:var(--teal); text-transform:uppercase; }
1562
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1563
  .row-summary { display:none; }
1564
  .card.row-mode .row-summary {
1565
  display:grid; cursor:pointer;
@@ -1677,6 +1699,7 @@ nav {
1677
  .hero { padding:100px 20px 50px; }
1678
  #signals-grid { grid-template-columns:1fr; }
1679
  .hero-stats { gap:8px; }
 
1680
  }
1681
 
1682
  /* ═══════════════════════════════════════════════
@@ -3235,6 +3258,7 @@ function buildCard(c, account, risk, meta) {
3235
 
3236
  // ── Market State block (Markov + HMM) ──
3237
  let stateHTML = '';
 
3238
  let cardStateConf = null; // exposed on card root so applyStateFilter() works (bug fix)
3239
  const mkData = ms.markov, hmmData = ms.hmm;
3240
  if (mkData || hmmData) {
@@ -3250,6 +3274,7 @@ function buildCard(c, account, risk, meta) {
3250
  let badges = '';
3251
  if (hmmData) badges += `<span class="state-badge ${hmmData.state}" title="HMM: probabilistic inference">HMM · ${hmmData.state} <span class="state-conf">${Math.round(hmmData.confidence*100)}%</span></span>`;
3252
  if (mkData) badges += `<span class="state-badge ${mkData.state}" title="Markov: state + transition matrix">MK · ${mkData.state} <span class="state-conf">${Math.round(mkData.confidence*100)}%</span></span>`;
 
3253
 
3254
  // Forecast bars for 1d, 3d, 7d
3255
  let forecastHTML = '';
@@ -3546,43 +3571,46 @@ function buildCard(c, account, risk, meta) {
3546
  <span class="rs-exp">▾</span>
3547
  </div>` : '';
3548
 
3549
- // ── Featured ring — shown only on the #1 ranked "Top Setup" card ──
3550
  const ringCirc = 226.2; // 2*pi*36
3551
- const featuredRingHTML = featured ? `
3552
- <div class="featured-ring-row">
 
 
3553
  <div class="conf-ring-wrap">
3554
  <svg viewBox="0 0 84 84">
3555
  <circle class="conf-ring-bg" cx="42" cy="42" r="36" stroke-width="7"/>
3556
  <circle class="conf-ring-val" cx="42" cy="42" r="36" stroke-width="7" stroke="${confColor}" stroke-dasharray="${ringCirc}" stroke-dashoffset="${(ringCirc-(ringCirc*confPct/100)).toFixed(1)}"/>
3557
  </svg>
3558
  <div class="conf-ring-center"><b>${conf}</b><span>/ 10</span></div>
3559
- </div>
3560
- <span class="featured-tag"><svg class="ic"><use href="#i-zap"/></svg> Top Setup · highest conviction</span>
3561
- </div>` : '';
3562
 
3563
- el.innerHTML=`${rowSummaryHTML}
3564
- <div class="card-detail"><div class="card-detail-inner">
3565
- ${featuredRingHTML}
3566
  <div class="ch">
3567
  <div class="ch-left">
3568
  <div class="ch-sym">${base}<span class="q">${quote}</span></div>
3569
  <div class="ch-badges">${exchBadge}${cvBadge}${newsBadge}${chgBadge}${volBadge}${frBadge}${takerBadge}${oiBadge}</div>
3570
  </div>
3571
  <span class="dir-tag ${dir}">${dir.toUpperCase()}</span>
3572
- </div>
3573
 
 
3574
  <div class="conf-box">
3575
  <div class="conf-row">
3576
  <span class="conf-lbl">Confidence Score</span>
3577
  <span class="conf-num" style="color:${confColor}">${conf}<span class="conf-denom">/10</span></span>${(()=>{const g=(c.price_action||{}).confluence_grade;if(!g)return '';const gc=g==='A+'?'pa-grade-ap':g==='A'?'pa-grade-a':g==='B'?'pa-grade-b':g==='C'?'pa-grade-c':'pa-grade-d';return `<span class="pa-conf-grade ${gc}">${g}</span>`;})()}
3578
  </div>
3579
  <div class="conf-bar"><div class="conf-fill ${confCls}" style="width:${confPct}%"></div></div>
3580
- </div>
3581
 
 
3582
  ${vetoBanner}
3583
  <div class="tf-row">${tfHTML}</div>
3584
- <div class="rule"></div>
3585
 
 
3586
  <div class="lvl-grid">
3587
  ${(()=>{
3588
  // Dollar P&L at each level using recommended leverage
@@ -3602,22 +3630,20 @@ function buildCard(c, account, risk, meta) {
3602
  <div class="lvl tp"> <div class="lvl-lbl">TP 2</div><div class="lvl-val">${sf(lv.tp2)}</div>${fmt(pTP2)}</div>
3603
  <div class="lvl tp"> <div class="lvl-lbl">TP 3</div><div class="lvl-val">${sf(lv.tp3)}</div>${fmt(pTP3)}</div>`;
3604
  })()}
3605
- </div>
3606
 
 
3607
  <div class="sz-strip">
3608
  <div class="sz-item"><div class="sz-lbl">Risk $</div><div class="sz-val">${fu(sz.risk_usd)}</div></div>
3609
  <div class="sz-item"><div class="sz-lbl">BingX qty</div><div class="sz-val">${sz.units??'—'}<span style="display:block;font-size:9px;color:var(--warn);font-weight:700;margin-top:1px">← enter on BingX</span></div></div>
3610
  <div class="sz-item"><div class="sz-lbl">Notional</div><div class="sz-val">${fu(sz.notional)}</div></div>
3611
- </div>
3612
-
3613
- ${probHTML}${levHTML}${durHTML}${stateHTML}${btHTML}${buildLiveAccPanel(sym)}
3614
- ${narr?`<div class="narr">${narr}</div>`:''}
3615
- <div class="rule"></div>
3616
 
3617
- <div class="ev-title">Score Breakdown — ${c.pa_available ? '35/20/15/15/15' : '40/20/20/20'}</div>
3618
- ${evHTML}
3619
- ${buildPriceActionSection(c)}
3620
 
 
3621
  <div class="card-acts">
3622
  <a class="ca ca-chart" href="${tvUrl}" target="_blank" rel="noopener">
3623
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg>
@@ -3630,7 +3656,43 @@ function buildCard(c, account, risk, meta) {
3630
  <button class="ca ca-ref" data-sym="${sym}" data-acc="${account}" data-risk="${risk}" data-rank="${rank??''}" data-featured="${featured?'1':'0'}" title="Refresh this card">
3631
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
3632
  </button>
3633
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3634
  </div></div>`;
3635
 
3636
  if (isRowMode) {
 
1139
 
1140
  /* ── Levels grid ── */
1141
  /* Color-coded: each box tells a story at a glance (trading convention) */
1142
+ .lvl-grid { display:grid; grid-template-columns:repeat(6,1fr); gap:7px; margin-bottom:10px; }
1143
  .lvl-pnl { font-size:10px; font-weight:700; font-variant-numeric:tabular-nums; margin-top:2px; }
1144
  .lvl-pnl.pos { color:var(--profit); }
1145
  .lvl-pnl.neg { color:var(--loss); }
 
1560
  .conf-ring-center span { font-size:8px; font-weight:700; letter-spacing:0.1em; color:var(--t3); }
1561
  .featured-tag { display:inline-flex; align-items:center; gap:6px; font-family:var(--font-display); font-size:11px; font-weight:700; letter-spacing:0.06em; color:var(--teal); text-transform:uppercase; }
1562
 
1563
+ /* ── Featured two-column layout: ring/grade/state/score rail + main content ── */
1564
+ .featured-layout { display:grid; grid-template-columns:280px 1fr; gap:28px; align-items:start; }
1565
+ .featured-left {
1566
+ display:flex; flex-direction:column; align-items:center; gap:14px;
1567
+ padding:20px 16px; border-radius:16px; text-align:center;
1568
+ background:linear-gradient(160deg, var(--mints, rgba(61,220,151,0.08)), transparent 70%);
1569
+ border:1px solid var(--gb);
1570
+ }
1571
+ .featured-left .conf-ring-wrap { width:148px; height:148px; }
1572
+ .featured-left .conf-ring-center b { font-size:34px; }
1573
+ .featured-left .state-strip, .featured-left .panel, .featured-left .featured-state-pills { width:100%; text-align:left; }
1574
+ .featured-left .featured-state-pills { display:flex; flex-wrap:wrap; gap:7px; justify-content:center; }
1575
+ .featured-right { display:flex; flex-direction:column; gap:16px; min-width:0; }
1576
+ .tag-grade { display:inline-flex; align-items:center; font-family:var(--font-display); font-weight:700; font-size:12px; letter-spacing:0.06em; padding:5px 13px; border-radius:9px; }
1577
+ .tag-grade.gA { color:var(--profit, var(--green)); background:var(--mints, rgba(61,220,151,0.11)); border:1px solid rgba(61,220,151,0.3); }
1578
+ .tag-grade.gB { color:var(--warn, var(--amber)); background:var(--ambers, rgba(245,181,42,0.12)); border:1px solid rgba(245,181,42,0.3); }
1579
+ .tag-grade.gC { color:var(--loss, var(--red)); background:var(--reds, rgba(255,107,122,0.10)); border:1px solid rgba(255,107,122,0.3); }
1580
+ @media (max-width:900px) {
1581
+ .featured-layout { grid-template-columns:1fr; }
1582
+ .featured-left { flex-direction:row; flex-wrap:wrap; justify-content:center; text-align:left; }
1583
+ }
1584
+
1585
  .row-summary { display:none; }
1586
  .card.row-mode .row-summary {
1587
  display:grid; cursor:pointer;
 
1699
  .hero { padding:100px 20px 50px; }
1700
  #signals-grid { grid-template-columns:1fr; }
1701
  .hero-stats { gap:8px; }
1702
+ .lvl-grid { grid-template-columns:repeat(3,1fr); }
1703
  }
1704
 
1705
  /* ═══════════════════════════════════════════════
 
3258
 
3259
  // ── Market State block (Markov + HMM) ──
3260
  let stateHTML = '';
3261
+ let stateBadgesSimpleHTML = ''; // lightweight HMM/MK pills only — used in the featured card's left rail
3262
  let cardStateConf = null; // exposed on card root so applyStateFilter() works (bug fix)
3263
  const mkData = ms.markov, hmmData = ms.hmm;
3264
  if (mkData || hmmData) {
 
3274
  let badges = '';
3275
  if (hmmData) badges += `<span class="state-badge ${hmmData.state}" title="HMM: probabilistic inference">HMM · ${hmmData.state} <span class="state-conf">${Math.round(hmmData.confidence*100)}%</span></span>`;
3276
  if (mkData) badges += `<span class="state-badge ${mkData.state}" title="Markov: state + transition matrix">MK · ${mkData.state} <span class="state-conf">${Math.round(mkData.confidence*100)}%</span></span>`;
3277
+ stateBadgesSimpleHTML = `<div class="state-badges featured-state-pills">${badges}</div>`;
3278
 
3279
  // Forecast bars for 1d, 3d, 7d
3280
  let forecastHTML = '';
 
3571
  <span class="rs-exp">▾</span>
3572
  </div>` : '';
3573
 
3574
+ // ── Featured ring + grade tag — shown only on the #1 ranked "Top Setup" card ──
3575
  const ringCirc = 226.2; // 2*pi*36
3576
+ const gradeLetter = conf>=7 ? 'A' : conf>=5 ? 'B' : 'C';
3577
+ const gradeCssCls = isVetoed ? 'gC' : gradeLetter==='A' ? 'gA' : gradeLetter==='B' ? 'gB' : 'gC';
3578
+ const gradeTagLabel = isVetoed ? 'VETOED · NO TRADE' : `GRADE ${gradeLetter} · TRADEABLE`;
3579
+ const featuredRingWrapHTML = featured ? `
3580
  <div class="conf-ring-wrap">
3581
  <svg viewBox="0 0 84 84">
3582
  <circle class="conf-ring-bg" cx="42" cy="42" r="36" stroke-width="7"/>
3583
  <circle class="conf-ring-val" cx="42" cy="42" r="36" stroke-width="7" stroke="${confColor}" stroke-dasharray="${ringCirc}" stroke-dashoffset="${(ringCirc-(ringCirc*confPct/100)).toFixed(1)}"/>
3584
  </svg>
3585
  <div class="conf-ring-center"><b>${conf}</b><span>/ 10</span></div>
3586
+ </div>` : '';
 
 
3587
 
3588
+ // ── Named content blocks — shared between the normal single-column layout
3589
+ // and the featured two-column layout, so nothing is duplicated or lost ──
3590
+ const chHTML = `
3591
  <div class="ch">
3592
  <div class="ch-left">
3593
  <div class="ch-sym">${base}<span class="q">${quote}</span></div>
3594
  <div class="ch-badges">${exchBadge}${cvBadge}${newsBadge}${chgBadge}${volBadge}${frBadge}${takerBadge}${oiBadge}</div>
3595
  </div>
3596
  <span class="dir-tag ${dir}">${dir.toUpperCase()}</span>
3597
+ </div>`;
3598
 
3599
+ const confBoxHTML = `
3600
  <div class="conf-box">
3601
  <div class="conf-row">
3602
  <span class="conf-lbl">Confidence Score</span>
3603
  <span class="conf-num" style="color:${confColor}">${conf}<span class="conf-denom">/10</span></span>${(()=>{const g=(c.price_action||{}).confluence_grade;if(!g)return '';const gc=g==='A+'?'pa-grade-ap':g==='A'?'pa-grade-a':g==='B'?'pa-grade-b':g==='C'?'pa-grade-c':'pa-grade-d';return `<span class="pa-conf-grade ${gc}">${g}</span>`;})()}
3604
  </div>
3605
  <div class="conf-bar"><div class="conf-fill ${confCls}" style="width:${confPct}%"></div></div>
3606
+ </div>`;
3607
 
3608
+ const tfBlockHTML = `
3609
  ${vetoBanner}
3610
  <div class="tf-row">${tfHTML}</div>
3611
+ <div class="rule"></div>`;
3612
 
3613
+ const lvlGridHTML = `
3614
  <div class="lvl-grid">
3615
  ${(()=>{
3616
  // Dollar P&L at each level using recommended leverage
 
3630
  <div class="lvl tp"> <div class="lvl-lbl">TP 2</div><div class="lvl-val">${sf(lv.tp2)}</div>${fmt(pTP2)}</div>
3631
  <div class="lvl tp"> <div class="lvl-lbl">TP 3</div><div class="lvl-val">${sf(lv.tp3)}</div>${fmt(pTP3)}</div>`;
3632
  })()}
3633
+ </div>`;
3634
 
3635
+ const szStripHTML = `
3636
  <div class="sz-strip">
3637
  <div class="sz-item"><div class="sz-lbl">Risk $</div><div class="sz-val">${fu(sz.risk_usd)}</div></div>
3638
  <div class="sz-item"><div class="sz-lbl">BingX qty</div><div class="sz-val">${sz.units??'—'}<span style="display:block;font-size:9px;color:var(--warn);font-weight:700;margin-top:1px">← enter on BingX</span></div></div>
3639
  <div class="sz-item"><div class="sz-lbl">Notional</div><div class="sz-val">${fu(sz.notional)}</div></div>
3640
+ </div>`;
 
 
 
 
3641
 
3642
+ const narrHTML = `${narr?`<div class="narr">${narr}</div>`:''}<div class="rule"></div>`;
3643
+ const evTitleHTML = `<div class="ev-title">Score Breakdown — ${c.pa_available ? '35/20/15/15/15' : '40/20/20/20'}</div>${evHTML}`;
3644
+ const priceActionHTML = buildPriceActionSection(c);
3645
 
3646
+ const cardActsHTML = `
3647
  <div class="card-acts">
3648
  <a class="ca ca-chart" href="${tvUrl}" target="_blank" rel="noopener">
3649
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/></svg>
 
3656
  <button class="ca ca-ref" data-sym="${sym}" data-acc="${account}" data-risk="${risk}" data-rank="${rank??''}" data-featured="${featured?'1':'0'}" title="Refresh this card">
3657
  <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
3658
  </button>
3659
+ </div>`;
3660
+
3661
+ // ── Featured cards: two-column layout (ring/grade/state/score rail + main content).
3662
+ // Non-featured cards: original single-column stacked layout, unchanged. ──
3663
+ const bodyHTML = featured ? `
3664
+ <div class="featured-layout">
3665
+ <div class="featured-left">
3666
+ ${featuredRingWrapHTML}
3667
+ <span class="tag-grade ${gradeCssCls}">${gradeTagLabel}</span>
3668
+ ${stateBadgesSimpleHTML}
3669
+ <div class="panel">${evTitleHTML}</div>
3670
+ </div>
3671
+ <div class="featured-right">
3672
+ ${chHTML}
3673
+ ${tfBlockHTML}
3674
+ ${lvlGridHTML}
3675
+ ${szStripHTML}
3676
+ ${probHTML}${levHTML}${durHTML}${stateHTML}${btHTML}${buildLiveAccPanel(sym)}
3677
+ ${narrHTML}
3678
+ ${priceActionHTML}
3679
+ ${cardActsHTML}
3680
+ </div>
3681
+ </div>` : `
3682
+ ${chHTML}
3683
+ ${confBoxHTML}
3684
+ ${tfBlockHTML}
3685
+ ${lvlGridHTML}
3686
+ ${szStripHTML}
3687
+ ${probHTML}${levHTML}${durHTML}${stateHTML}${btHTML}${buildLiveAccPanel(sym)}
3688
+ ${narrHTML}
3689
+ ${evTitleHTML}
3690
+ ${priceActionHTML}
3691
+ ${cardActsHTML}`;
3692
+
3693
+ el.innerHTML=`${rowSummaryHTML}
3694
+ <div class="card-detail"><div class="card-detail-inner">
3695
+ ${bodyHTML}
3696
  </div></div>`;
3697
 
3698
  if (isRowMode) {