// chibre — feuille de score Jass · style sanguinolent // Logique : // atouts : Trèfle (×1), Carreau (×1), Cœur (×1), Pique (×2) // par manche : (points + annonces + match) × multiplicateur // bonus Match = 100 (les 9 plis) // total points par manche = 157 → saisir dans une équipe remplit l'autre // manches éditables ; objectif personnalisable const { useState, useEffect, useMemo } = React; // --- palette sanguinolente ------------------------------------------------ const C = { bg: '#0a0807', bgDeep: '#050403', bgVoid: '#020100', panel: '#14100e', panelLight:'#1f1815', paper: '#2a221d', paperLight:'#3a2e26', line: '#3a2823', lineDim: '#251915', bone: '#d8c9a8', boneDim: '#9c8d70', bonePale: '#e8dfca', blood: '#7a0c0c', bloodBri: '#b81818', bloodDeep: '#3d0606', bloodInk: '#510808', rust: '#6b3a1a', amber: '#c9a142', rot: '#5a6b32', ash: '#6a605a', }; const TRUMPS = [ { id: 'trefle', label: 'Trèfle', mult: 1, glyph: '♣' }, { id: 'carreau', label: 'Carreau', mult: 1, glyph: '♦' }, { id: 'coeur', label: 'Cœur', mult: 1, glyph: '♥' }, { id: 'pique', label: 'Pique', mult: 2, glyph: '♠' }, ]; // --- racine --------------------------------------------------------------- function App() { useEffect(() => { const linkEl = document.createElement('link'); linkEl.rel = 'stylesheet'; linkEl.href = 'https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,700;0,900;1,700;1,900&family=Special+Elite&family=IM+Fell+English+SC&family=JetBrains+Mono:wght@400;500;700&display=swap'; document.head.appendChild(linkEl); const styleEl = document.createElement('style'); styleEl.textContent = ` *, *::before, *::after { box-sizing: border-box; } body { margin: 0; background: ${C.bgVoid}; font-family: 'Special Elite', 'JetBrains Mono', monospace; color: ${C.bone}; overflow-x: hidden; } ::selection { background: ${C.blood}; color: ${C.bone}; } input { font-family: inherit; color: inherit; } input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } input[type=number] { -moz-appearance: textfield; } button { font-family: inherit; } @keyframes ch_flash { 0% { filter: brightness(1) saturate(1); } 25% { filter: brightness(1.4) saturate(1.5) drop-shadow(0 0 24px ${C.bloodBri}); } 100% { filter: brightness(1) saturate(1); } } @keyframes ch_pop { 0% { transform: translateY(0) scale(1); } 35% { transform: translateY(-3px) scale(1.04); } 100% { transform: translateY(0) scale(1); } } @keyframes ch_fadeup { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } @keyframes ch_blink { 0%,100% { opacity: 1; } 50% { opacity: 0.2; } } @keyframes ch_drip { 0% { transform: translateY(-100%) scaleY(0.5); opacity: 0; } 20% { opacity: 1; } 100% { transform: translateY(0) scaleY(1); opacity: 0.85; } } @keyframes ch_flicker { 0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% { opacity: 1; text-shadow: 0 0 4px ${C.bloodBri}88, 0 0 12px ${C.blood}; } 20%, 24%, 55% { opacity: 0.55; text-shadow: none; } } .ch-page { position: relative; min-height: 100vh; } /* film grain + vignette */ .ch-page::before { content: ''; position: fixed; inset: 0; background-image: radial-gradient(circle at 30% 30%, ${C.blood}11, transparent 50%), radial-gradient(circle at 80% 80%, ${C.bloodInk}15, transparent 55%), radial-gradient(ellipse at center, transparent 30%, ${C.bgVoid}d0 100%); pointer-events: none; z-index: 1; } .ch-page::after { content: ''; position: fixed; inset: 0; background-image: repeating-radial-gradient(circle at 13% 27%, ${C.bone}06 0 1px, transparent 1px 3px), repeating-radial-gradient(circle at 71% 84%, ${C.bone}05 0 1px, transparent 1px 4px); pointer-events: none; opacity: 0.7; z-index: 2; mix-blend-mode: overlay; } .ch-inner { max-width: 1200px; margin: 0 auto; position: relative; z-index: 3; padding: 28px 20px 56px; } .ch-header { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 14px; padding-bottom: 26px; margin-bottom: 26px; border-bottom: 2px solid ${C.bloodDeep}; position: relative; } .ch-header::after { content: ''; position: absolute; left: 50%; bottom: -2px; transform: translateX(-50%); width: 60%; height: 2px; background: linear-gradient(90deg, transparent, ${C.bloodBri} 40%, ${C.bloodBri} 60%, transparent); box-shadow: 0 0 12px ${C.bloodBri}; } .ch-header-side { display: flex; align-items: center; gap: 10px; } .ch-header-side-r { justify-content: flex-end; gap: 8px; flex-wrap: wrap; } .ch-header-center { display: flex; flex-direction: column; align-items: center; gap: 4px; } .ch-board { display: grid; grid-template-columns: 1fr auto 1fr; gap: 14px; align-items: stretch; margin-bottom: 24px; } .ch-trump-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; } .ch-inputs-row { display: grid; grid-template-columns: 1fr auto 1fr; gap: 18px; align-items: flex-start; } .ch-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 18px; border-top: 1px dashed ${C.line}; } .ch-history::-webkit-scrollbar { width: 6px; height: 6px; } .ch-history::-webkit-scrollbar-thumb { background: ${C.bloodDeep}; } .ch-history::-webkit-scrollbar-track { background: ${C.bgDeep}; } .ch-input::placeholder { color: ${C.boneDim}; opacity: 0.5; font-style: italic; } .ch-mobile-only { display: none; } /* ============= MOBILE ============= */ @media (max-width: 760px) { .ch-inner { padding: 14px 10px 36px; } .ch-header { grid-template-columns: 1fr; gap: 10px; padding-bottom: 18px; margin-bottom: 16px; text-align: center; } .ch-header-side { justify-content: center !important; flex-wrap: wrap; } .ch-header-side-r { order: 3; } .ch-wordmark { font-size: 56px !important; } .ch-board { grid-template-columns: 1fr; gap: 12px; margin-bottom: 18px; } .ch-divider { display: none !important; } .ch-card { padding: 22px 18px 18px !important; } .ch-score-number { font-size: 96px !important; } .ch-trump-row { grid-template-columns: repeat(4, 1fr); gap: 8px; } .ch-token-disc { width: 56px !important; height: 56px !important; } .ch-inputs-row { grid-template-columns: 1fr; gap: 14px; } .ch-inputs-center { padding-top: 0 !important; order: 2; } .ch-input-col-r { order: 3; align-items: flex-start !important; } .ch-input-col-r .ch-col-head, .ch-input-col-r .ch-input-row, .ch-input-col-r .ch-bottom-row, .ch-input-col-r .ch-preview-row { flex-direction: row !important; } .ch-actions { flex-direction: column-reverse; align-items: stretch; gap: 10px; } .ch-actions button { width: 100%; justify-content: center; } .ch-entry, .ch-history-card { padding: 16px 14px !important; } .ch-section-title { font-size: 16px !important; } .ch-mult-label { display: none; } .ch-thead, .ch-trow { gap: 6px !important; padding: 10px 2px !important; } .ch-th-cumul, .ch-td-cumul { display: none; } .ch-th-trump, .ch-td-trump { flex: 0 0 64px !important; } .ch-trump-pill-text { display: none; } .ch-mobile-only { display: inline; } .ch-target-wrap { flex-wrap: wrap; } .ch-target-custom { width: 70px !important; } .ch-verdict-inner { min-width: 0 !important; padding: 32px 24px 26px !important; width: calc(100vw - 28px); } .ch-verdict-name { font-size: 56px !important; } .ch-edit-bar { flex-wrap: wrap; } } @media (max-width: 380px) { .ch-trump-row { grid-template-columns: repeat(2, 1fr); } .ch-score-number { font-size: 84px !important; } .ch-wordmark { font-size: 44px !important; } } `; document.head.appendChild(styleEl); return () => { linkEl.remove(); styleEl.remove(); }; }, []); return ; } // --- composant principal -------------------------------------------------- function Chibre() { const [target, setTarget] = useState(1000); const [customTarget, setCustomTarget] = useState(''); const [targetMode, setTargetMode] = useState('1000'); // '1000' | '2500' | 'custom' const [names, setNames] = useState(['Nous', 'Eux']); const [editingName, setEditingName] = useState(null); const [rounds, setRounds] = useState([]); const [editingIdx, setEditingIdx] = useState(null); const [trumpId, setTrumpId] = useState('coeur'); const [p1, setP1] = useState(''); const [p2, setP2] = useState(''); const [w1, setW1] = useState(''); const [w2, setW2] = useState(''); const [match, setMatch] = useState('none'); const [flash, setFlash] = useState(null); const trump = TRUMPS.find(t => t.id === trumpId); const scores = useMemo(() => { const s = [0, 0]; rounds.forEach(r => { s[0] += r.t1; s[1] += r.t2; }); return s; }, [rounds]); const winner = scores[0] >= target ? 0 : scores[1] >= target ? 1 : null; // Saisie auto-complémentaire : 157 = total des points par manche const setPoints1 = (val) => { const cleaned = val.replace(/[^0-9]/g, ''); setP1(cleaned); if (cleaned === '') { setP2(''); return; } const n = Math.min(157, parseInt(cleaned) || 0); setP2(String(Math.max(0, 157 - n))); }; const setPoints2 = (val) => { const cleaned = val.replace(/[^0-9]/g, ''); setP2(cleaned); if (cleaned === '') { setP1(''); return; } const n = Math.min(157, parseInt(cleaned) || 0); setP1(String(Math.max(0, 157 - n))); }; const previewT = useMemo(() => { const pp1 = parseInt(p1) || 0; const pp2 = parseInt(p2) || 0; const ww1 = parseInt(w1) || 0; const ww2 = parseInt(w2) || 0; const m1 = match === 'team1' ? 100 : 0; const m2 = match === 'team2' ? 100 : 0; return [(pp1 + ww1 + m1) * trump.mult, (pp2 + ww2 + m2) * trump.mult]; }, [p1, p2, w1, w2, match, trump]); function applyTargetMode(mode, custom) { setTargetMode(mode); if (mode === '1000') setTarget(1000); else if (mode === '2500') setTarget(2500); else { const n = parseInt(custom) || 0; if (n > 0) setTarget(n); } } function validate() { if (winner !== null) return; const pp1 = parseInt(p1) || 0; const pp2 = parseInt(p2) || 0; const ww1 = parseInt(w1) || 0; const ww2 = parseInt(w2) || 0; if (pp1 + pp2 + ww1 + ww2 === 0 && match === 'none') return; setRounds(rs => [...rs, { trump: trumpId, mult: trump.mult, p1: pp1, p2: pp2, w1: ww1, w2: ww2, match, t1: previewT[0], t2: previewT[1], }]); if (previewT[0] > previewT[1]) setFlash(0); else if (previewT[1] > previewT[0]) setFlash(1); setTimeout(() => setFlash(null), 1100); setP1(''); setP2(''); setW1(''); setW2(''); setMatch('none'); } function undo() { setRounds(rs => rs.slice(0, -1)); } function reset() { if (rounds.length && !confirm('Effacer la partie en cours ?')) return; setRounds([]); setP1(''); setP2(''); setW1(''); setW2(''); setMatch('none'); } function saveEdit(idx, edited) { const t = TRUMPS.find(x => x.id === edited.trump) || trump; const m1 = edited.match === 'team1' ? 100 : 0; const m2 = edited.match === 'team2' ? 100 : 0; const t1 = (edited.p1 + edited.w1 + m1) * t.mult; const t2 = (edited.p2 + edited.w2 + m2) * t.mult; setRounds(rs => rs.map((r, i) => i === idx ? { ...edited, mult: t.mult, t1, t2 } : r)); setEditingIdx(null); } function deleteRound(idx) { if (!confirm('Supprimer cette manche ?')) return; setRounds(rs => rs.filter((_, i) => i !== idx)); setEditingIdx(null); } return (
{/* éclaboussures de fond */}
0} />
setNames([n, names[1]])} score={scores[0]} target={target} preview={previewT[0]} isWinner={winner === 0} flashing={flash === 0} editing={editingName === 0} setEditing={(b) => setEditingName(b ? 0 : null)} /> setNames([names[0], n])} score={scores[1]} target={target} preview={previewT[1]} isWinner={winner === 1} flashing={flash === 1} editing={editingName === 1} setEditing={(b) => setEditingName(b ? 1 : null)} />
0} locked={winner !== null} /> {winner !== null && }
); } // --- éclaboussures de sang en fond --------------------------------------- function BloodSplats() { return ( {/* gouttes/coulures */} {[ [12, 5, 24], [28, 3, 80], [54, 4, 30], [73, 6, 60], [88, 4, 40], ].map(([x, w, h], i) => ( ))} ); } // --- en-tête -------------------------------------------------------------- function Header({ targetMode, target, customTarget, setCustomTarget, applyTargetMode, onReset, canReset }) { return (
PRENEZ · GARDE

