/* services-rows.css — funpay-catalog Slice 2.
 *
 * Row-based catalog primitive shared between desktop (≥720px) and mobile
 * (<720px) via grid-template-areas reflow (Decision 1). Shipped behind
 * CATALOG_V2 flag-off — only loaded by views/services-rows.ejs which is
 * only rendered when `process.env.CATALOG_V2 === "true"` per the lazy
 * gate at index.js (`/services` route handler). With the flag off, the
 * legacy views/services.ejs is rendered and this file is never linked.
 *
 * Design tokens (--foreground, --background, --muted, --border, --accent,
 * --ring, --primary, --primary-foreground, --radius, --destructive, etc.)
 * are defined globally in /css/shadcn-common.css. We do NOT redefine them
 * here.
 *
 * The `.delivery-badge-inline` BASE class is already declared in
 * /css/services.css:567-585 (kept for the legacy view's compatibility).
 * We only add the modifier classes (--auto, --manual) here. Including
 * services.css alongside this file is the safer composition vs. forking
 * the base class — keeps a single source of truth.
 */

/* -------------------------------------------------------------------------
 * Page-level chrome.
 * ------------------------------------------------------------------------- */

.catalog-container {
  max-width: 1180px;
  margin: 0 auto;
  padding: 1.5rem 1rem 4rem;
}

.catalog-page-header {
  margin-bottom: 1.5rem;
}

.catalog-page-header h1 {
  margin: 0 0 0.25rem;
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--foreground);
}

.catalog-page-subtitle {
  margin: 0;
  color: var(--muted-foreground);
  font-size: 0.9375rem;
}

/* -------------------------------------------------------------------------
 * Category chip nav.
 * ------------------------------------------------------------------------- */

.catalog-category-tabs {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.catalog-category-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: 9999px;
  background: var(--background);
  color: var(--foreground);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  user-select: none;
  text-decoration: none;
}

.catalog-category-tab:hover {
  background: var(--accent);
}

.catalog-category-tab.active {
  background: var(--primary);
  color: var(--primary-foreground);
  border-color: var(--primary);
}

.catalog-category-tab .tab-count {
  opacity: 0.7;
  font-weight: 600;
  font-size: 0.75rem;
}

/* -------------------------------------------------------------------------
 * Toolbar (search + balance only — no qty pills, no sort dropdown per
 * Slice 0 evolution).
 * ------------------------------------------------------------------------- */

.catalog-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  align-items: center;
  padding: 0.75rem;
  margin-bottom: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--background);
}

.catalog-toolbar form {
  flex: 1 1 220px;
  min-width: 180px;
  display: flex;
  gap: 0.5rem;
}

.catalog-toolbar input[type="search"] {
  flex: 1 1 auto;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) - 2px);
  font: inherit;
  background: var(--background);
  color: var(--foreground);
  min-width: 0;
}

.catalog-toolbar .balance-widget {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) - 2px);
  background: var(--muted);
  font-weight: 500;
  font-feature-settings: "tnum" 1;
}

.catalog-toolbar .balance-widget .top-up {
  color: var(--success, hsl(142 70% 40%));
  font-weight: 600;
  text-decoration: none;
}

/* -------------------------------------------------------------------------
 * Service rows — desktop layout (Decision 1, 4, 6).
 *
 * Single shared DOM for desktop + mobile; grid-template-areas reflow
 * via @media (max-width: 719px) below. Whole row is an <a> per Decision
 * 4; no nested interactive content (Decision 14, asserted by the
 * service-row-no-nested-clickables.test.js invariant test).
 * ------------------------------------------------------------------------- */

.service-rows {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.service-row {
  display: grid;
  grid-template-columns: 40px minmax(0, 2fr) minmax(180px, 1fr) 130px 110px 24px;
  grid-template-areas: "icon name seller delivery price chevron";
  align-items: center;
  gap: 0.75rem;
  min-height: 56px; /* WCAG 2.2 SC 2.5.8 — Decision 4 */
  padding: 0.625rem 1rem 0.625rem 0.875rem;
  border-bottom: 1px solid var(--border);
  border-left: 4px solid var(--service-row-tint, transparent);
  background: var(--background);
  color: var(--foreground);
  text-decoration: none;
  position: relative;
  transition: background-color 0.12s ease;
}

.service-row:first-child {
  border-top: 1px solid var(--border);
}

.service-row:hover {
  background-color: var(--accent);
}

.service-row:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: -2px;
}

.service-row::after {
  content: "\203A";
  grid-area: chevron;
  justify-self: end;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--muted-foreground);
}

