/* Collection Visualizer — Styles
 *
 * All card CSS uses the canonical class name fp-card__image-wrap
 * (not the legacy fp-card__img-wrap from folder-preview/browser.js).
 * All card images carry class="no-pswp" to prevent nested-anchor bugs.
 */

.collection-visualizer {
  margin-bottom: var(--spacing-xl, 2rem);
}

.collection__empty {
  color: var(--text-light, #888);
  font-style: italic;
}

/* ── SEO wrapper (search + cards column) ─────────────────────────────────── */

.fp-seo-wrapper {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm, 1rem);
}

/* The collection's filter input is a search surface, so it reads from the SAME
   --sv-* token contract as the site-wide Pagefind bar (lib/visualizers/search/
   styles.css). The two cannot share markup — one is Pagefind's element, one is
   ours — so they share variables instead. A theme that rounds its search bar
   rounds this one; a theme that squares it squares this one.

   Fallbacks are repeated here rather than relied upon from search/styles.css so
   this still renders correctly on a page where the search shape's CSS is not
   loaded (see TECH-DEBT #4, per-page visualizer loading).

   SCOPED to .collection-visualizer on purpose. folder-preview/styles.css
   declares an identical unscoped `.fp-search-input` and, being later in the
   alphabet, its stylesheet loads after this one and wins every tie. Scoping
   this one rule lets the collection's input take the token styling without
   touching folder-preview's input on other sites. The wider `fp-*` collision
   between the two shapes is recorded in TECH-DEBT (#41). */
