/* ============================================================================
 * COMPONENT — Feed (infinite scroll listing)
 * ----------------------------------------------------------------------------
 * Renderers: shared/components/feed-open.php / feed-close.php
 * Behaviour: shared/assets/js/feed.js
 *
 * The default shape for every public listing: jobs, services, institutions,
 * teachers. More rows load as the reader scrolls, with the total shown at the
 * top so they always know how much there is.
 *
 * The "load more" control underneath is a REAL link to ?page=2. JavaScript
 * hides it and takes over; without JavaScript — and for a crawler — it is
 * ordinary pagination and the whole list is still reachable. That is what keeps
 * a listing indexable while it behaves like a feed for people.
 * ========================================================================== */

/* --------------------------------------------------------------------------
 * Header — the count, always visible above the list
 * ----------------------------------------------------------------------- */

.feed__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-block-end: var(--sp-4);
}

.feed__count {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: var(--fs-base);
  color: var(--ink-soft);
}

.feed__total {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  color: var(--ink);
  /* Tabular figures: the number changes as more rows arrive, and proportional
     digits make the label jitter sideways each time it does. */
  font-variant-numeric: tabular-nums;
  font-family: var(--font-latin);
}

/* "showing 20 of 412" — updated by feed.js as pages arrive. */
.feed__shown {
  font-size: var(--fs-sm);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.feed__actions {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* --------------------------------------------------------------------------
 * Items
 * ----------------------------------------------------------------------- */

.feed__items {
  display: grid;
  gap: var(--sp-4);
}

.feed__items--cards {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}

/* Rows arriving from a fetch fade in, so an appended block is noticed rather
   than silently appearing under the thumb. */
.feed__items > .is-new {
  animation: feed-in var(--dur-base) var(--ease-out);
}

@keyframes feed-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .feed__items > .is-new { animation: none; }
}

/* --------------------------------------------------------------------------
 * Footer — sentinel, spinner, the real link
 * ----------------------------------------------------------------------- */

.feed__foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  /* Tall enough that the observer fires before the reader hits the bottom, so
     the next rows are usually already there by the time they arrive. */
  min-block-size: 80px;
  padding-block: var(--sp-6);
}

.feed__spinner {
  inline-size: 26px;
  block-size: 26px;
  border: 2.5px solid var(--border-strong);
  border-block-start-color: var(--brand);
  border-radius: var(--r-full);
  animation: feed-spin 700ms linear infinite;
}

@keyframes feed-spin {
  to { transform: rotate(360deg); }
}

.feed__status {
  font-size: var(--fs-sm);
  color: var(--ink-muted);
  text-align: center;
}

/* The end of the list is stated, not left to silence — otherwise a reader
   cannot tell "that is everything" from "it failed to load". */
.feed__end {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  inline-size: 100%;
  max-inline-size: 340px;
  color: var(--ink-muted);
  font-size: var(--fs-sm);
}

.feed__end::before,
.feed__end::after {
  content: "";
  flex: 1 1 auto;
  block-size: 1px;
  background: var(--border);
}

/* -- states ---------------------------------------------------------------
 * feed.js sets data-state on .feed__foot; each state shows exactly one child.
 * Driving it from one attribute keeps the possible combinations to four, and
 * makes an impossible pairing — spinner plus end-of-list — unrepresentable.
 *
 * TWO OF THE FIVE CHILDREN ARE .btn (feed__more, feed__retry — rendered by
 * the button component). button.css sets `.btn { display: inline-flex }` at
 * one-class specificity, so a bare `.feed__foot > *` hide rule — also one
 * class, since the universal selector and the child combinator both add zero
 * — ties with it, and the tie is broken by CSS LOAD ORDER: whichever
 * stylesheet the page happened to register second wins. That made this
 * button visible or not depending on what a PAGE'S OWN Assets::component()
 * call listed 'button' before or after 'feed' — nothing about feed.css
 * itself. Named here instead of `*`, matching the two-class specificity the
 * "show" rules below already use, so the hide rule beats `.btn`
 * unconditionally and stops being a coin flip decided by an unrelated page. */
.feed__foot > .feed__more,
.feed__foot > .feed__spinner,
.feed__foot > .feed__status,
.feed__foot > .feed__retry,
.feed__foot > .feed__end {
  display: none;
}

.feed__foot[data-state="idle"]    .feed__more,
.feed__foot[data-state="loading"] .feed__spinner,
.feed__foot[data-state="loading"] .feed__status,
.feed__foot[data-state="error"]   .feed__status,
.feed__foot[data-state="error"]   .feed__retry,
.feed__foot[data-state="done"]    .feed__end {
  display: flex;
}

/* Once feed.js is driving, the fallback button is redundant — auto-loading and
   a "load more" button at the same time is just two ways to do one thing. */
.feed__foot.is-enhanced[data-state="idle"] .feed__more { display: none; }