/* Mini image icon — D-Slice0-1: <img> not <span>. Sized small; same
 * URL source as the main service.imageUrl on /service/:id. */
.service-row__icon {
  grid-area: icon;
  width: 40px;
  height: 40px;
  border-radius: 8px;
  object-fit: cover;
  background: var(--muted);
  display: block;
  flex-shrink: 0;
}

.service-row__name {
  grid-area: name;
  min-width: 0;
}

.service-row__title {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--foreground);
}

.service-row__blurb {
  /* No `grid-area` here — this <p> is nested inside <div.service-row__name>,
   * not a direct child of the grid container, so grid-area would be inert.
   * It stacks below the <h3.service-row__title> as a normal flow sibling
   * within the name cell on both desktop and mobile.
   *
   * Visibility: shown on both viewports (block on desktop, line-clamp box
   * on mobile via the @media override). EJS only emits the <p> when
   * row.blurb is truthy (services without a blurb render zero rows of
   * extra height). 80-char cap upstream in normalizeServiceRow. */
  margin: 0.15rem 0 0;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
}

.service-row__seller {
  grid-area: seller;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  font-size: 0.8125rem;
}

.service-row__seller-avatar {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.service-row__seller-avatar img,
.service-row__seller-avatar svg {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: block;
}

.service-row__seller-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.service-row__seller-name {
  font-weight: 500;
  color: var(--foreground);
  /* sales-count Slice 1 / Decision 8: presence dot relocated inline next
     to seller name. flex layout aligns name text + dot on one baseline
     without disturbing the existing column-stack of seller-text. */
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  /* Polish slice 2026-04-29: constrain to parent + allow shrink. With
     inline-flex the previous `text-overflow: ellipsis` rule was inert
     (CSS spec: ellipsis applies to block-level text, not to anonymous
     flex items). Overflow rules moved to .service-row__seller-name-text
     below; this outer container just owns layout for [text + dot]. */
  max-width: 100%;
  min-width: 0;
}

/* Inner text wrapper — owns overflow:ellipsis (which now actually works
   because text is inside a block-context flex item, not an anonymous
   inline run inside an inline-flex container). flex-shrink default 1 +
   min-width:0 lets the text truncate while the sibling .service-row__
   online-dot keeps its 6px size via its own flex-shrink:0 rule. */
.service-row__seller-name-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.service-row__seller-meta {
  color: var(--muted-foreground);
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.75rem;
  /* sales-count Slice 1 / D8 / A10: meta-line is OPTIONAL — rendered
     only when there's a rating OR sales-count badge to show. The EJS
     gates the entire <span> so layout collapses cleanly when neither
     applies (no `min-height` cheat needed; the spans simply don't exist
     in DOM). */
}

/* sales-count Slice 1 / Decision 2 + 3: "X sold" badge slots into the
   rating-or-empty fall-through chain at priority 2 (rating > sales >
   absent). Visual treatment matches the rating-count caption (muted
   foreground, same font-size as seller-meta). */
.service-row__sales-badge {
  color: var(--muted-foreground);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.service-row__online-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.service-row__online-dot--online {
  background: var(--success, hsl(142 70% 40%));
}

.service-row__online-dot--offline {
  background: var(--muted-foreground);
  opacity: 0.5;
}

.service-row__rating {
  color: var(--foreground);
  font-weight: 500;
  white-space: nowrap;
}

.service-row__rating-star {
  color: hsl(45 95% 50%);
}

.service-row__rating-count {
  opacity: 0.7;
}

.service-row__delivery {
  grid-area: delivery;
  min-width: 0;
}

.service-row__price {
  grid-area: price;
  text-align: right;
  font-feature-settings: "tnum" 1;
}

.service-row__price-amount {
  display: block;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--foreground);
}

.service-row__price-qty {
  display: block;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* -------------------------------------------------------------------------
 * Group header (Phase 6 forward-compat — only renders when
 * row.templateGroupCount > 1, which is false today; the conditional in
 * the EJS template keeps this dead until Phase 6 schema activates).
 * ------------------------------------------------------------------------- */

.service-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 1rem 0.5rem 0.875rem;
  border-bottom: 1px solid var(--border);
  border-left: 4px solid var(--service-row-tint, transparent);
  background: var(--muted);
  font-size: 0.8125rem;
}

.service-group-header__title {
  font-weight: 600;
  color: var(--foreground);
}

.service-group-header__meta {
  color: var(--muted-foreground);
  flex: 1;
}

/* -------------------------------------------------------------------------
 * Delivery badge — base + modifiers (D-Slice0-2).
 *
 * Base rules MIGRATED FROM public/css/services.css:567-585 on 2026-04-28
 * (follow-up polish slice) so that home page Section #4 renders the badge
 * with proper pill shape. Both /services and home consumers load this
 * file; /services additionally loads services.css (which no longer carries
 * the duplicate). Modifiers (--auto / --manual) sit below.
 * ------------------------------------------------------------------------- */

.delivery-badge-inline {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: 9999px;
  background-color: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.7rem;
  font-weight: 500;
  border: 1px solid var(--border);
  margin-bottom: 0.75rem;
  white-space: nowrap;
}

.delivery-badge-inline i {
  font-size: 0.6rem;
  color: hsl(142, 60%, 45%);
}

.delivery-badge-inline--auto {
  color: var(--foreground);
}

.delivery-badge-inline--auto .delivery-badge-inline__icon {
  color: var(--success, hsl(142 70% 40%));
}

.delivery-badge-inline--manual {
  color: var(--muted-foreground);
}

.delivery-badge-inline__icon {
  font-size: 0.7rem;
  line-height: 1;
  flex-shrink: 0;
}

/* -------------------------------------------------------------------------
 * Empty state.
 * ------------------------------------------------------------------------- */

.catalog-empty-state {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--muted-foreground);
}

