/* App center cards, grid, tags, and detail view. Extracted from style.css. */ .apps-section { --app-min: 328px; --app-gap: 20px; display: grid; /* auto-fit + minmax(min, 1fr): tracks stretch to fill the row width so zooming out gives wider cards instead of a card-shaped hole on the right (each track is at least --app-min wide; the 1fr upper bound shares any remaining content width across them). auto-fit collapses trailing empty tracks so a 2-card row in a 3-track-wide viewport doesn't leave a fixed-width empty slot at the end. The tradeoff is that card widths vary between categories (a 2-card category gets fatter cards than a 3-card one) and between viewport widths — that's the price of "box always reaches the layout edge". The 22px margin handles the gutter from the parent; no explicit max-width cap needed. */ grid-template-columns: repeat(auto-fit, minmax(var(--app-min), 1fr)); gap: var(--app-gap); margin: 22px; padding: 22px; background: rgba(var(--text-rgb), 0.025); border: 1px solid var(--border-subtle); border-radius: 16px; } /* Override grid styling when showing loading content */ .apps-section .loading-content { position: absolute !important; top: 20px !important; left: 20px !important; right: 20px !important; bottom: 0 !important; display: flex !important; flex-direction: column !important; justify-content: center !important; align-items: center !important; width: calc(100% - 40px) !important; height: calc(100% - 20px) !important; padding: 60px 20px !important; background: var(--input-bg) !important; border: 2px solid var(--border-color) !important; border-radius: 12px !important; box-sizing: border-box !important; margin: 0 !important; min-height: 400px !important; } /* Make apps-section relative for absolute positioning */ .apps-section { position: relative !important; } .app-card { background: var(--card-bg); border: 1px solid var(--card-border); border-radius: 12px; padding: 20px; display: flex; flex-direction: column; gap: 16px; box-shadow: var(--card-shadow); transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s; min-height: 120px; width: 100%; position: relative; } .app-card-top { display: flex; align-items: flex-start; gap: 16px; } .app-card-icon { width: 70px; height: 70px; background: rgba(var(--text-rgb), 0.1); border-radius: 12px; display: flex; align-items: center; justify-content: center; padding: 12px; border: 1px solid rgba(var(--text-rgb), 0.2); flex-shrink: 0; } .app-card-icon svg { width: 100%; height: 100%; object-fit: contain; } .app-card-icon img { width: 100%; height: 100%; object-fit: contain; max-width: 100%; max-height: 100%; } .app-card-content { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; } .app-card-title { font-size: 16px; font-weight: 600; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .app-card-long-description { font-size: 11px; color: var(--text-secondary); line-height: 1.3; margin-top: 8px; margin-bottom: 8px; display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; /* Standard property */ -webkit-box-orient: vertical; overflow: hidden; font-style: italic; width: 100%; } .app-card-tags { display: flex; flex-wrap: wrap; gap: 8px; } .app-tag { display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 12px; font-size: 12px; font-weight: 500; border: 1px solid; transition: all 0.2s ease; } /* Category tags - Blue */ .app-tag.category-tag { background: rgba(var(--accent-rgb), 0.1); color: var(--accent); border-color: rgba(var(--accent-rgb), 0.2); } .app-tag.category-tag:hover { background: rgba(var(--accent-rgb), 0.2); transform: translateY(-1px); } /* Description tags - White to match title */ .app-tag.description-tag { background: rgba(var(--text-rgb), 0.1); color: var(--text-primary); border-color: rgba(var(--text-rgb), 0.2); font-style: italic; } /* Installed tags - Green. Light pastel green text on a saturated green pill so the label stays in the green family but actually reads on dark themes (the default --status-success #28a745 is too dark at small sizes). Leading ✓ glyph reinforces the state at a glance. */ .app-tag.installed-tag { background: rgba(var(--status-success-rgb), 0.35); color: #86efac; border-color: rgba(var(--status-success-rgb), 0.70); transform: translateY(-2px); } .app-tag.installed-tag::before { content: '✓'; margin-right: 5px; font-weight: 700; line-height: 1; } /* Not Installed tags - Gray with a leading ✕ glyph for symmetry with the ✓ on the installed pill. */ .app-tag.not-installed-tag { background: rgba(var(--text-rgb), 0.10); color: var(--text-secondary); border-color: rgba(var(--text-rgb), 0.30); } .app-tag.not-installed-tag::before { content: '✕'; margin-right: 5px; font-weight: 700; line-height: 1; } /* Clickable tags (category / installed-status) — jump to that filter view */ .app-tag.clickable { cursor: pointer; } .app-tag.clickable:hover { transform: translateY(-1px); } .app-tag img { width: 12px; height: 12px; margin: 0; } .app-card-actions { display: flex; gap: 8px; align-items: stretch; flex-direction: row; margin-top: auto; overflow: visible; position: relative; } .app-card-actions button { flex: 1; } .app-card:hover { transform: translateY(-3px); border-color: var(--accent) !important; box-shadow: var(--card-shadow-hover); } .app-card button { margin-top: 0; padding: 12px 16px; border: none; border-radius: 8px; font-weight: 600; cursor: pointer; transition: background 0.2s, transform 0.2s; font-size: 14px; text-align: center; min-height: 44px; display: flex; align-items: center; justify-content: center; gap: 8px; white-space: nowrap; } .app-icon { width: 80px; height: 80px; border-radius: 12px; flex-shrink: 0; } .app-icon img { width: 100%; height: 100%; object-fit: contain; max-width: 100%; max-height: 100%; } .app-details .app-description { font-size: 16px; color: var(--text-secondary, #ccc); margin-bottom: 8px; } /* .btn-primary / .btn-secondary / .btn-outline / .btn-danger live in themes.css with the nebula-glass treatment. .btn-install / .btn-manage / .btn-uninstall ditto. */ /* App-card manage / install button styling lives in themes.css. The previous block was 6 layers of "ultra-specific" selectors re-asserting solid-colour fallbacks — all dead now that themes.css owns the glass treatment with !important. */ /* Force green with attribute selectors */ .app-card-actions button[class*="install-btn"] { background: var(--status-success) !important; color: #ffffff !important; border: 1px solid var(--status-success) !important; } .app-card-actions button[class*="install-btn"]:hover { background: var(--status-success-hover) !important; border-color: var(--status-success-hover) !important; } .installed-apps .app-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 12px; padding: 20px; transition: all 0.2s ease; cursor: pointer; } .installed-apps .app-card:hover { transform: translateY(-2px); box-shadow: var(--card-shadow-hover); border-color: var(--primary-color); } .installed-apps .app-card-top { display: flex; align-items: center; gap: 16px; } .installed-apps .app-card-icon { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; border-radius: 8px; flex-shrink: 0; } .installed-apps .app-card-icon img { width: 32px; height: 32px; object-fit: contain; } .installed-apps .app-card-content { flex: 1; min-width: 0; } .installed-apps .app-card-title { font-size: 16px; font-weight: 600; color: var(--text-color); margin: 0 0 4px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .installed-apps .app-card-description { font-size: 14px; color: var(--text-secondary, #ccc); margin: 0; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; /* Standard property */ -webkit-box-orient: vertical; overflow: hidden; } .installed-apps .app-card-actions { display: flex; align-items: center; gap: 8px; } .installed-apps .app-card-actions .manage-btn { display: flex; align-items: center; gap: 6px; background: var(--accent) !important; color: var(--text-primary) !important; border: 1px solid var(--accent) !important; border-radius: 6px; font-size: 12px; font-weight: 600 !important; cursor: pointer; transition: all 0.2s; } .installed-apps .app-card-actions .manage-btn:hover { background: var(--accent-hover) !important; border-color: var(--accent-hover) !important; transform: translateY(-1px) !important; } /* Extra specific rules for index page manage button */ .app-card-actions .btn-loading.manage-btn { color: transparent !important; } .app-card-actions .btn-loading.manage-btn * { opacity: 0 !important; visibility: hidden !important; } @media (max-width: 768px) { .apps-section { margin: 10px; padding: 12px; gap: 12px; /* Mobile is always a single column — let it fill width regardless of how many cards there are (no auto-centering, no card-count cap). */ max-width: none; } /* Install screen action buttons stack full-width below the console. */ .console-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; } .console-actions .btn { width: 100%; justify-content: center; } }