/* ========================================================================== Sprite Forge — Pixel Art Sprite Dataset Builder Design: dark editor workspace (Aseprite/annotation-tool register), phosphor-green confidence accent, monospace data + Inter UI chrome. ========================================================================== */ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@400;500;600;700&display=swap'); :root { --canvas: #15171c; --panel: #1d2027; --panel-raised: #262a33; --panel-raised-2: #2e333e; --line: #363b47; --line-soft: #2a2e38; --ink: #e8e9ed; --ink-dim: #8b90a0; --ink-faint: #5a5f6e; --accent: #7fe08b; --accent-dim: #4d9e59; --accent-wash: rgba(127, 224, 139, 0.12); --warn: #f2b84b; --warn-wash: rgba(242, 184, 75, 0.14); --danger: #e8607a; --danger-wash: rgba(232, 96, 122, 0.14); --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; --radius-sm: 3px; --radius-md: 5px; --topbar-h: 52px; --statusbar-h: 44px; } * { box-sizing: border-box; } html, body { height: 100%; margin: 0; } body { background: var(--canvas); color: var(--ink); font-family: var(--font-ui); font-size: 13px; line-height: 1.5; overflow: hidden; } button { font-family: inherit; } ::selection { background: var(--accent-wash); color: var(--ink); } /* Scrollbars: thin, editor-style */ ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--panel-raised-2); border-radius: 6px; border: 2px solid var(--panel); } ::-webkit-scrollbar-thumb:hover { background: var(--line); } /* ========================================================================== App shell ========================================================================== */ #app { display: grid; grid-template-rows: var(--topbar-h) 1fr var(--statusbar-h); height: 100vh; } /* ---- topbar ---- */ .topbar { display: flex; align-items: center; gap: 16px; padding: 0 16px; background: var(--panel); border-bottom: 1px solid var(--line); } .brand { display: flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-weight: 700; font-size: 14px; letter-spacing: 0.02em; color: var(--ink); white-space: nowrap; } .brand-mark { display: inline-grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 1fr); width: 18px; height: 18px; gap: 1px; } .brand-mark span { background: var(--line); } .brand-mark span:nth-child(2), .brand-mark span:nth-child(5), .brand-mark span:nth-child(6), .brand-mark span:nth-child(9), .brand-mark span:nth-child(11), .brand-mark span:nth-child(15) { background: var(--accent); } .topbar-actions { display: flex; gap: 8px; } .topbar-spacer { flex: 1; } .topbar-stat { font-family: var(--font-mono); font-size: 12px; color: var(--ink-dim); white-space: nowrap; } .topbar-stat b { color: var(--ink); font-weight: 600; } /* ---- buttons ---- */ .btn { display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; background: var(--panel-raised); border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); font-size: 12.5px; font-weight: 500; cursor: pointer; transition: background-color 120ms ease, border-color 120ms ease; white-space: nowrap; } .btn:hover { background: var(--panel-raised-2); border-color: var(--ink-faint); } .btn:active { transform: translateY(1px); } .btn:disabled { opacity: 0.4; cursor: not-allowed; } .btn:disabled:hover { background: var(--panel-raised); border-color: var(--line); } .btn-primary { background: var(--accent); border-color: var(--accent); color: #0d1f10; font-weight: 600; } .btn-primary:hover { background: #93e79d; border-color: #93e79d; } .btn-danger { color: var(--danger); border-color: var(--danger); background: transparent; } .btn-danger:hover { background: var(--danger-wash); } .btn-ghost { background: transparent; border-color: transparent; color: var(--ink-dim); } .btn-ghost:hover { background: var(--panel-raised); color: var(--ink); } .btn-sm { padding: 4px 9px; font-size: 11.5px; } .btn-block { width: 100%; justify-content: center; } /* ========================================================================== Workspace: three-pane layout ========================================================================== */ .workspace { display: grid; grid-template-columns: 240px 1fr 320px; overflow: hidden; } .pane { overflow-y: auto; min-height: 0; } .pane-left { background: var(--panel); border-right: 1px solid var(--line); } .pane-center { background: var(--canvas); display: flex; flex-direction: column; overflow: hidden; } .pane-right { background: var(--panel); border-left: 1px solid var(--line); } .pane-section { padding: 14px; border-bottom: 1px solid var(--line-soft); } .pane-label { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); margin: 0 0 10px 0; } /* ---- sheets list (left pane) ---- */ .sheet-item { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--radius-sm); cursor: pointer; color: var(--ink-dim); font-size: 12.5px; } .sheet-item:hover { background: var(--panel-raised); color: var(--ink); } .sheet-item.active { background: var(--accent-wash); color: var(--ink); box-shadow: inset 2px 0 0 var(--accent); } .sheet-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-mono); } .sheet-item-count { font-family: var(--font-mono); font-size: 11px; color: var(--ink-faint); } .empty-hint { color: var(--ink-faint); font-size: 12px; padding: 6px 10px 2px; line-height: 1.6; } /* ---- upload dropzone ---- */ .dropzone { border: 1.5px dashed var(--line); border-radius: var(--radius-md); padding: 18px 10px; text-align: center; color: var(--ink-faint); font-size: 11.5px; cursor: pointer; transition: border-color 120ms ease, background-color 120ms ease; } .dropzone:hover, .dropzone.drag-over { border-color: var(--accent-dim); background: var(--accent-wash); color: var(--ink-dim); } .dropzone-icon { font-family: var(--font-mono); font-size: 18px; color: var(--ink-faint); margin-bottom: 6px; } .padding-row { display: flex; gap: 6px; margin-top: 10px; } .padding-chip { flex: 1; text-align: center; padding: 5px 0; font-family: var(--font-mono); font-size: 11px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink-dim); cursor: pointer; background: transparent; } .padding-chip:hover { border-color: var(--ink-faint); } .padding-chip.active { border-color: var(--accent); background: var(--accent-wash); color: var(--accent); } /* ========================================================================== Center canvas: sheet + bounding box overlay ========================================================================== */ .canvas-toolbar { display: flex; align-items: center; gap: 10px; padding: 8px 14px; border-bottom: 1px solid var(--line); background: var(--panel); } .canvas-toolbar-title { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .canvas-toolbar-spacer { flex: 1; } .zoom-controls { display: flex; align-items: center; gap: 4px; font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-dim); } .canvas-scroll { flex: 1; overflow: auto; position: relative; /* checkerboard = the actual transparency convention every image editor uses, doubles as the canvas's textural identity */ background-color: var(--canvas); background-image: linear-gradient(45deg, #1b1e24 25%, transparent 25%), linear-gradient(-45deg, #1b1e24 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #1b1e24 75%), linear-gradient(-45deg, transparent 75%, #1b1e24 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px; display: flex; align-items: flex-start; justify-content: flex-start; padding: 40px; } .sheet-stage { position: relative; flex-shrink: 0; image-rendering: pixelated; image-rendering: -moz-crisp-edges; box-shadow: 0 0 0 1px var(--line); } .sheet-stage img { display: block; image-rendering: pixelated; image-rendering: -moz-crisp-edges; } /* ---- bounding box overlay: the signature element ---- */ .bbox { position: absolute; border: 1px solid var(--bbox-color, var(--accent)); cursor: pointer; transition: box-shadow 100ms ease; } .bbox:hover { box-shadow: 0 0 0 1px var(--bbox-color, var(--accent)), 0 0 8px 0 var(--bbox-color, var(--accent)); z-index: 5; } @media (max-width: 880px) { /* Small sprites (a handful of source pixels, scaled down further to fit a phone screen) can end up as a 4-6px tappable box -- well under any usable touch target. An invisible ::before hit-area extends the actual tap region without changing the visible box size or shifting layout (position:absolute + inset avoids affecting sibling sprites' boxes, since each bbox is independently absolutely positioned). */ .bbox::before { content: ''; position: absolute; inset: -6px; } } .bbox-tag { position: absolute; top: -1px; left: -1px; transform: translateY(-100%); background: var(--bbox-color, var(--accent)); color: #0d1f10; font-family: var(--font-mono); font-size: 9px; font-weight: 700; line-height: 1; padding: 2px 3px; white-space: nowrap; pointer-events: none; } /* Reviewed sprites stay identifiable at a glance: accepted gets a solid filled tag + checkmark, rejected gets a dimmed dashed border. Relying on opacity alone was too subtle against small, already-dark sprites. */ .bbox.status-accepted { border-style: solid; box-shadow: 0 0 0 1px var(--accent); } .bbox.status-accepted .bbox-tag { background: var(--accent); color: #0d1f10; } .bbox.status-accepted .bbox-tag::after { content: ' ✓'; } .bbox.status-rejected { border-style: dashed; opacity: 0.4; } .bbox.status-rejected .bbox-tag { background: var(--panel-raised-2); color: var(--ink-faint); text-decoration: line-through; } .bbox.selected { border-color: var(--ink); animation: marching-ants 550ms linear infinite; z-index: 6; } .bbox.selected::after { content: ''; position: absolute; inset: -2px; border: 1px dashed var(--ink); animation: marching-ants 550ms linear infinite; } @keyframes marching-ants { to { background-position: 8px 0; } } .bbox.selected { background-image: repeating-linear-gradient( 90deg, var(--ink) 0 4px, transparent 4px 8px ); background-size: 8px 1px; background-repeat: repeat-x; background-position: 0 0; border: none; outline: 1px solid var(--ink); } .bbox.selected::after { display: none; } @media (prefers-reduced-motion: reduce) { .bbox.selected { animation: none; } } .canvas-empty { margin: auto; text-align: center; color: var(--ink-faint); font-size: 13px; max-width: 320px; } .canvas-empty-mark { font-family: var(--font-mono); font-size: 28px; color: var(--line); margin-bottom: 12px; } /* ========================================================================== Right pane: inspector ========================================================================== */ .inspector-empty { padding: 40px 20px; text-align: center; color: var(--ink-faint); font-size: 12.5px; line-height: 1.7; } .preview-frame { display: flex; align-items: center; justify-content: center; background-color: var(--canvas); background-image: linear-gradient(45deg, #1b1e24 25%, transparent 25%), linear-gradient(-45deg, #1b1e24 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #1b1e24 75%), linear-gradient(-45deg, transparent 75%, #1b1e24 75%); background-size: 16px 16px; background-position: 0 0, 0 8px, 8px -8px, -8px 0px; border: 1px solid var(--line); border-radius: var(--radius-md); height: 200px; overflow: hidden; } .preview-frame img { image-rendering: pixelated; image-rendering: -moz-crisp-edges; max-width: 100%; max-height: 100%; } .sprite-id { font-family: var(--font-mono); font-size: 11px; color: var(--ink-faint); margin-top: 8px; word-break: break-all; } .dim-row { display: flex; justify-content: space-between; align-items: baseline; margin-top: 10px; font-family: var(--font-mono); } .dim-row .dims { font-size: 15px; font-weight: 600; color: var(--ink); } .dim-row .source { font-size: 10.5px; color: var(--ink-faint); } .confidence-banner { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 8px 10px; border-radius: var(--radius-sm); font-size: 11.5px; border: 1px solid var(--line); } .confidence-banner.high { border-color: var(--accent-dim); background: var(--accent-wash); color: var(--accent); } .confidence-banner.mid { border-color: #b88a2c; background: var(--warn-wash); color: var(--warn); } .confidence-banner.low { border-color: #b8425a; background: var(--danger-wash); color: var(--danger); } .confidence-banner .conf-value { font-family: var(--font-mono); font-weight: 700; } .confidence-reasons { margin: 6px 0 0 0; padding-left: 16px; font-size: 11px; color: var(--ink-dim); } .score-grid { display: grid; grid-template-columns: 1fr auto; gap: 6px 10px; margin-top: 10px; font-size: 11.5px; } .score-grid .k { color: var(--ink-dim); } .score-grid .v { font-family: var(--font-mono); color: var(--ink); text-align: right; } .score-bar { grid-column: 1 / -1; height: 3px; background: var(--line-soft); border-radius: 2px; overflow: hidden; margin: -3px 0 4px; } .score-bar-fill { height: 100%; background: var(--accent); } .field-group { margin-top: 14px; } .field-label { display: block; font-size: 11px; color: var(--ink-dim); margin-bottom: 5px; } .field-select, .field-input { width: 100%; padding: 7px 9px; background: var(--panel-raised); border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); font-family: var(--font-ui); font-size: 12.5px; } .field-select:focus, .field-input:focus { outline: none; border-color: var(--accent-dim); } .tag-list { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; } .tag-chip { display: inline-flex; align-items: center; gap: 4px; padding: 3px 7px; background: var(--panel-raised-2); border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-dim); } .tag-chip button { background: none; border: none; color: var(--ink-faint); cursor: pointer; font-size: 11px; padding: 0; line-height: 1; } .tag-chip button:hover { color: var(--danger); } .dup-banner { margin-top: 12px; padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid #7a5230; background: var(--warn-wash); font-size: 11.5px; color: var(--warn); } .dup-banner b { font-family: var(--font-mono); } .bg-toggle { display: flex; gap: 6px; margin-top: 10px; } .bg-toggle .padding-chip { flex: 1; } .action-row { display: flex; gap: 8px; margin-top: 16px; } .action-row .btn { flex: 1; justify-content: center; } .edit-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-top: 10px; } .edit-row label { display: block; font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-faint); margin-bottom: 3px; } .edit-row input { width: 100%; padding: 5px 6px; background: var(--panel-raised); border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); font-family: var(--font-mono); font-size: 11.5px; } /* ========================================================================== Status bar ========================================================================== */ .statusbar { display: flex; align-items: center; gap: 18px; padding: 0 16px; background: var(--panel); border-top: 1px solid var(--line); font-family: var(--font-mono); font-size: 11.5px; } .stat { display: flex; align-items: center; gap: 6px; color: var(--ink-dim); } .stat-dot { width: 7px; height: 7px; border-radius: 1px; } .stat-dot.accepted { background: var(--accent); } .stat-dot.rejected { background: var(--danger); } .stat-dot.pending { background: var(--ink-faint); } .stat-dot.duplicates { background: var(--warn); } .stat b { color: var(--ink); font-weight: 600; } .statusbar-spacer { flex: 1; } .batch-controls { display: flex; gap: 6px; } /* ========================================================================== Toasts ========================================================================== */ #toast-stack { position: fixed; bottom: calc(var(--statusbar-h) + 14px); right: 16px; display: flex; flex-direction: column; gap: 8px; z-index: 100; } .toast { padding: 10px 14px; background: var(--panel-raised); border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: var(--radius-sm); font-size: 12px; color: var(--ink); box-shadow: 0 4px 16px rgba(0,0,0,0.35); max-width: 320px; animation: toast-in 180ms ease; } .toast.error { border-left-color: var(--danger); } @keyframes toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } } /* ========================================================================== Modal (merge/split) ========================================================================== */ .modal-backdrop { position: fixed; inset: 0; background: rgba(10, 11, 14, 0.7); display: flex; align-items: center; justify-content: center; z-index: 200; } .modal { width: 420px; max-width: calc(100vw - 40px); background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-md); padding: 18px; box-shadow: 0 12px 40px rgba(0,0,0,0.5); } .modal-title { font-family: var(--font-mono); font-size: 13px; font-weight: 600; margin: 0 0 6px; } .modal-desc { font-size: 12px; color: var(--ink-dim); margin: 0 0 14px; line-height: 1.6; } .modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; } /* ========================================================================== Responsive: mobile layout below ~880px ========================================================================== Desktop uses a fixed 100vh grid where each pane scrolls independently (an editor-window model). That model breaks down on a phone: three panes stacked vertically inside a fixed viewport height leaves each one too short to use. Below the breakpoint we switch to natural page scroll instead -- the whole app becomes one tall scrollable column, sections stack in the order you actually use them (upload → canvas → inspector), and only the sprite-sheet canvas keeps its own internal scroll (it needs horizontal pan/zoom regardless of viewport). */ @media (max-width: 880px) { html, body { height: auto; } body { overflow-y: auto; overflow-x: hidden; /* bottom padding is set later in this block once the fixed statusbar's mobile height (two rows) is known */ } #app { height: auto; min-height: 100vh; display: block; } .topbar { height: auto; min-height: var(--topbar-h); flex-wrap: wrap; row-gap: 6px; padding: 8px 12px; position: sticky; top: 0; z-index: 20; } .topbar-stat { display: none; } .topbar-actions { gap: 6px; } .topbar-actions .btn { padding: 9px 12px; /* keep tap targets >= ~40px tall */ font-size: 12px; } .workspace { display: block; overflow: visible; } .pane { overflow: visible; } .pane-left { border-right: none; border-bottom: 1px solid var(--line); } .pane-left .pane-section { padding: 12px; } /* Sheets list: horizontal chip scroller instead of a tall vertical list, so it doesn't push the canvas below the fold on a phone. */ #sheet-list { display: flex; gap: 8px; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 4px; } #sheet-list .empty-hint { white-space: normal; min-width: 220px; } .sheet-item { flex: 0 0 auto; min-width: 120px; } .dropzone { padding: 14px 10px; } .pane-center { overflow: visible; } .canvas-toolbar { position: sticky; top: var(--topbar-h); z-index: 15; flex-wrap: wrap; row-gap: 6px; } .canvas-toolbar-title { font-size: 11.5px; } .zoom-controls .btn { padding: 8px 10px; min-height: 40px; } /* The canvas itself: allow real horizontal + vertical panning with a thumb, and let the browser's native pinch-zoom work on it (desktop disables that nowhere, but touch-action defaults can interfere with drag-scroll -- pan-x pan-y keeps both working together). */ .canvas-scroll { height: 62vh; min-height: 320px; max-height: 520px; padding: 16px; touch-action: pan-x pan-y pinch-zoom; } .canvas-empty { font-size: 12.5px; padding: 0 8px; } .pane-right { border-left: none; border-top: 1px solid var(--line); } .inspector-empty { padding: 24px 20px; } .preview-frame { height: 160px; } .score-grid { font-size: 11px; } .action-row .btn { padding: 11px 10px; } /* bigger tap target */ /* Baseline tap-target floor: anything clickable gets at least ~40px of height on touch, even where desktop uses a tighter, mouse-precision padding (padding-chips, sm buttons, tag remove buttons, etc). */ .btn, .padding-chip, .sheet-item, select, input[type="number"], input[type="text"] { min-height: 40px; } .btn-sm { min-height: 38px; } .tag-chip button { min-width: 24px; min-height: 24px; } .field-select, .field-input { padding: 10px 9px; } /* Status bar: at phone widths the counts + batch actions no longer fit on one row. Instead of overflowing off-screen, the bar becomes two stacked rows -- counts on top (always visible, compact), batch action buttons in a horizontally-scrollable strip below -- and stays pinned to the viewport bottom like on desktop, since it's the primary place review actions live. */ .statusbar { position: fixed; left: 0; right: 0; bottom: 0; height: auto; flex-wrap: wrap; row-gap: 8px; padding: 10px 12px; z-index: 25; } .statusbar .stat { flex: 0 0 auto; font-size: 11px; } .statusbar-spacer { display: none; flex-basis: 100%; height: 0; } .batch-controls { flex: 0 0 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 2px; } .batch-controls .btn { flex: 0 0 auto; padding: 10px 13px; font-size: 11.5px; } body { padding-bottom: 92px; } /* clears the now-taller fixed statusbar */ .modal { width: calc(100vw - 32px); } .edit-row { grid-template-columns: repeat(2, 1fr); row-gap: 8px; } #toast-stack { left: 12px; right: 12px; bottom: 100px; } .toast { max-width: none; } } @media (max-width: 460px) { .brand { font-size: 12.5px; } .brand-mark { width: 15px; height: 15px; } .topbar-actions .btn span.btn-label-full { display: none; } } /* Focus visibility (kept intentional, not suppressed) */ a:focus-visible, button:focus-visible, [tabindex]:focus-visible, input:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } /* ========================================================================== Auto-labelling notice ========================================================================== */ .auto-tag-banner { margin-top: 12px; padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid #3c5470; background: rgba(96, 152, 232, 0.12); font-size: 11.5px; color: #8fb4e8; line-height: 1.55; } .auto-tag-banner b { font-family: var(--font-mono); } /* ========================================================================== Bulk assign panel ========================================================================== */ .field-hint { color: var(--ink-faint); font-weight: 400; } .checkbox-row { display: flex; align-items: center; gap: 7px; margin-top: 7px; font-size: 11.5px; color: var(--ink-dim); cursor: pointer; } .checkbox-row input { accent-color: var(--accent-dim); } .mono { font-family: var(--font-mono); } /* ========================================================================== Animation preview ========================================================================== */ .modal-wide { width: 560px; } .modal-scroll { max-height: calc(100vh - 60px); overflow-y: auto; } .anim-stage { position: relative; margin: 14px auto 4px; background: repeating-conic-gradient(#22252c 0% 25%, #1a1d23 0% 50%) 50% / 16px 16px; border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; } .anim-frame { position: absolute; display: none; image-rendering: pixelated; } .anim-frame.visible { display: block; } .anim-controls { display: flex; align-items: center; gap: 8px; margin-top: 12px; flex-wrap: wrap; } .anim-counter { font-family: var(--font-mono); font-size: 12px; color: var(--ink-dim); min-width: 62px; text-align: center; } .anim-fps { display: flex; align-items: center; gap: 8px; margin-left: auto; font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-dim); } .anim-fps input { width: 96px; accent-color: var(--accent-dim); } /* ========================================================================== Dataset report ========================================================================== */ .report-warnings { display: flex; flex-direction: column; gap: 7px; margin: 12px 0 4px; } .report-warning { padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid #7a5230; background: var(--warn-wash); color: var(--warn); font-size: 11.5px; line-height: 1.55; } .report-ok { margin: 12px 0 4px; padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid var(--accent-dim); background: var(--accent-wash); color: var(--accent); font-size: 11.5px; } .report-note { margin-top: 6px; padding: 8px 10px; border-radius: var(--radius-sm); background: var(--panel-raised); border: 1px solid var(--line-soft); color: var(--ink-dim); font-size: 11.5px; line-height: 1.6; } .dist-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; } .dist-row { display: grid; grid-template-columns: 130px 1fr 78px; align-items: center; gap: 8px; font-size: 11.5px; } .dist-name { font-family: var(--font-mono); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .dist-bar { height: 7px; background: var(--panel-raised); border-radius: 99px; overflow: hidden; } .dist-bar-fill { display: block; height: 100%; background: var(--accent-dim); } .dist-count { font-family: var(--font-mono); color: var(--ink-dim); text-align: right; } @media (max-width: 880px) { .dist-row { grid-template-columns: 96px 1fr 66px; } .modal-wide { width: auto; } }