chibre

feuille de pointage
); } function Ornament() { return ( ); } function TargetToggle({ mode, target, custom, setCustom, apply }) { return (
{[ ['1000', '1000'], ['2500', '2500'], ].map(([m, l]) => ( ))}
apply('custom', custom)} onChange={(e) => { const v = e.target.value.replace(/[^0-9]/g, ''); setCustom(v); apply('custom', v); }} style={S.targetCustomInput} />
); } // --- carte d'équipe ------------------------------------------------------- function TeamCard({ side, accent, name, onRename, score, target, preview, isWinner, flashing, editing, setEditing }) { const pct = Math.min(1, score / Math.max(1, target)); const previewPct = preview > 0 ? Math.min(1, (score + preview) / Math.max(1, target)) : pct; const [shown, setShown] = useState(score); const [bumping, setBumping] = useState(false); useEffect(() => { if (score === shown) return; setBumping(true); const t = setTimeout(() => { setShown(score); setBumping(false); }, 180); return () => clearTimeout(t); }, [score]); // eslint-disable-line return (
{/* corner stains */} {/* edge strip */}
{side === 'left' ? 'I' : 'II'} {editing ? ( { onRename(e.target.value.trim() || name); setEditing(false); }} onKeyDown={(e) => { if (e.key === 'Enter') e.currentTarget.blur(); if (e.key === 'Escape') setEditing(false); }} style={{ ...S.teamNameInput, color: accent, borderColor: accent }} /> ) : ( )} {side === 'left' ? 'I' : 'II'}
{shown}
de {target} {preview > 0 && ( +{preview} )}
{isWinner ? · VAINQUEUR · : il reste{' '} {Math.max(0, target - score)}{' '} points }
); } function CornerStain({ pos }) { const map = { tl: { top: -10, left: -10, rot: 0 }, br: { bottom: -10, right: -10, rot: 180 }, }; const p = map[pos]; return ( ); } // --- jauge ---------------------------------------------------------------- function Gauge({ pct, previewPct, accent }) { const ticks = []; for (let i = 0; i <= 10; i++) ticks.push({ pct: i * 10, major: true }); for (let i = 0; i < 10; i++) ticks.push({ pct: i * 10 + 5, major: false }); return (
{previewPct > pct && (
)}
{ticks.map((t, i) => (
))}
); } // --- séparateur ----------------------------------------------------------- function Divider() { return (
VS
); } // --- saisie --------------------------------------------------------------- function RoundEntry({ trump, trumpId, setTrumpId, names, p1, setP1, p2, setP2, w1, setW1, w2, setW2, match, setMatch, previewT, onValidate, onUndo, canUndo, locked }) { return (
· MANCHE · Inscrire la donne
1 ? C.bloodBri : C.line, color: trump.mult > 1 ? C.bloodBri : C.bone, boxShadow: trump.mult > 1 ? `0 0 12px ${C.bloodBri}55` : 'none', }}> ×{trump.mult} multiplicateur
{TRUMPS.map(t => ( setTrumpId(t.id)} /> ))}
setMatch(match === 'team1' ? 'none' : 'team1')} preview={previewT[0]} mult={trump.mult} />
setMatch(match === 'team2' ? 'none' : 'team2')} preview={previewT[1]} mult={trump.mult} mirror />
); } function TrumpToken({ trump, active, onClick }) { const isRed = trump.id === 'coeur' || trump.id === 'carreau'; const ink = isRed ? C.bloodBri : C.bone; return ( ); } function ColumnInputs({ label, sideTag, accent, points, setPoints, weis, setWeis, match, onMatch, preview, mult, mirror }) { return (
{sideTag} {label}
setWeis(v.replace(/[^0-9]/g, ''))} accent={accent} />
cette manche 0 ? accent : C.boneDim, }}> {preview > 0 ? `+${preview}` : '—'}
); } function Field({ label, hint, value, onChange, accent, big }) { return ( ); } function SumIndicator({ a, b }) { const sum = a + b; const ok = sum === 0 || sum === 157; const color = sum === 0 ? C.boneDim : (ok ? C.amber : C.bloodBri); return (
somme {sum || '—'} = 157
); } // --- historique éditable ------------------------------------------------- function History({ rounds, names, editingIdx, setEditingIdx, onSave, onDelete }) { if (!rounds.length) { return (
· REGISTRE · Historique des manches
Aucune manche jouée. Distribuez les cartes.
); } let r1 = 0, r2 = 0; return (
· REGISTRE · Historique · {rounds.length} manche{rounds.length > 1 ? 's' : ''}
Atout
{names[0]}
cumul
{names[1]}
cumul
{rounds.map((r, i) => { r1 += r.t1; r2 += r.t2; const t = TRUMPS.find(x => x.id === r.trump) || TRUMPS[0]; const isEditing = editingIdx === i; if (isEditing) { return ( onSave(i, edited)} onCancel={() => setEditingIdx(null)} onDelete={() => onDelete(i)} /> ); } return (
{String(i + 1).padStart(2, '0')}
1 ? C.bloodBri : C.line, color: t.id === 'coeur' || t.id === 'carreau' ? C.bloodBri : C.bone, }}> {t.glyph} {t.label}{t.mult > 1 ? ×{t.mult} : null} {t.mult > 1 ? '×2' : ''}
{r1}
{r2}
); })}
); } function EditRow({ round, onSave, onCancel, onDelete }) { const [trumpId, setTrumpId] = useState(round.trump); const [p1, setP1] = useState(String(round.p1)); const [p2, setP2] = useState(String(round.p2)); const [w1, setW1] = useState(String(round.w1 || '')); const [w2, setW2] = useState(String(round.w2 || '')); const [match, setMatch] = useState(round.match || 'none'); const t = TRUMPS.find(x => x.id === trumpId) || TRUMPS[0]; // auto-complete points const onP1 = (v) => { const c = v.replace(/[^0-9]/g, ''); setP1(c); if (c === '') { setP2(''); return; } setP2(String(Math.max(0, 157 - Math.min(157, parseInt(c) || 0)))); }; const onP2 = (v) => { const c = v.replace(/[^0-9]/g, ''); setP2(c); if (c === '') { setP1(''); return; } setP1(String(Math.max(0, 157 - Math.min(157, parseInt(c) || 0)))); }; const previewT1 = ((parseInt(p1)||0) + (parseInt(w1)||0) + (match === 'team1' ? 100 : 0)) * t.mult; const previewT2 = ((parseInt(p2)||0) + (parseInt(w2)||0) + (match === 'team2' ? 100 : 0)) * t.mult; return (
Modifier {TRUMPS.map(tt => ( ))}
Équipe I
onP1(e.target.value)} placeholder="pts" style={{ ...S.editInput, color: C.bloodBri }} /> setW1(e.target.value.replace(/[^0-9]/g, ''))} placeholder="weis" style={{ ...S.editInput, color: C.bloodBri }} />
= +{previewT1}
Équipe II
onP2(e.target.value)} placeholder="pts" style={{ ...S.editInput, color: C.amber }} /> setW2(e.target.value.replace(/[^0-9]/g, ''))} placeholder="weis" style={{ ...S.editInput, color: C.amber }} />
= +{previewT2}
); } function RoundCell({ points, weis, match, total, mult, accent, align }) { const parts = [`${points}`]; if (weis) parts.push(`+${weis}a`); if (match) parts.push('+100m'); return (
{total} ({parts.join(' ')}){mult > 1 ? `×${mult}` : ''}
); } // --- verdict -------------------------------------------------------------- function Verdict({ name, onReset }) { return (
· la partie est gagnée ·
{name}
); } function Footer() { const items = [ [C.bone, 'Trèfle', '♣'], [C.bloodBri,'Carreau', '♦'], [C.bloodBri,'Cœur', '♥'], [C.bone, 'Pique ×2','♠'], ]; return (
{items.map(([col, name, gl], i) => ( {gl} {name} {i < items.length - 1 && ·} ))}
); } // --- styles --------------------------------------------------------------- const S = { page: { minHeight: '100vh', background: ` radial-gradient(ellipse at 25% 0%, ${C.bloodInk}88 0%, transparent 55%), radial-gradient(ellipse at 80% 100%, ${C.bloodInk}55 0%, transparent 55%), linear-gradient(180deg, ${C.bg} 0%, ${C.bgDeep} 50%, ${C.bgVoid} 100%), ${C.bgVoid} `, backgroundAttachment: 'fixed', }, eyebrow: { fontFamily: "'IM Fell English SC', serif", fontSize: 12, letterSpacing: '0.34em', textTransform: 'uppercase', color: C.bloodBri, fontWeight: 700, }, wordmark: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 78, margin: 0, color: C.bonePale, letterSpacing: '0.005em', lineHeight: 1, textShadow: ` 2px 2px 0 ${C.bloodDeep}, 4px 4px 0 ${C.bgVoid}, 0 0 22px ${C.blood}88 `, }, subtitle: { fontFamily: "'IM Fell English SC', serif", fontSize: 12, letterSpacing: '0.32em', color: C.boneDim, textTransform: 'lowercase', }, targetWrap: { display: 'inline-flex', border: `1px solid ${C.line}`, background: C.panel, boxShadow: `inset 0 0 8px ${C.bgVoid}, 0 2px 4px ${C.bgVoid}`, }, targetBtn: { background: 'transparent', border: 'none', borderRight: `1px solid ${C.lineDim}`, color: C.boneDim, padding: '8px 14px', fontFamily: "'IM Fell English SC', serif", fontSize: 13, letterSpacing: '0.12em', cursor: 'pointer', fontWeight: 700, }, targetBtnOn: { background: `linear-gradient(180deg, ${C.bloodBri}, ${C.blood})`, color: C.bonePale, boxShadow: `inset 0 1px 0 ${C.bonePale}33, inset 0 -2px 4px ${C.bloodDeep}`, textShadow: `0 1px 0 ${C.bloodDeep}`, }, targetCustomWrap: { display: 'flex', alignItems: 'center', padding: '0 4px', background: C.bgDeep, transition: 'all 200ms ease', }, targetCustomWrapOn: { background: `linear-gradient(180deg, ${C.bloodBri}22, ${C.bloodDeep})`, boxShadow: `inset 0 0 12px ${C.blood}55`, }, targetCustomInput: { width: 60, background: 'transparent', border: 'none', color: C.bonePale, padding: '8px 6px', fontFamily: "'IM Fell English SC', serif", fontSize: 13, fontWeight: 700, letterSpacing: '0.06em', outline: 'none', textAlign: 'center', }, divider: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', position: 'relative', minWidth: 36, }, dividerLabel: { position: 'absolute', top: '50%', transform: 'translateY(-50%)', fontFamily: "'IM Fell English SC', serif", fontWeight: 700, fontSize: 16, color: C.bonePale, background: C.bg, padding: '6px 8px', letterSpacing: '0.16em', border: `1px solid ${C.bloodDeep}`, boxShadow: `0 0 10px ${C.blood}66`, }, card: { position: 'relative', padding: '34px 30px 24px', background: ` radial-gradient(ellipse at 18% 8%, ${C.paperLight}, ${C.paper} 60%, ${C.panel} 100%) `, backgroundColor: C.paper, color: C.bone, overflow: 'hidden', transition: 'box-shadow 350ms ease', border: 'none', }, teamHeader: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 14, marginBottom: 12, }, teamSideTag: { fontFamily: "'IM Fell English SC', serif", fontWeight: 700, fontSize: 18, letterSpacing: '0.12em', opacity: 0.85, }, teamName: { background: 'transparent', border: 'none', cursor: 'pointer', fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 36, letterSpacing: '0.01em', padding: '2px 10px', textShadow: `1px 1px 0 ${C.bgVoid}`, }, teamNamePencil: { fontSize: 14, marginLeft: 6, fontStyle: 'normal', opacity: 0.6, }, teamNameInput: { background: C.bgVoid, border: '1px solid', fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 32, textAlign: 'center', padding: '4px 10px', outline: 'none', width: 220, }, scoreWrap: { display: 'flex', flexDirection: 'column', alignItems: 'center', margin: '4px 0 14px', }, scoreNumber: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 'clamp(110px, 14vw, 168px)', lineHeight: 0.92, letterSpacing: '-0.02em', fontVariantNumeric: 'lining-nums tabular-nums', }, scoreFooting: { display: 'flex', alignItems: 'center', gap: 12, marginTop: 2, }, scoreOf: { fontFamily: "'IM Fell English SC', serif", fontSize: 13, letterSpacing: '0.18em', color: C.boneDim, textTransform: 'lowercase', }, previewChip: { display: 'inline-flex', alignItems: 'baseline', gap: 2, fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 18, border: `1px solid`, padding: '2px 10px', }, previewPlus: { fontSize: 14, marginRight: 1 }, gaugeWrap: { padding: '14px 0 6px' }, gaugeTrack: { position: 'relative', height: 20, background: `linear-gradient(180deg, ${C.bgVoid}, ${C.bgDeep})`, border: `1px solid ${C.line}`, }, gaugeFill: { position: 'absolute', left: 0, top: 0, bottom: 0, transition: 'width 480ms cubic-bezier(.2,.7,.2,1)', }, gaugeFillPreview: { position: 'absolute', left: 0, top: 0, bottom: 0, transition: 'width 220ms ease', }, gaugeNeedle: { position: 'absolute', top: -8, bottom: -8, transform: 'translateX(-50%)', transition: 'left 480ms cubic-bezier(.2,.7,.2,1)', pointerEvents: 'none', }, gaugeNeedleHead: { width: 10, height: 10, border: `1px solid`, borderRadius: '50%', margin: '0 auto', }, gaugeNeedleStem: { width: 2, height: 'calc(100% - 10px)', margin: '0 auto', }, cardSeal: { marginTop: 14, textAlign: 'center', fontFamily: "'IM Fell English SC', serif", fontSize: 13, letterSpacing: '0.16em', paddingTop: 12, borderTop: `1px dashed ${C.line}`, textTransform: 'lowercase', }, entry: { position: 'relative', background: `linear-gradient(180deg, ${C.panel}, ${C.bgDeep})`, border: `1px solid ${C.line}`, padding: '20px 22px', marginBottom: 22, boxShadow: `0 0 24px ${C.bloodInk}88, inset 0 0 30px ${C.bgVoid}`, }, entryHeader: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginBottom: 16, paddingBottom: 12, borderBottom: `1px dashed ${C.line}`, }, entryHeaderLeft: { display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }, entryHeaderRight: { display: 'flex', alignItems: 'center', gap: 12 }, sectionEyebrow: { fontFamily: "'IM Fell English SC', serif", fontSize: 11, letterSpacing: '0.32em', textTransform: 'uppercase', color: C.bloodBri, fontWeight: 700, }, sectionTitle: { fontFamily: "'Cormorant Garamond', serif", fontStyle: 'italic', fontWeight: 700, fontSize: 22, color: C.bonePale, }, multBadge: { display: 'inline-flex', alignItems: 'baseline', gap: 8, border: '1px solid', padding: '5px 14px', background: C.bgVoid, }, multBadgeNum: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 22, }, multBadgeLabel: { fontFamily: "'IM Fell English SC', serif", fontSize: 11, letterSpacing: '0.18em', textTransform: 'lowercase', color: C.boneDim, }, entryBody: { display: 'flex', flexDirection: 'column', gap: 22 }, tokenWrap: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7, padding: '12px 4px 8px', background: 'transparent', border: 'none', cursor: 'pointer', transition: 'transform 180ms ease', position: 'relative', }, tokenWrapOn: { transform: 'translateY(-3px)' }, tokenDisc: { position: 'relative', width: 64, height: 64, display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid', transition: 'all 220ms ease', }, tokenGlyph: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontSize: 32, lineHeight: 1, transition: 'all 220ms ease', textShadow: `1px 1px 0 ${C.bgVoid}`, }, tokenLabel: { fontFamily: "'IM Fell English SC', serif", fontSize: 13, letterSpacing: '0.1em', textTransform: 'lowercase', fontWeight: 700, transition: 'color 220ms ease', }, inputsCenter: { display: 'flex', alignItems: 'center', justifyContent: 'center', paddingTop: 32, }, inputCol: { display: 'flex', flexDirection: 'column', gap: 12, width: '100%', }, inputColHead: { display: 'flex', alignItems: 'baseline', gap: 10, }, colSide: { fontFamily: "'IM Fell English SC', serif", fontWeight: 700, fontSize: 14, letterSpacing: '0.12em', opacity: 0.8, }, colName: { fontFamily: "'Cormorant Garamond', serif", fontStyle: 'italic', fontWeight: 700, fontSize: 22, }, inputRow: { display: 'flex', gap: 10, width: '100%' }, inputBottomRow: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, width: '100%' }, field: { display: 'flex', flexDirection: 'column', gap: 6, flex: '1 1 0', }, fieldLabel: { fontFamily: "'IM Fell English SC', serif", fontSize: 11, letterSpacing: '0.2em', textTransform: 'uppercase', color: C.boneDim, fontWeight: 700, }, fieldHint: { letterSpacing: '0.14em', opacity: 0.7, fontStyle: 'italic', textTransform: 'lowercase' }, fieldInput: { width: '100%', background: C.bgVoid, border: `1px solid ${C.line}`, padding: '10px 14px', fontFamily: "'Cormorant Garamond', serif", fontWeight: 700, fontStyle: 'italic', fontSize: 24, fontVariantNumeric: 'lining-nums tabular-nums', outline: 'none', transition: 'border-color 220ms ease', boxShadow: `inset 0 2px 4px ${C.bgVoid}`, }, fieldInputBig: { fontSize: 32, padding: '8px 14px', fontWeight: 900 }, sumWrap: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2, minWidth: 60, }, sumLabel: { fontFamily: "'IM Fell English SC', serif", fontSize: 10, letterSpacing: '0.28em', textTransform: 'uppercase', color: C.boneDim, fontWeight: 700, }, sumValue: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 30, lineHeight: 1, }, sumHint: { fontFamily: "'Special Elite', monospace", fontSize: 10, color: C.boneDim, letterSpacing: '0.06em', }, matchBtn: { display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 14px', background: C.bgVoid, border: `1px solid ${C.line}`, color: C.boneDim, fontFamily: "'IM Fell English SC', serif", fontSize: 12, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 700, cursor: 'pointer', transition: 'all 200ms ease', }, matchBtnDot: { fontSize: 13, color: C.bloodBri }, matchBtnPlus: { color: C.amber, marginLeft: 2, fontFamily: "'Cormorant Garamond', serif", fontStyle: 'italic', fontWeight: 900 }, previewRow: { display: 'flex', alignItems: 'baseline', gap: 8 }, previewLabel: { fontFamily: "'IM Fell English SC', serif", fontSize: 10, letterSpacing: '0.24em', textTransform: 'uppercase', color: C.boneDim, fontWeight: 700, }, previewValue: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 24, }, btnGhost: { background: 'transparent', border: `1px solid ${C.line}`, color: C.bonePale, padding: '10px 18px', fontFamily: "'IM Fell English SC', serif", fontSize: 13, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 700, cursor: 'pointer', transition: 'all 200ms ease', }, btnPrimary: { display: 'inline-flex', alignItems: 'center', gap: 12, padding: '14px 30px', background: `linear-gradient(180deg, ${C.bloodBri} 0%, ${C.blood} 60%, ${C.bloodDeep} 100%)`, border: `1px solid ${C.bonePale}`, color: C.bonePale, fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 20, letterSpacing: '0.04em', cursor: 'pointer', boxShadow: ` inset 0 1px 0 ${C.bonePale}44, inset 0 -3px 6px ${C.bloodDeep}, 0 4px 0 ${C.bloodDeep}, 0 0 20px ${C.blood}aa `, textShadow: `0 1px 0 ${C.bloodDeep}, 0 0 8px ${C.bonePale}55`, }, btnPrimaryGlyph: { color: C.bonePale, fontSize: 14, opacity: 0.85 }, history: { background: `linear-gradient(180deg, ${C.panel}, ${C.bgDeep})`, border: `1px solid ${C.line}`, padding: '20px 22px', marginBottom: 22, boxShadow: `0 0 18px ${C.bloodInk}66, inset 0 0 20px ${C.bgVoid}`, }, historyEmpty: { fontFamily: "'IM Fell English SC', serif", fontStyle: 'normal', fontSize: 14, color: C.boneDim, textAlign: 'center', padding: '28px 0', border: `1px dashed ${C.line}`, background: C.bgVoid, letterSpacing: '0.12em', }, historyScroll: { maxHeight: 360, overflowY: 'auto', }, tableHead: { display: 'flex', gap: 12, padding: '8px 4px 10px', borderBottom: `1px solid ${C.bloodDeep}`, marginBottom: 4, }, thCell: { fontFamily: "'IM Fell English SC', serif", fontSize: 11, letterSpacing: '0.22em', textTransform: 'uppercase', color: C.bloodBri, fontWeight: 700, }, tableRow: { display: 'flex', gap: 12, padding: '12px 4px', borderBottom: `1px dotted ${C.lineDim}`, alignItems: 'center', }, tdCell: { fontFamily: "'Special Elite', monospace", fontSize: 12 }, trumpPill: { display: 'inline-flex', alignItems: 'center', background: C.bgVoid, padding: '4px 10px', border: '1px solid', fontFamily: "'IM Fell English SC', serif", fontSize: 12, fontWeight: 700, letterSpacing: '0.04em', }, editBtn: { background: 'transparent', border: `1px solid ${C.line}`, color: C.boneDim, width: 28, height: 28, cursor: 'pointer', fontSize: 13, transition: 'all 200ms ease', }, // edit row editRow: { padding: '16px 12px', background: `linear-gradient(180deg, ${C.bloodInk}33, ${C.bgVoid})`, border: `1px solid ${C.bloodBri}`, boxShadow: `0 0 18px ${C.bloodBri}55, inset 0 0 20px ${C.bgVoid}`, margin: '6px 0', }, editBar: { display: 'flex', alignItems: 'center', gap: 6, paddingBottom: 12, borderBottom: `1px dashed ${C.line}`, marginBottom: 12, flexWrap: 'wrap', }, editTrumpBtn: { background: C.bgVoid, border: `1px solid ${C.line}`, color: C.bone, padding: '6px 10px', fontFamily: "'IM Fell English SC', serif", cursor: 'pointer', transition: 'all 180ms ease', display: 'inline-flex', alignItems: 'center', }, editGrid: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, }, editCol: { display: 'flex', flexDirection: 'column', gap: 8, }, editColLabel: { fontFamily: "'IM Fell English SC', serif", fontSize: 12, letterSpacing: '0.18em', textTransform: 'uppercase', color: C.boneDim, fontWeight: 700, }, editFieldRow: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6, }, editInput: { background: C.bgVoid, border: `1px solid ${C.line}`, padding: '6px 10px', fontFamily: "'Cormorant Garamond', serif", fontWeight: 700, fontSize: 18, outline: 'none', }, editMatchBtn: { background: C.bgVoid, border: `1px solid ${C.line}`, color: C.boneDim, padding: '6px 12px', fontFamily: "'IM Fell English SC', serif", fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 700, cursor: 'pointer', width: 'fit-content', transition: 'all 180ms ease', }, editActions: { display: 'flex', alignItems: 'center', gap: 8, paddingTop: 14, marginTop: 12, borderTop: `1px dashed ${C.line}`, flexWrap: 'wrap', }, verdict: { position: 'fixed', inset: 0, background: `radial-gradient(ellipse at center, ${C.bloodInk}cc, ${C.bgVoid}f5)`, backdropFilter: 'blur(6px)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 200, animation: 'ch_fadeup 320ms ease-out', padding: 16, }, verdictInner: { position: 'relative', background: ` radial-gradient(ellipse at 18% 8%, ${C.paperLight}, ${C.paper} 60%, ${C.panel} 100%) `, padding: '44px 64px 36px', border: `1px solid ${C.bloodBri}`, boxShadow: ` 0 40px 100px ${C.bgVoid}, inset 0 0 60px ${C.bloodInk}55, 0 0 60px ${C.bloodBri}88, 0 0 120px ${C.blood}55 `, textAlign: 'center', color: C.bone, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, minWidth: 420, }, verdictKicker: { fontFamily: "'IM Fell English SC', serif", fontSize: 12, letterSpacing: '0.32em', textTransform: 'uppercase', color: C.bloodBri, marginTop: 6, fontWeight: 700, }, verdictName: { fontFamily: "'Cormorant Garamond', serif", fontWeight: 900, fontStyle: 'italic', fontSize: 76, color: C.bonePale, lineHeight: 1, textShadow: ` 2px 2px 0 ${C.bloodDeep}, 4px 4px 0 ${C.bgVoid}, 0 0 40px ${C.bloodBri}88, 0 0 80px ${C.blood}55 `, }, verdictRule: { width: 90, height: 1, background: `linear-gradient(90deg, transparent, ${C.bloodBri}, transparent)`, margin: '4px 0 8px', boxShadow: `0 0 8px ${C.bloodBri}`, }, footer: { textAlign: 'center', padding: '20px 0 0', fontFamily: "'IM Fell English SC', serif", fontSize: 12, letterSpacing: '0.1em', }, }; ReactDOM.createRoot(document.getElementById('root')).render();