/* COMPONENTS — reusable widgets. Each block is self-contained and named after the thing it styles (BEM-ish: block, block__element, block--modifier). Theme values come from tokens.css; never hardcode colors/sizes here if a token exists. */ /* ---- buttons ------------------------------------------------------------- */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-2) var(--space-4); border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm); background: var(--color-surface-2); color: var(--color-text); font-size: var(--text-sm); font-weight: var(--font-weight-medium); line-height: 1.3; cursor: pointer; user-select: none; transition: background 120ms ease, border-color 120ms ease; } .btn:hover { background: var(--color-surface-hover); border-color: var(--color-border-strong); } .btn:active { transform: translateY(1px); } .btn:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; } .btn--primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-text); } .btn--primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); } .btn--ghost { background: transparent; border-color: transparent; color: var(--color-text-dim); } .btn--ghost:hover { background: var(--color-surface); color: var(--color-text); } .btn--sm { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); } .btn:disabled { opacity: 0.5; cursor: default; pointer-events: none; } /* ---- form fields --------------------------------------------------------- */ .field { width: 100%; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface-2); color: var(--color-text); font: inherit; font-size: var(--text-sm); } .field::placeholder { color: var(--color-text-faint); } .field:focus { outline: none; border-color: var(--color-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 25%, transparent); } select.field { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2398a2b0' stroke-width='2'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 32px; } .field-label { display: block; margin-bottom: var(--space-1); font-size: var(--text-xs); font-weight: var(--font-weight-medium); color: var(--color-text-dim); } /* ---- badges & tags -------------------------------------------------------- */ .badge { display: inline-flex; align-items: center; padding: 1px var(--space-2); border: 1px solid var(--color-border-strong); border-radius: var(--radius-full); font-size: var(--text-xs); font-weight: var(--font-weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-text-dim); white-space: nowrap; } .badge--accent { border-color: var(--color-accent); color: var(--color-accent); } .tag { display: inline-block; padding: 2px var(--space-2); border-radius: var(--radius-sm); background: var(--color-surface-2); border: 1px solid var(--color-border); font-size: var(--text-xs); color: var(--color-text-dim); } /* ---- chips (filters) ------------------------------------------------------- */ .chips { display: flex; flex-wrap: wrap; gap: var(--space-2); } .chip { padding: var(--space-1) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-full); background: transparent; color: var(--color-text-dim); font-size: var(--text-sm); font-weight: var(--font-weight-medium); cursor: pointer; transition: background 120ms ease, color 120ms ease, border-color 120ms ease; } .chip:hover { border-color: var(--color-border-strong); color: var(--color-text); } .chip--active { background: var(--color-surface); border-color: var(--color-accent); color: var(--color-text); } /* ---- media cards (poster) --------------------------------------------------- */ .card { display: block; flex: 0 0 var(--card-width); width: var(--card-width); cursor: pointer; } .card__poster { position: relative; aspect-ratio: var(--poster-aspect); border-radius: var(--radius-md); overflow: hidden; background: var(--color-surface); border: 1px solid var(--color-border); transition: border-color 120ms ease, transform 120ms ease; } .card:hover .card__poster { border-color: var(--color-border-strong); transform: translateY(-2px); } .card__poster img { width: 100%; height: 100%; object-fit: cover; } .card__poster--empty { display: flex; align-items: center; justify-content: center; color: var(--color-text-faint); font-size: var(--text-2xl); } .card__title { margin-top: var(--space-2); font-size: var(--text-sm); font-weight: var(--font-weight-medium); line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .card__meta { margin-top: 2px; font-size: var(--text-xs); color: var(--color-text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .card__progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(255, 255, 255, 0.15); } .card__progress i { display: block; height: 100%; background: var(--color-accent); } /* ---- rows (horizontal carousels) ------------------------------------------ */ .row { margin-bottom: var(--space-6); } .row__header { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); } .row__title { font-size: var(--text-lg); font-weight: var(--font-weight-semibold); } .row__link { font-size: var(--text-sm); color: var(--color-text-dim); } .row__link:hover { color: var(--color-text); } .row__scroll { display: flex; gap: var(--space-3); overflow-x: auto; scroll-snap-type: x proximity; padding-bottom: var(--space-2); scrollbar-width: thin; scrollbar-color: var(--color-border-strong) transparent; } .row__scroll .card { scroll-snap-align: start; } /* ---- results grid ---------------------------------------------------------- */ .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--card-width), 1fr)); gap: var(--space-4); } .grid .card { flex: none; width: auto; } /* ---- modal ----------------------------------------------------------------- */ .modal-overlay { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: var(--space-4); background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); } .modal { width: 100%; max-width: 460px; border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); box-shadow: var(--shadow-2); } .modal__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--color-border); } .modal__title { font-size: var(--text-lg); font-weight: var(--font-weight-semibold); } .modal__body { padding: var(--space-5); display: grid; gap: var(--space-4); } .modal__hint { font-size: var(--text-xs); color: var(--color-text-faint); } .modal__actions { display: flex; justify-content: flex-end; gap: var(--space-2); padding: var(--space-4) var(--space-5); border-top: 1px solid var(--color-border); } /* ---- toast ----------------------------------------------------------------- */ .toast { position: fixed; left: 50%; bottom: var(--space-6); z-index: 110; transform: translateX(-50%); max-width: min(90vw, 480px); padding: var(--space-2) var(--space-4); border: 1px solid var(--color-border-strong); border-radius: var(--radius-md); background: var(--color-surface); box-shadow: var(--shadow-2); font-size: var(--text-sm); opacity: 0; pointer-events: none; transition: opacity 150ms ease, transform 150ms ease; } .toast--show { opacity: 1; } .toast--error { border-color: var(--color-danger); color: var(--color-danger); } /* ---- loading & empty states ------------------------------------------------- */ .spinner { width: 28px; height: 28px; border: 3px solid var(--color-border); border-top-color: var(--color-accent); border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .spinner--center { padding: var(--space-8) 0; text-align: center; } .empty { padding: var(--space-7) 0; text-align: center; color: var(--color-text-faint); } .empty h3 { font-size: var(--text-lg); color: var(--color-text-dim); margin-bottom: var(--space-2); }