P2-10: ledger read-card density — tighter padding/margins (3-4 per phone screen)

Phone audit: read cards were huge, only 1-2 fit per screen. Compressed the
vertical spacing — article padding 16->12, header margin 8->5, name 15->14px,
ladder-rungs margin 10->8, book/date line 12->8.

Kept the archetype showDesc: it renders INLINE (same row as the badge), so it
adds zero vertical height — dropping it wouldn't help density and would break
the ds5 design lock ("the badge shows its one-line meaning where it leads").
Locked the density in vyndrParityQA (P2-10).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-17 01:47:48 -04:00
parent 77e8937a56
commit 71e35e90fd
2 changed files with 21 additions and 7 deletions
+11
View File
@@ -298,3 +298,14 @@ describe('P1-8 — Compare verdict is time-honest (form, not a phantom game)', (
expect(compare).toMatch(/on current form/i); expect(compare).toMatch(/on current form/i);
}); });
}); });
// ── P2-10 lock — ledger read cards are dense (3-4 per phone screen) ──────────
describe('P2-10 — ledger cards are tightened for density', () => {
const ledger = read('app/ledger/page.tsx');
it('the read card uses tight padding for density (3-4 per phone screen)', () => {
// the LedgerCard <article> padding dropped 16 -> 12 (showDesc is INLINE, so
// density comes from padding/margins, not from stripping the archetype meaning)
expect(ledger).toMatch(/animate-fade-up stagger-[^]*?padding: 12 \}\}>/);
expect(ledger).toMatch(/ArchetypeBadge[^]*?showDesc/); // meaning preserved (inline, no height cost)
});
});
+10 -7
View File
@@ -333,8 +333,8 @@ function LedgerCard({ row, index, ladder }: { row: LedgerRow; index: number; lad
const rungs = Array.isArray(ladder) ? ladder : [row]; const rungs = Array.isArray(ladder) ? ladder : [row];
const isLadder = rungs.length > 1; const isLadder = rungs.length > 1;
return ( return (
<article className={`surface diagonal-cut animate-fade-up stagger-${(index % 6) + 1}`} style={{ padding: 16 }}> <article className={`surface diagonal-cut animate-fade-up stagger-${(index % 6) + 1}`} style={{ padding: 12 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8 }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 5 }}>
<span className="mono" style={{ fontSize: 10, fontWeight: 700, padding: '2px 8px', borderRadius: 999, background: `${sportColor}1F`, color: sportColor }}> <span className="mono" style={{ fontSize: 10, fontWeight: 700, padding: '2px 8px', borderRadius: 999, background: `${sportColor}1F`, color: sportColor }}>
{row.sport.toUpperCase()} {row.sport.toUpperCase()}
</span> </span>
@@ -348,10 +348,13 @@ function LedgerCard({ row, index, ladder }: { row: LedgerRow; index: number; lad
<GradePill grade={row.grade} /> <GradePill grade={row.grade} />
</span> </span>
</div> </div>
<h3 style={{ fontSize: 15, fontWeight: 600, marginBottom: 2 }}>{row.player_name}</h3> <h3 style={{ fontSize: 14, fontWeight: 600, marginBottom: 2 }}>{row.player_name}</h3>
{/* Part 5 — the archetype glyph+chip, propagated (self-hides when absent). */} {/* Part 5 — the archetype glyph+chip, propagated (self-hides when absent).
showDesc renders INLINE (same row), so it costs no vertical height —
kept for its one-line meaning. P2-10 density comes from the tighter
padding/margins, not from stripping this. */}
{row.archetype && ( {row.archetype && (
<div style={{ marginBottom: 6 }}> <div style={{ marginBottom: 4 }}>
<ArchetypeBadge archetype={row.archetype} size="sm" showDesc /> <ArchetypeBadge archetype={row.archetype} size="sm" showDesc />
</div> </div>
)} )}
@@ -362,7 +365,7 @@ function LedgerCard({ row, index, ladder }: { row: LedgerRow; index: number; lad
<p className="mono" style={{ fontSize: 12, color: 'var(--text-secondary)', textTransform: 'capitalize', marginBottom: 6 }}> <p className="mono" style={{ fontSize: 12, color: 'var(--text-secondary)', textTransform: 'capitalize', marginBottom: 6 }}>
{row.stat.replace(/_/g, ' ')} <span style={{ color: 'var(--text-tertiary)' }}>· {rungs.length} lines</span> {row.stat.replace(/_/g, ' ')} <span style={{ color: 'var(--text-tertiary)' }}>· {rungs.length} lines</span>
</p> </p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 }}> <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
{rungs.map((rung) => ( {rungs.map((rung) => (
<span key={rung.id} className="mono" style={{ fontSize: 10.5, display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', borderRadius: 6, background: 'var(--bg-2)', border: '1px solid var(--border)' }}> <span key={rung.id} className="mono" style={{ fontSize: 10.5, display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 8px', borderRadius: 6, background: 'var(--bg-2)', border: '1px solid var(--border)' }}>
{rung.side}{rung.line} {rung.side}{rung.line}
@@ -376,7 +379,7 @@ function LedgerCard({ row, index, ladder }: { row: LedgerRow; index: number; lad
{row.side} {row.line} {row.stat.replace(/_/g, ' ')} {row.side} {row.line} {row.stat.replace(/_/g, ' ')}
</p> </p>
)} )}
<p className="mono" style={{ fontSize: 11, color: 'var(--text-tertiary)', marginBottom: 12 }}> <p className="mono" style={{ fontSize: 11, color: 'var(--text-tertiary)', marginBottom: 8 }}>
{row.book ? <BookWordmark book={row.book} size={11} /> : '—'}{row.locked_odds ? ` · ${row.locked_odds}` : ''} · {row.game_date} {row.book ? <BookWordmark book={row.book} size={11} /> : '—'}{row.locked_odds ? ` · ${row.locked_odds}` : ''} · {row.game_date}
{/* model_value is MODEL output — always labeled, never blended with market numbers. */} {/* model_value is MODEL output — always labeled, never blended with market numbers. */}
{row.model_value != null && <span> · MODEL {row.model_value}</span>} {row.model_value != null && <span> · MODEL {row.model_value}</span>}