.collection-visualizer .fp-search-input {
  width: 100%;
  padding: var(--sv-input-pad-y, 0.6em) var(--sv-input-pad-x, 1.25em);
  border: 1px solid var(--border-color, rgba(0, 0, 0, 0.15));
  border-radius: var(--sv-input-radius, 999px);
  font-family: var(--font-body, sans-serif);
  font-size: var(--sv-input-font-size, 1.125rem);
  line-height: 1.4;
  color: var(--text-color, #333);
  background: var(--sv-input-bg, var(--card-bg, #fff));
  box-sizing: border-box;
  transition: background 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
}

.collection-visualizer .fp-search-input::placeholder {
  color: var(--text-light, #666);
}

.collection-visualizer .fp-search-input:focus {
  outline: none;
  border-color: var(--accent-color, #555);
  background: var(--sv-input-bg-focus, var(--sv-input-bg, var(--card-bg, #fff)));
  box-shadow: var(--sv-input-focus-ring, none);
}

.fp-filter-placeholder {
  min-height: 0; /* reserved for filter chips */
}

/* ── Card grid ────────────────────────────────────────────────────────────── */

.fp-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-md, 1.5rem);
}

.fp-card {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: var(--text-color, #333);
  background: var(--card-bg, #fff);
  border: 1px solid var(--border-color, rgba(0, 0, 0, 0.1));
  border-radius: var(--border-radius, 6px);
  overflow: hidden;
  transition: box-shadow 0.15s, transform 0.15s;
}

.fp-card:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

/* Search filtering sets `hidden` on non-matching items. The UA stylesheet turns
   that into display:none only when nothing else sets `display` — and the item
   rules below use flex/grid, which silently win. Without these overrides the
   property flips and the element stays on screen.

   Kept together so a new display mode is an obvious addition. Guarded by
   tests/collection-search-visibility.test.js, which measures rendered geometry;
   asserting `el.hidden === true` cannot catch this, since that only reads back
   the value the filter just set. */
.fp-card[hidden],
.collection-visualizer .fp-marble[hidden],
.collection-visualizer .fp-bubble[hidden],
.collection-visualizer .folder-preview__item[hidden] {
  display: none;
}

/* fp-card__image-wrap: canonical class name used by collection.
   folder-preview/styles.css also defines fp-card__img-wrap (legacy runtime
   class) and fp-card__image-wrap (SEO class) — both still load on AE pages
   where folder-preview is active (articles slider). */
.fp-card__image-wrap {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--border-color, rgba(0, 0, 0, 0.06));
  flex-shrink: 0;
}

.fp-card__image-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.fp-card__image-wrap--placeholder {
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--accent-color, #9b6dff) 18%, var(--bg-color, #ece8f4) 82%) 0%,
    var(--bg-color, #ece8f4) 100%
  );
}

.fp-card__body {
  padding: var(--spacing-sm, 1rem);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 1;
}

/* SELF-SUFFICIENCY RULE (TECH-DEBT #41) — scoped so collection renders the same
   whether or not folder-preview.css is loaded. That matters for per-page
   visualizer loading (#4), which drops stylesheets a page doesn't use.

   folder-preview/styles.css declares `.fp-card__title` TWICE: line ~99 (a small
   uppercase label, matching collection's own intent) and line ~349, a later
   override styling it as a 16px headline for folder-preview's own SEO grid.
   Load order means line 349 wins, so **that is what AE's collection cards
   render today** — verified in a browser, not assumed.

   These values deliberately replicate line 349 so nothing changes on the live
   AE site, and so AE's folder-preview cards and collection cards keep matching.

   REVIEWED 2026-07-28 against the live AE build: scoping this rule DID change
   AE, because a theme override cannot reach it. AE's own override used a bare
   `.fp-card__title` (0,1,0) and now loses to this selector (0,2,0) no matter
   how late it loads, so AE's small orange label reverted to this grey headline.
   Fixed by matching the scope in themes/alter-engineers/assets/css/visualizers/
   collection.css. Anyone scoping a rule here must expect the same: raising
   specificity in shared CSS silently outranks every theme override of it.

   What AE renders today is actually a MERGE of folder-preview's two rules:
   font-size/weight/family/colour/margin from line 349, text-transform and
   letter-spacing from line 99 (which line 349 never resets). Both are
   replicated below, so this single scoped rule reproduces the merged result
   exactly — confirmed identical with and without folder-preview.css across all
   four themes. */
.collection-visualizer .fp-card__title {
  display: block;
  font-family: var(--font-heading, sans-serif);
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  color: var(--text-color, #333);
  line-height: 1.35;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Main headline — themes override in their visualizer override CSS */
.fp-card__subtitle {
  display: block;
  font-size: clamp(0.95rem, 2vw, 1.1rem);
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-color, #1a1a1a);
  margin: 0 0 0.5rem;
}

/* One field per line, kept tight. `show_fields: building_type, location, sqft`
   is a spec list, not prose — running the values together on a wrapped row made
   them hard to scan. Column direction rather than a row that happens to wrap,
   so a short pair like "School" + "Oakland" still gets its own line each. */
.fp-card__fields {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: 0.25rem;
}

.fp-field {
  display: inline-flex;
  gap: 0.25em;
  font-size: 0.78rem;
  line-height: 1.4;
}

.fp-field__label {
  font-weight: 600;
  color: var(--accent-color, #555);
}

.fp-field__label::after {
  content: ":";
}

.fp-field__value {
  color: var(--text-color, #555);
  opacity: 0.8;
}

/* ── List display ─────────────────────────────────────────────────────────── */

.folder-preview__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1em;
}

.folder-preview__item {
  border-bottom: 1px solid var(--border-color, rgba(0, 0, 0, 0.08));
}

/* Scoped for self-sufficiency (TECH-DEBT #41), same reason as .fp-card__title.
   Here collection's value is kept rather than folder-preview's: folder-preview
   falls back to a hardcoded `#914c9a` (marbles purple), which renders a stray
   purple link on any non-marbles theme. Falling back to the theme's own accent
   is the correct behaviour, so scoping this *fixes* list mode on AE rather than
   preserving a bug. AE does not currently use `display: list`. */
.collection-visualizer .folder-preview__link {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.55em 0.25em;
  text-decoration: none;
  color: var(--link-color, var(--accent-color, #555));
  font-weight: 500;
  transition: color 0.12s;
}

.collection-visualizer .folder-preview__link:hover {
  color: var(--accent-dark, var(--accent-color, #333));
}

.folder-preview__icon {
  width: 1.1em;
  height: 1.1em;
  object-fit: contain;
  flex-shrink: 0;
  border-radius: 0;
}

/* ── Bubbles display ──────────────────────────────────────────────────────── */

.fp-bubbles {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
  padding: 20px 24px 60px;
  align-items: flex-start;
}

.fp-bubble {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  text-decoration: none;
  text-align: center;
  padding: 16px;
  cursor: pointer;
  flex-shrink: 0;
  background: radial-gradient(
    circle at 40% 32%,
    rgba(190, 210, 248, 0.52) 0%,
    rgba(165, 185, 232, 0.32) 55%,
    transparent 100%
  );
  box-shadow: 0 8px 32px rgba(80, 60, 140, 0.2);
  -webkit-mask-image: radial-gradient(circle, black 50%, transparent 80%);
  mask-image: radial-gradient(circle, black 50%, transparent 80%);
  transition: transform 0.2s ease;
}

.fp-bubble:hover {
  transform: scale(1.06);
  -webkit-mask-image: radial-gradient(circle, black 60%, transparent 86%);
  mask-image: radial-gradient(circle, black 60%, transparent 86%);
}

.fp-bubble__type {
  display: block;
  font-size: 0.65rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* Same fix + rationale as lib/visualizers/folder-preview/styles.css: this bubble is a
     light glassmorphism fill, not a dark backdrop — hardcoded white was illegible on light
     themes. Token-driven so each theme's own text color applies. */
  color: var(--text-light, rgba(0, 0, 0, 0.55));
  margin-bottom: 5px;
  pointer-events: none;
}

.fp-bubble__title {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-color, #1a1a1a);
  line-height: 1.3;
  pointer-events: none;
}

@media (max-width: 480px) {
  .fp-bubble { width: 110px !important; height: 110px !important; margin-top: 0 !important; }
  .fp-bubbles { gap: 12px; }
}

/* ── Marbles display ──────────────────────────────────────────────────────── */

.fp-marbles {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  padding: 20px 24px 60px;
  align-items: flex-start;
}

.fp-marble {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
  cursor: grab;
  border-radius: 50%;
  flex-shrink: 0;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  will-change: transform;
}

.fp-marble--dragging {
  cursor: grabbing;
  z-index: 100;
}

.fp-marble__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  opacity: 0.38;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.fp-marble__title {
  position: relative;
  z-index: 1;
  /* Same fix + rationale as folder-preview's .fp-marble__title: no background of its own,
     shows the page background through at low opacity, so dark theme text (not white) is
     what's actually legible. Shadow flipped to a light halo to match. */
  color: var(--text-color, #1a1a1a);
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
  padding: 0 14px;
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.7);
  pointer-events: none;
}

@media (max-width: 480px) {
  .fp-marble { width: 110px !important; height: 110px !important; margin-top: 0 !important; }
  .fp-marbles { gap: 10px; }
}

/* ── Responsive ───────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .fp-cards { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
  .fp-cards { grid-template-columns: 1fr; }
}

/* ── Nested-shape presentation guard ─────────────────────────────────────────
   A collection is frequently rendered INSIDE another shape's body — the folder
   index is literally an article shape with a collection in it. Container shapes
   style their prose, and `.article-body a { text-decoration: underline }` is
   (0,1,1), which beats a bare `.fp-marble` (0,1,0) and underlined every marble
   title on melt after its pages moved onto the article shape.

   The container is not wrong to underline prose links — so the nested shape
   wins by scoping to its own container instead. Guarded by
   tests/shape-nesting.test.js. */
.collection-visualizer .fp-card,
.collection-visualizer .fp-marble,
.collection-visualizer .fp-bubble,
.collection-visualizer .folder-preview__link {
  text-decoration: none;
}
