/* Apps store page (sohub skin). Shared chrome (pills, tags, nav v3, footer v3)
   lives in base.css. Same house rule as work.css: depth comes from colour
   blocking, scale and overlap — no borders, no shadows, no image filters.

   The store reads App Store / Play Store: squircle icons, a featured card, a
   scrollable chip rail, then a card grid of rows (icon · name · meta · action).
   Everything that is not shipped says so in plain words instead of pretending. */

/* ---------- Page head ---------- */

.apps-head {
  padding-top: calc(var(--nav-height) + clamp(3rem, 10vh, 6rem));
  padding-bottom: clamp(2.5rem, 6vh, 4rem);
}
.apps-head .eyebrow { display: block; margin-bottom: 1.25rem; }
.apps-head .statement { max-width: 14ch; }
.apps-head .page-lede {
  margin-top: 1.75rem;
  max-width: 54ch;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  line-height: 1.55;
}
.apps-head .tag-row { margin-top: 2.25rem; }

/* Live count gets a pulsing dot so "7 live" reads as a fact, not a label. */
.tag-live { display: inline-flex; align-items: center; gap: 0.5rem; }
.tag-live::before {
  content: '';
  width: 0.5rem; height: 0.5rem;
  border-radius: 50%;
  background: var(--blue);
  animation: live-pulse 2.4s var(--ease-out) infinite;
}
@keyframes live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.72); }
}
@media (prefers-reduced-motion: reduce) { .tag-live::before { animation: none; } }

/* ---------- The squircle ---------- */

.app-icon {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 23%;              /* the store-standard superellipse approximation */
  overflow: hidden;
  background: var(--ink);
  transition: transform 0.45s var(--ease-spring);
}
.app-icon img, .app-icon svg { display: block; width: 100%; height: 100%; }

/* Marks that were drawn as a logo rather than an icon need breathing room
   inside the tile; full-bleed icons (POLA, Cat Fresh Mart) must not get any. */
.app-icon--inset img { width: 76%; height: 76%; }

/* A single hairline of light along the top edge, the way store icons catch it.
   Inset, so it is part of the tile rather than a border around it. */
.app-icon::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0) 42%);
  pointer-events: none;
}

/* ---------- Featured card ---------- */

.store-featured {
  padding-bottom: clamp(2.5rem, 6vh, 4rem);
}
.featured-card {
  position: relative;
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  padding: clamp(1.75rem, 4vw, 3.25rem);
  border-radius: var(--r-mega);
  background: var(--ink);
  color: var(--on-dark);
  overflow: hidden;
  isolation: isolate;
}
/* Colour blocking, not a shadow: a bright-blue wash bleeding in from the right. */
.featured-card::before {
  content: '';
  position: absolute;
  inset: -40% -20% auto auto;
  width: 70%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--deck-1) 0%, rgba(37, 99, 255, 0) 68%);
  opacity: 0.55;
  z-index: -1;
}
.featured-eyebrow {
  font-size: var(--text-small);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--blue-light);
}
.featured-body { display: grid; gap: 1.5rem; }
.featured-top {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.5vw, 1.75rem);
  flex-wrap: wrap;
}
.featured-card .app-icon {
  width: clamp(5rem, 12vw, 7.5rem);
  height: clamp(5rem, 12vw, 7.5rem);
}
.featured-name {
  font-size: clamp(2rem, 5vw, 3.75rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-5);
}
.featured-meta {
  margin-top: 0.6rem;
  font-size: var(--text-small);
  color: var(--blue-light);
}
.featured-lede {
  max-width: 46ch;
  font-size: clamp(1.05rem, 1.7vw, 1.4rem);
  line-height: 1.5;
  color: var(--on-dark);
}
.featured-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.featured-card .pill-light { background: var(--bg); color: var(--ink); }
.featured-card .tag { background: var(--tag-bg); color: var(--on-dark); }

@media (min-width: 900px) {
  .featured-card { grid-template-columns: 1fr; }
  .featured-top { flex-wrap: nowrap; }
}

/* ---------- Chip rail ---------- */

/* Edge-to-edge scroll on phones so the rail reads as a store filter row and
   the last chip is visibly cut off, which is what invites the swipe. */
