.search-field { width: min(28rem, 40vw); @media (max-width: 899px) { width: 12rem; } @media (max-width: 599px) { width: 100%; } } .filters { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; padding: 1rem 1.5rem 0.5rem; mat-form-field { min-width: 10rem; } @media (max-width: 599px) { padding-inline: 1rem; mat-form-field { flex: 1 1 8rem; min-width: 0; } } } .grid { display: grid; /* Cards size themselves; no masonry library required for this. */ grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 1rem; padding: 1rem 1.5rem; @media (max-width: 599px) { grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: 0.75rem; padding: 0.75rem 1rem; } } .game-card { display: flex; flex-direction: column; padding: 0; overflow: hidden; cursor: pointer; transition: transform 120ms ease, box-shadow 120ms ease; &:hover, &:focus-visible { transform: translateY(-2px); box-shadow: var(--mat-sys-level3); } &:focus-visible { outline: 2px solid var(--mat-sys-primary); outline-offset: 2px; } .art { aspect-ratio: 3 / 4; background: var(--mat-sys-surface-container-high); } img { width: 100%; height: 100%; /* `contain`, not `cover`: box art spans everything from near-square SNES boxes to tall N64 ones, and cropping to a single ratio slices the title off the edges. Letterboxing against the tile background shows the whole cover, which is what the user is scanning for. */ object-fit: contain; display: block; } .art-placeholder { display: grid; place-items: center; height: 100%; color: var(--mat-sys-outline); mat-icon { font-size: 2.5rem; width: 2.5rem; height: 2.5rem; } } .body { display: flex; flex-direction: column; gap: 0.25rem; padding: 0.625rem 0.75rem 0.75rem; } .title { margin: 0; font-size: 0.9rem; font-weight: 600; line-height: 1.3; /* Two lines, then ellipsis — keeps every card the same height. */ display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .meta { display: flex; gap: 0.5rem; margin: 0; font-size: 0.75rem; color: var(--mat-sys-on-surface-variant); } .system { font-weight: 600; } } .badges { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.125rem; } .badge { font-size: 0.625rem; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; padding: 0.125rem 0.375rem; border-radius: 0.25rem; background: var(--mat-sys-surface-container-highest); color: var(--mat-sys-on-surface-variant); &--finished { background: var(--mat-sys-primary); color: var(--mat-sys-on-primary); } &--played { background: var(--mat-sys-tertiary-container); color: var(--mat-sys-on-tertiary-container); } } .state-panel { display: grid; place-items: center; gap: 0.75rem; padding: 4rem 1.5rem; text-align: center; color: var(--mat-sys-on-surface-variant); mat-icon { font-size: 3rem; width: 3rem; height: 3rem; opacity: 0.6; } h2 { margin: 0; font-size: 1.125rem; font-weight: 500; } p { margin: 0; max-width: 28rem; } } mat-paginator { background: transparent; }