.catalog-empty-state h3 {
  margin: 0 0 0.5rem;
  font-size: 1.125rem;
  color: var(--foreground);
}

.catalog-empty-state .catalog-empty-cta {
  display: inline-block;
  margin-top: 1rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--foreground);
  background: var(--background);
}

.catalog-empty-state .catalog-empty-cta:hover {
  background: var(--accent);
}

/* -------------------------------------------------------------------------
 * Load more.
 * ------------------------------------------------------------------------- */

.catalog-load-more {
  margin: 1.5rem auto 0;
  display: block;
  text-align: center;
  padding: 0.625rem 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--background);
  color: var(--foreground);
  text-decoration: none;
  font-weight: 500;
  width: fit-content;
}

.catalog-load-more:hover {
  background: var(--accent);
}

/* -------------------------------------------------------------------------
 * Mobile (<720px) — Funpay-style flat row list (UX decision 2026-04-29,
 * grid rectified 2026-04-28: prior 3-row template had `icon` in row 1 col 1
 * AND row 3 col 1 with `blurb blurb` in row 2 — non-rectangular per CSS
 * Grid spec → entire grid-template-areas declaration was invalid and
 * discarded. Browser fell back to auto-flow placement, which pushed
 * .service-row__seller into col 3 row 1 next to the title and squeezed
 * the title column down to ~40% of width, causing 3-4 line title wraps
 * on iPhone-width viewports. Fix: make icon span both rows in a valid
 * 2-row template. The standalone `blurb` grid area was also dead — the
 * <p class="service-row__blurb"> sits inside <div class="service-row__name">,
 * not as a direct grid child, so its grid-area declaration was inert.
 * Blurb stacks naturally inside the name cell as a flow sibling).
 *
 * Same DOM as desktop; this @media block reflows via grid-template-areas
 * AND prunes desktop-only chrome (border, radius, gap, "from"/"unit"
 * price scaffolding, delivery label text). Result: dense list of
 * compact rows separated by hairline border, like funpay.com mobile.
 *
 * What the user sees per row (mobile):
 *   ┌─────────────────────────────────────────────────────────┐
 *   │ [32px icon] Twitch Chat Bot for 1 Hour          $0.20  │
 *   │             Fully AI-Powered & Human-Like…              │
 *   │ [32px col]  [16px avatar] NEZHNA · ● online      ⚡     │
 *   └─────────────────────────────────────────────────────────┘
 *
 * Title is bounded to 2 lines via -webkit-line-clamp; longer names
 * truncate with ellipsis. Blurb is also clamped to 1 line. The 32px
 * icon column extends the full row height (top-aligned via
 * align-self).
 *
 * Removed vs prior card-style mobile:
 *   - 4px purple top border (.service-row tint)
 *   - 1px box border + radius
 *   - 0.625rem inter-row gap
 *   - "from" price prefix
 *   - "/ unit" price suffix
 *   - delivery-badge text label ("AI-Powered" / "Cheap")
 *
 * Single breakpoint; iPad-landscape gets desktop layout.
 * ------------------------------------------------------------------------- */