.filter-bar {
  display: flex;
  gap: 0.6rem;
  overflow-x: auto;
  scrollbar-width: none;
  padding-block: 0.25rem clamp(1.75rem, 4vh, 2.5rem);
  padding-inline: var(--gutter);
  margin-inline: 0;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.filter-bar::-webkit-scrollbar { display: none; }
.filter-bar .chip { flex: none; scroll-snap-align: start; }

.chip {
  border: 0;
  border-radius: var(--r-pill);
  padding: 0.7rem 1.2rem;
  font: inherit;
  font-size: var(--text-small);
  font-weight: 600;
  letter-spacing: var(--track-3);
  background: var(--soft);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.3s var(--ease-out), color 0.3s var(--ease-out), transform 0.3s var(--ease-pill);
}
.chip:hover { transform: scale(1.06); }
.chip[aria-pressed="true"] { background: var(--ink); color: var(--on-dark); }

.filter-status {
  padding-inline: var(--gutter);
  margin-bottom: 1.25rem;
  font-size: var(--text-small);
  color: var(--muted);
}

/* ---------- App grid ---------- */

.app-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  padding-bottom: clamp(3rem, 8vh, 5rem);
  align-items: stretch;    /* every card in a row is the same height... */
}
@media (min-width: 760px)  { .app-grid { grid-template-columns: 1fr 1fr; gap: 1.25rem; } }
@media (min-width: 1280px) { .app-grid { grid-template-columns: 1fr 1fr 1fr; gap: 1.5rem; } }

.app-card {
  display: grid;
  /* ...so the description takes the slack and every action pill in the row
     lands on the same line, the way a store's rows align. */
  grid-template-rows: auto 1fr auto;
  gap: 1.1rem;
  padding: clamp(1.15rem, 2.2vw, 1.6rem);
  border-radius: var(--r-panel);
  background: var(--soft);
  color: var(--ink);
  text-decoration: none;
  transition: transform 0.4s var(--ease-spring), background 0.3s var(--ease-out);
}
a.app-card:hover { transform: scale(1.02); background: #cbdcff; }
a.app-card:hover .app-icon { transform: scale(1.07) rotate(-3deg); }

.app-card-top {
  display: flex;
  align-items: center;
  gap: 0.95rem;
}
.app-card .app-icon {
  width: clamp(3.75rem, 8vw, 4.5rem);
  height: clamp(3.75rem, 8vw, 4.5rem);
}
.app-card-id { min-width: 0; flex: 1 1 auto; }
/* Name and meta are spans (they sit inside the card's single <a>), so they have
   to be told to stack — left inline they run together on one line. */
.app-name {
  display: block;
  font-size: clamp(1.15rem, 1.7vw, 1.4rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: var(--track-3);
}
.app-meta {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.8125rem;
  line-height: 1.35;
  color: var(--muted);
}
.app-desc {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--ink);
  opacity: 0.78;
}
.app-card-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
}
/* The action reads as the store's GET button: dark pill, arrow that slides. */
.app-card .pill-dark { background: var(--ink); color: var(--on-dark); }
.app-card:hover .pill .pill-chip svg.swap-out { transform: translateX(250%); }
.app-card:hover .pill .pill-chip svg.swap-in { transform: translateX(0); }

/* Not shipped yet: quieter surface, and the action is a tag, never a button. */
.app-card--soon { background: #e3ecff; }
.app-card--soon .app-icon { opacity: 0.62; }
.app-card--soon .app-name { color: var(--muted); }
.app-card--soon .tag { background: var(--soft); color: var(--muted); }

.app-card[hidden] { display: none; }

.apps-empty {
  padding-block: clamp(2rem, 6vh, 4rem);
  color: var(--muted);
}
.apps-empty[hidden] { display: none; }

/* Grid entrance + filter transitions are owned by apps.js, not ScrollTrigger:
   a card the filter has hidden never trips a scroll trigger, so a `once:true`
   reveal would strand it at opacity 0 the moment it is filtered back in.
   The hidden state is keyed off `html.apps-js`, a class apps.js sets on its own
   first line — so if that script fails to load, the grid renders fully visible
   instead of blank. */
html.apps-js .app-card {
  opacity: 0;
  transform: translateY(22px);
}
html.apps-js .app-card.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
html.apps-js a.app-card.is-in:hover { transform: scale(1.02); }

@media (prefers-reduced-motion: reduce) {
  html.apps-js .app-card { opacity: 1; transform: none; }
  .app-icon, .app-card, .chip { transition: none; }
}

/* ---------- Closing band ---------- */

.apps-cta {
  margin-bottom: clamp(4rem, 10vh, 7rem);
  padding: clamp(1.75rem, 4vw, 3.25rem);
  border-radius: var(--r-mega);
  background: var(--dark-2);
  color: var(--on-dark);
  display: grid;
  gap: 1.75rem;
}
.apps-cta h2 {
  font-size: clamp(1.75rem, 4vw, 3rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: var(--track-5);
  max-width: 20ch;
}
.apps-cta p { max-width: 52ch; color: var(--blue-light); line-height: 1.55; }
.apps-cta .pill-light { background: var(--bg); color: var(--ink); }
.apps-cta-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }
@media (min-width: 900px) {
  .apps-cta { grid-template-columns: 1.4fr 1fr; align-items: end; }
  .apps-cta-actions { justify-content: flex-end; }
}
