/* Chimera design system — corrections layer. Loaded last on purpose: several component stylesheets are linked after stitch.css, so token-level fixes have to sit downstream of all of them. Tokens still live in stitch.css; this file only resolves conflicts. */ /* ============================================================================ Design-system corrections — 2026-08-23 One authoritative block. stitch.css owns the tokens; base.css owns the reset. Ordered: type scale, elevation, surfaces, controls, forms, edges. ========================================================================== */ /* --- Type: one scale, sentence case above the label sizes ----------------- */ #chimera-route-title{ font-family:var(--display); font-size:var(--fs-display); font-weight:640; letter-spacing:-.03em; line-height:1.04; text-transform:none; text-wrap:balance; } .stat-num{font-family:var(--display);font-size:var(--fs-xl);font-weight:600;line-height:1;font-variant-numeric:tabular-nums} .stat-lbl{font-size:var(--fs-xs)} .page-header h1{font-family:var(--display);font-size:var(--fs-xl);font-weight:620;letter-spacing:-.025em;text-transform:none} h2{font-size:var(--fs-lg)} h3,h4{font-size:var(--fs-md)} .game-card .s-tag{font-size:var(--fs-micro)} #chimera-route-breadcrumb{font-size:var(--fs-micro);letter-spacing:.14em} /* --- Elevation: three levels, nothing invented per component -------------- */ .card,.stat-card,.table-wrap,.chimera-home-panel{box-shadow:var(--shadow-panel)} .modal,.modal-shell,.import-wizard,#toast-container .toast,.chimera-command-palette{box-shadow:var(--shadow-float)} .btn,.chimera-toolbar-button,.chimera-route-link,.fbtn,.badge,.pill{box-shadow:var(--shadow-flat)} /* --- Surfaces: inherit the radius scale, stop hand-rolling values --------- */ .card,.stat-card,.table-wrap,.backup-card,.progress-area,.chimera-home-panel,.catalog-health-strip{border-radius:var(--radius)} .btn,.fbtn,input,select,textarea,.filter-select,.search-input, .chimera-domain-button,.modal-workspace-links button{border-radius:var(--radius-sm)} .modal,.modal-shell,.import-wizard{border-radius:var(--radius-lg)} .badge,.pill,.s-tag,.bk-badge{border-radius:999px} /* --- Controls: one filled button per view --------------------------------- */ /* Teal was acting as a second primary. It becomes an outlined action and the accent fill stays the single call to action. */ .btn-teal{ background:transparent; color:var(--teal); border-color:rgba(34,199,232,.42); font-weight:600; } .btn-teal:hover:not(:disabled){ background:rgba(34,199,232,.1); border-color:var(--teal); color:var(--teal); } .btn-accent{background:var(--accent-d);border-color:var(--accent-d);color:#fff} .btn-accent:hover:not(:disabled){background:var(--accent);border-color:var(--accent);color:#1a1220} .btn{min-height:36px;font-size:var(--fs-xs);display:inline-flex;align-items:center;justify-content:center;gap:7px} /* --- Forms: label above field, one control height, full card width -------- */ .card .form-row,.card .form-grid{width:100%} .card label{flex-direction:column;align-items:flex-start;gap:6px;font-size:var(--fs-xs)} .card label.toggle-label,.card .toggle-row{flex-direction:row;align-items:center} input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]), select,textarea{min-height:40px;font-size:var(--fs-xs)} /* The accent picker was a raw native colour input sitting outside the system. */ .color-swatch{ position:relative;width:40px;height:40px;flex:none;overflow:hidden; border:1px solid var(--border);border-radius:var(--radius-sm); background:var(--accent-d); } .color-picker-input{ position:absolute;inset:-4px;width:calc(100% + 8px);height:calc(100% + 8px); padding:0;border:0;background:transparent;cursor:pointer;opacity:0; } .color-hex-label{ width:11ch;font-family:var(--mono);font-size:var(--fs-xs); text-transform:uppercase;text-align:center; } /* --- Edges: error placement, toast clearance, orphaned rails -------------- */ /* The header banner and the toast reported the same failure twice. The banner keeps it (state persists); the toast is suppressed for route-load errors. */ .chimera-route-availability{ max-width:52ch;padding:7px 11px;line-height:1.45; background:rgba(228,173,85,.1);border:1px solid rgba(228,173,85,.3); color:var(--yellow);white-space:normal; } /* Toast stack clears the floating import button instead of landing under it. */ #toast-container{bottom:calc(var(--statusbar-h) + 74px)} /* The catalog health rail was floating in the grid with no container, and its text values were rendered at the numeral display size. */ .catalog-health-strip{ background:var(--surface2); border:1px solid var(--border-soft); padding:6px 4px; } #game-catalog-health{font-size:var(--fs-xs)} #game-catalog-health strong,#game-catalog-health b{ font-family:var(--display);font-size:var(--fs-lg);font-weight:600; line-height:1.15;font-variant-numeric:tabular-nums; } /* Compact settings rows: a class, not 17 copies of the same inline style. */ .setting-label{ flex:none; white-space:nowrap; font-size:var(--fs-xs); color:var(--text-dim); } .form-row>.setting-label,.color-picker-row>.setting-label{align-self:center} /* Last two off-scale sizes: a button inheriting the UA default, and a glyph. */ #sidebar-donate{font-size:var(--fs-xs)} .chimera-command-search-icon,.game-library-search>span[aria-hidden]{font-size:var(--fs-md);line-height:1} /* ============================================================================ Library: poster-first cards The grid is the artwork. Actions live on the art and only when reached; the card itself opens the detail modal, so it carries no button stack. ========================================================================== */ #games-grid{ grid-template-columns:repeat(auto-fill,minmax(170px,1fr)); gap:20px 18px; align-items:start; } .game-card{ display:flex;flex-direction:column;gap:0; background:0 0;border:0;box-shadow:none;padding:0; overflow:visible; } /* --- the poster ---------------------------------------------------------- */ .game-card-art{ position:relative; aspect-ratio:var(--game-cover-ratio, 2 / 3); overflow:hidden; border-radius:var(--radius); background:var(--surface2); border:1px solid var(--border-soft); box-shadow:0 12px 28px -14px rgba(0,0,0,.75); transition:box-shadow .24s cubic-bezier(.2,.8,.2,1),border-color .24s; } .game-card:hover .game-card-art, .game-card:focus-visible .game-card-art{ border-color:rgba(var(--accent-rgb),.5); box-shadow:0 22px 46px -16px rgba(0,0,0,.85),0 0 0 1px rgba(var(--accent-rgb),.16); } .game-card-cover{width:100%;height:100%;object-fit:cover;display:block} /* Coverless titles get a mark derived from their own title ID, so a grid with no artwork still reads as a shelf of distinct things. */ .game-card-cover-fallback.is-visible{ position:absolute;inset:0;aspect-ratio:auto; padding:14px;gap:4px; background: radial-gradient(circle at 74% 16%, hsl(var(--card-hue,265) 70% 46% / .42), transparent 46%), radial-gradient(circle at 18% 88%, hsl(calc(var(--card-hue,265) + 46) 68% 40% / .34), transparent 50%), linear-gradient(158deg,#1a1422,#0a0b11); } .game-card-cover-fallback.is-visible::before{ top:14%;right:-22%;width:86%; border-color:hsl(var(--card-hue,265) 80% 78% / .22); } .game-card-cover-fallback strong{font-size:var(--fs-md);max-width:13ch;line-height:1.12} .game-card-cover-fallback span{color:hsl(var(--card-hue,265) 85% 80% / .9)} /* --- state marker: a corner chip, not a banner across the poster ---------- */ .game-card-sync{ position:absolute;top:10px;left:10px;right:auto; display:inline-flex;align-items:center;gap:6px; max-width:calc(100% - 20px); padding:4px 9px; font-size:var(--fs-micro);font-weight:600;letter-spacing:.02em; color:var(--text);background:rgba(10,8,14,.72); border:1px solid var(--border-soft);border-radius:999px; backdrop-filter:blur(10px); overflow:hidden;text-overflow:ellipsis;white-space:nowrap; } .game-card-sync.pending::before{ content:"";flex:none;width:6px;height:6px;border-radius:50%; background:var(--yellow);box-shadow:0 0 0 3px rgba(228,173,85,.18); } /* --- actions: on the art, on reach --------------------------------------- */ .game-card-actions{ position:absolute;left:0;right:0;bottom:0; display:flex;gap:6px;padding:10px; background:linear-gradient(transparent,rgba(8,6,12,.82) 42%); opacity:0;transform:translateY(6px); z-index:4; transition:opacity .2s,transform .2s cubic-bezier(.2,.8,.2,1); } .game-card:hover .game-card-actions, .game-card:focus-within .game-card-actions{opacity:1;transform:none} .game-card-actions .btn{flex:1;min-height:32px;padding-inline:8px;font-size:var(--fs-micro)} /* Pointer-less and reduced-motion contexts never get hover, so pin them open. */ @media (hover:none){ .game-card-actions{position:static;opacity:1;transform:none;background:0 0;padding:8px 0 0} } @media (prefers-reduced-motion:reduce){ .game-card-art,.game-card-actions{transition:none} } /* --- caption ------------------------------------------------------------- */ .game-card-body{ display:flex;flex-direction:column;gap:3px; padding:10px 2px 0;background:0 0;border:0; } .game-card-heading strong{ display:block;font-size:var(--fs-xs);font-weight:600;line-height:1.3;color:var(--text); overflow:hidden;text-overflow:ellipsis;white-space:nowrap; } .game-card-meta{ font-family:var(--mono);font-size:var(--fs-micro);color:var(--text-muted); overflow:hidden;text-overflow:ellipsis;white-space:nowrap; } .game-card .game-card-status{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px} /* The sync chip was a full-width purple banner in uppercase mono across the poster. It is a state marker, not a headline. */ .game-card-sync, .game-card-sync.pending{ color:var(--text); background:rgba(10,8,14,.72); border-color:var(--border-soft); font:600 var(--fs-micro)/1.2 var(--ui); letter-spacing:.01em; text-transform:none; right:auto; } /* A coverless poster carries the title as its artwork, so the caption below it would only repeat itself. Show the caption title when real cover art exists. */ /* Two art treatments already print the title onto the poster: the generated fallback, and the "case" used when only a square icon exists. In both the caption below would just repeat it. */ .game-card:has(.game-card-cover-fallback.is-visible) .game-card-heading, .game-card:has(.game-card-cover-caption) .game-card-heading{display:none} .game-card:has(.game-card-cover-fallback.is-visible) .game-card-body, .game-card:has(.game-card-cover-caption) .game-card-body{padding-top:8px} /* ============================================================================ Title detail: hero header The dialog opened on a fifteen-row key/value table with an empty banner bar. The header now carries the artwork, the name and the identity chips. ========================================================================== */ #modal-header{border-bottom:0} #modal-banner{ filter:blur(18px) saturate(1.15); transform:scale(1.25); opacity:.55; } /* No artwork: a ground derived from the title's own ID, same seed as the card. */ #modal-header::before{ content:"";position:absolute;inset:0; background: radial-gradient(circle at 78% 8%, hsl(var(--modal-hue,265) 72% 48% / .40), transparent 52%), radial-gradient(circle at 12% 96%, hsl(calc(var(--modal-hue,265) + 46) 66% 42% / .30), transparent 55%), linear-gradient(160deg,#181322,#0b0910); } #modal-banner.has-art{opacity:.78} /* Scrim so the title always holds against whatever artwork loads. */ #modal-header::after{ content:"";position:absolute;inset:0;pointer-events:none; background:linear-gradient(180deg,rgba(10,8,14,.30),rgba(18,14,23,.86) 72%,var(--surface)); } #modal-header-content{position:relative;z-index:2} #modal-icon{ width:84px!important;height:84px!important; border-radius:var(--radius-sm)!important; border:1px solid rgba(255,255,255,.14); box-shadow:0 16px 34px -12px rgba(0,0,0,.9)!important; } #modal-header h2#modal-title{text-wrap:balance} #modal-subtitle{ margin-top:6px; font-family:var(--mono); font-size:var(--fs-micro); color:var(--text-dim); letter-spacing:.04em; } #modal-close{ position:relative;z-index:3; width:36px;height:36px;display:grid;place-items:center; border-radius:50%; background:rgba(10,8,14,.55);border:1px solid var(--border-soft); color:var(--text);backdrop-filter:blur(10px); } #modal-close:hover{background:rgba(10,8,14,.8);border-color:var(--accent)} /* Workspace links read as destinations, not as a second toolbar. */ .modal-workspace-links{margin-top:12px;gap:6px} .modal-workspace-links button{ background:rgba(10,8,14,.5)!important; border-color:var(--border-soft)!important; backdrop-filter:blur(10px); } /* --- metric tiles --------------------------------------------------------- */ .modal-metrics{ display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr)); gap:1px;background:var(--border-soft); border:1px solid var(--border-soft);border-radius:var(--radius); overflow:hidden;margin-bottom:18px; } .modal-metric{ display:flex;flex-direction:column;gap:5px; padding:14px 16px;background:var(--surface2); } .modal-metric span{ font-family:var(--mono);font-size:var(--fs-micro); letter-spacing:.11em;text-transform:uppercase;color:var(--text-muted); } .modal-metric strong{ font-family:var(--display);font-size:var(--fs-md);font-weight:600; color:var(--text);font-variant-numeric:tabular-nums;line-height:1.15; } .modal-metric.is-ok strong{color:var(--green)} .modal-metric.is-warn strong{color:var(--yellow)} .modal-metric.is-idle strong{color:var(--text-muted)} /* --- tab strip: fade the overflow instead of showing a raw scrollbar ------- */ .modal-tabs{ position:relative; scrollbar-width:none; -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 44px),transparent); mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 44px),transparent); } .modal-tabs::-webkit-scrollbar{height:0} /* --- metadata table: let absent values recede ----------------------------- */ .detail-table th{ font-family:var(--ui);font-size:var(--fs-xs);font-weight:500; letter-spacing:0;text-transform:none;color:var(--text-muted); } .detail-table td{font-size:var(--fs-xs)} .detail-table td{color:var(--text)} /* ============================================================================ Title detail: subsystem rail Thirteen subsystems sat in a horizontal tab strip that overflowed and had to be scrolled to be read. The same buttons become a vertical rail — every destination scannable at once, no horizontal scroll, and room for the summary to breathe. Structure is untouched: #modal already has exactly four children, so this is a grid re-layout, not a rebuild. Below 760px the original horizontal strip is kept; a rail costs too much width. ========================================================================== */ @media (min-width:760px){ #modal{ display:grid; grid-template-columns:206px minmax(0,1fr); grid-template-rows:auto minmax(0,1fr) auto; } #modal-header{grid-column:1/-1;grid-row:1} #modal-body{grid-column:2;grid-row:2;min-height:0;overflow-y:auto} #modal-footer{grid-column:1/-1;grid-row:3} .modal-tabs{ grid-column:1;grid-row:2; display:flex;flex-direction:column;align-items:stretch; gap:2px; min-height:0; padding:14px 10px 18px; overflow-x:hidden;overflow-y:auto; border-bottom:0; border-right:1px solid var(--border-soft); background:rgba(10,8,14,.28); /* cancel the horizontal overflow fade */ -webkit-mask-image:none;mask-image:none; scrollbar-width:thin; } .modal-tabs::before{ content:"Subsystems"; padding:0 11px 9px; font-family:var(--mono);font-size:var(--fs-micro); letter-spacing:.14em;text-transform:uppercase;color:var(--text-muted); } .modal-tab{ flex:0 0 auto; justify-content:flex-start; min-height:34px; margin-bottom:0; padding:7px 11px; text-align:left; border-bottom:0; border-left:2px solid transparent; border-radius:var(--radius-sm); font-size:var(--fs-xs); } .modal-tab:hover{background:rgba(255,255,255,.045)} .modal-tab.active{ color:var(--text); background:rgba(var(--accent-rgb),.16); border-bottom-color:transparent; border-left-color:var(--accent); } /* the count badge trails the label instead of crowding it */ .modal-tab .tab-badge{margin-left:auto} } /* ============================================================================ Utilities index.html carried 275 inline style attributes. Inline styles beat every stylesheet rule without !important, which is why the type scale could not reach the settings labels no matter what the CSS said. These six recurring declarations are now classes; the remaining ~220 are per-site layout and dynamic values (progress widths) that need judgement, not a find-replace. ========================================================================== */ .u-flex-1{flex:1} .u-push{margin-left:auto} .u-row-8{align-items:center;gap:8px} .u-fs-micro{font-size:var(--fs-micro)} .u-field-md{min-width:150px} .u-field-sm{width:140px} /* otherwise inherits the browser's 0.83em and compounds below the floor. */ small,.hint,.toggle-hint{font-size:var(--fs-xs)} /* An unclassed