@media (max-width: 719px) {
  .catalog-container {
    padding: 1rem 0.75rem 3rem;
  }

  .catalog-toolbar {
    padding: 0.5rem;
  }

  .catalog-toolbar form {
    flex: 1 1 100%;
  }

  .catalog-toolbar .balance-widget {
    flex: 1 1 100%;
    justify-content: center;
  }

  /* Flat list — no inter-row gap, hairline divider. */
  .service-rows {
    gap: 0;
  }

  .service-row {
    /* 3-col grid: icon (full-height, spans both rows) | name+blurb stacked
       in col 2 row 1 with seller below in col 2 row 2 | price row 1 +
       delivery row 2 in col 3. `icon` forms a valid rectangle (rows 1-2
       col 1) so the entire grid-template-areas declaration is honored
       (vs the prior 3-row template where icon was in disconnected cells
       and the whole declaration was discarded by the browser). */
    grid-template-columns: 32px minmax(0, 1fr) auto;
    grid-template-areas:
      "icon name   price"
      "icon seller delivery";
    column-gap: 0.625rem;
    row-gap: 0.125rem;
    align-items: start;
    padding: 0.625rem 0.75rem;
    /* Funpay-style: hairline separator only. No card border, no top tint
       bar, no border-radius. */
    border: 0;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    border-left: 0;
  }

  .service-row:first-child {
    /* Symmetric hairline above first row so the list reads as a
       bordered group rather than detached rows. */
    border-top: 1px solid var(--border);
  }

  .service-row::after {
    display: none;
  }

  .service-row__icon {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    align-self: start;
    margin-top: 0.125rem;
  }

  .service-row__title {
    /* 2-line clamp: bounds title height for very long names (e.g.
       "Twitch Live Viewers for 4 Hours"). White-space normal allows
       wrap; -webkit-line-clamp truncates beyond 2 lines with ellipsis.
       The :first-line CSS pseudo would not work here because line-clamp
       requires display:-webkit-box. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
    word-break: break-word;
    font-size: 0.9375rem;
    line-height: 1.25;
  }

  .service-row__blurb {
    /* Switch from desktop's display:block + nowrap+ellipsis to
       line-clamp box on mobile. Same visual effect (1-line truncation)
       but uses -webkit-box so it could be bumped to 2-line clamp later
       if needed. Note: this <p> is a flow sibling of
       <h3.service-row__title> inside <div.service-row__name>, NOT a
       direct grid child — its former `grid-area: blurb` declaration
       was dead (grid-area only applies to direct children of the grid
       container). It stacks below the title naturally on both
       viewports. */
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
    margin-top: 0;
    font-size: 0.8125rem;
    line-height: 1.3;
  }

  /* Seller cell sits inline (avatar + name + dot) under the name —
     not the desktop's stacked column layout. */
  .service-row__seller {
    font-size: 0.75rem;
    align-items: center;
    gap: 0.4rem;
  }

  .service-row__seller-avatar,
  .service-row__seller-avatar img,
  .service-row__seller-avatar svg {
    width: 18px;
    height: 18px;
  }

  .service-row__seller-text {
    /* Mobile: collapse the desktop's column stack to a single inline
       row so name + status sit on one baseline. */
    flex-direction: row;
    align-items: center;
    gap: 0.35rem;
  }

  .service-row__seller-name {
    font-weight: 500;
    font-size: 0.75rem;
  }

  .service-row__seller-meta {
    font-size: 0.6875rem;
    gap: 0.25rem;
  }

  /* Delivery: icon-only on mobile (label text in title attr per long-
     press accessibility convention). */
  .service-row__delivery {
    align-self: start;
    padding-top: 0.25rem;
    text-align: right;
  }

  .delivery-badge-inline {
    /* Strip background pill / padding on mobile — just the icon. */
    background: transparent;
    border: 0;
    padding: 0;
    gap: 0;
  }

  .delivery-badge-inline__icon {
    font-size: 0.875rem;
  }

  .delivery-badge-inline__label {
    /* Hidden on mobile per Funpay-style icon-only delivery indicator.
       Desktop reveals via default display. Title attr on the parent
       still surfaces the text on long-press. */
    display: none;
  }

  /* Price: bare amount on mobile, no "from" prefix, no "/ unit" suffix. */
  .service-row__price {
    align-self: start;
    padding-top: 0.125rem;
  }

  .service-row__price-amount {
    font-size: 1rem;
  }

  .service-row__price-prefix,
  .service-row__price-qty {
    display: none;
  }

  .service-group-header {
    border-radius: 0;
    border-left: 0;
    margin-top: 0;
  }
}
