/*
 * Canvastia design system — the one place the product's look is defined.
 *
 * Every web surface (landing, studio, admin) is built on these tokens and
 * primitives rather than on colours and paddings written at the point of use.
 * The mobile app carries the same decisions in `mobile/src/theme/index.ts`; the
 * two files are deliberately kept in step, because the app and the site are one
 * product and a member moves between them.
 *
 * The look is dark-first, taken from the Canvastia mobile app kit: a near-black
 * ground, rounded cards that lift off it, and a single warm gold-amber accent
 * that carries every action. The pet artwork is the other colour on the page.
 * The mobile app carries the same tokens in `mobile/src/theme/index.ts`.
 *
 * One accent, one meaning: --ca-accent (gold-amber) is *the* action — generate,
 * continue, save, buy, the active tab, the FAB. It is also what money reads in
 * (prices, credits), because in this kit the two are the same warm colour; the
 * `--ca-gold*` tokens are kept as aliases so older component rules still work.
 * Positive change is green (--ca-success); problems are red (--ca-danger);
 * secondary/route information is blue (--ca-info).
 */

:root,
[data-ca-theme='dark'] {
  /* ---------------------------------------------------------------- colour */
  /* The ground, and the surfaces that lift off it. Near-black, faintly warm,
     like the app kit — the card edges and the amber do the separating. */
  --ca-bg: #131315;
  --ca-bg-deep: #0e0e10;
  --ca-surface: #1d1d1f;
  --ca-surface-2: #252527;
  --ca-surface-3: #2d2d30;

  /* A tinted field/hover pair, for inputs and row hover. */
  --ca-field: #29292c;
  --ca-hover: #323235;

  /* Borders are the quiet structure: hairlines separate, strong outlines mean
     "you may type here" or "this is selected". */
  --ca-border: #333336;
  --ca-border-strong: #47474d;

  --ca-ink: #f4f4f6;
  --ca-ink-muted: #a8a8ad;
  --ca-ink-faint: #7c7c82;

  /* The one accent. Dark text sits on it. */
  --ca-accent: #f5b52e;
  --ca-accent-strong: #e59a15;
  --ca-accent-ink: #1c1400;
  --ca-accent-soft: #33280f;

  /* Money uses the same warm accent in this kit. Aliases, not a second hue. */
  --ca-gold: var(--ca-accent);
  --ca-gold-strong: var(--ca-accent-strong);
  --ca-gold-ink: var(--ca-accent-ink);
  --ca-gold-soft: var(--ca-accent-soft);

  --ca-success: #34d399;
  --ca-success-soft: rgba(52, 211, 153, 0.15);
  --ca-warning: #f5924a;
  --ca-warning-soft: rgba(245, 146, 74, 0.15);
  --ca-danger: #f5564a;
  --ca-danger-soft: rgba(245, 86, 74, 0.15);
  --ca-info: #3b9eff;
  --ca-info-soft: rgba(59, 158, 255, 0.15);

  /* ------------------------------------------------------------- gradients */
  /* One light source, used sparingly: behind the hero, and on the primary
     button. A gradient on every surface is how a page stops having a focus. */
  --ca-grad-accent: linear-gradient(135deg, #f7c94a, #e59a15);
  --ca-grad-gold: var(--ca-grad-accent);
  --ca-glow: radial-gradient(60% 70% at 50% 0%, rgba(245, 181, 46, 0.18), transparent 70%);

  /* --------------------------------------------------------------- shadows */
  --ca-shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.34);
  --ca-shadow: 0 12px 36px rgba(0, 0, 0, 0.42);
  --ca-shadow-float: 0 6px 22px rgba(0, 0, 0, 0.32);
  --ca-shadow-modal: 0 25px 100px rgba(0, 0, 0, 0.5);
  --ca-shadow-accent: 0 10px 30px rgba(229, 154, 21, 0.32);
  --ca-shadow-gold: var(--ca-shadow-accent);

  color-scheme: dark;
}

:root {
  /* ------------------------------------------------------------ typography */
  /*
   * One face, like Vellum: Inter everywhere. Headings are the same family a
   * step or two heavier with tight tracking — that is what makes them read as
   * deliberate rather than merely large, without a second webfont to wait for.
   * `--ca-font-display` is kept as a separate token so existing rules keep
   * working; it just points at the same stack now.
   */
  --ca-font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --ca-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  /* The sketches write their warm asides in a hand — Caveat is the closest
     face to that lettering and is loaded with the other brand fonts. */
  --ca-font-hand: 'Caveat', 'Segoe Script', 'Bradley Hand', cursive;

  /* A scale, not a list of sizes: each step is a deliberate jump, and a heading
     that needs a size between two of them is a heading in the wrong place. */
  --ca-text-display: clamp(2.4rem, 5.4vw, 4.25rem);
  --ca-text-h1: clamp(2rem, 4vw, 3rem);
  --ca-text-h2: clamp(1.55rem, 2.8vw, 2.25rem);
  --ca-text-h3: 1.2rem;
  --ca-text-body: 1rem;
  --ca-text-small: 0.875rem;
  --ca-text-caption: 0.75rem;

  --ca-weight-display: 800;
  --ca-weight-heading: 700;
  --ca-weight-strong: 600;
  --ca-weight-body: 400;

  --ca-leading-tight: 1.06;
  --ca-leading-heading: 1.2;
  --ca-leading-body: 1.65;
  --ca-tracking-display: -0.02em;
  --ca-tracking-eyebrow: 0.14em;

  /* --------------------------------------------------------------- spacing */
  /* A four-based scale. Section rhythm is deliberately large: the reference's
     premium feel is mostly empty space, and it is the first thing lost when
     sections are packed. */
  --ca-space-1: 4px;
  --ca-space-2: 8px;
  --ca-space-3: 12px;
  --ca-space-4: 16px;
  --ca-space-5: 24px;
  --ca-space-6: 32px;
  --ca-space-7: 48px;
  --ca-space-8: 64px;
  --ca-space-9: 96px;
  --ca-section: clamp(56px, 9vw, 120px);
  --ca-gutter: clamp(16px, 4vw, 32px);
  --ca-measure: 1200px;

  /* ---------------------------------------------------------------- shapes */
  /* Vellum's small, consistent radii: controls and buttons at 6, cards and
     menus at 9-12, modals at 15. Pills are reserved for genuine pills
     (badges, avatars, toggles), not for buttons. */
  --ca-radius-sm: 6px;
  --ca-radius: 9px;
  --ca-radius-lg: 12px;
  --ca-radius-xl: 15px;
  --ca-radius-pill: 999px;

  /* ---------------------------------------------------------------- motion */
  /* Vellum: fast, small, ease-out — opacity plus a few pixels, never more. */
  --ca-ease: cubic-bezier(0.2, 0.7, 0.3, 1);
  --ca-fast: 0.15s;
  --ca-slow: 0.28s;

  --ca-z-sticky: 60;
  --ca-z-modal: 120;
}

/* Everything that moves, stops moving when the reader asked for that. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --ca-fast: 0.01ms;
    --ca-slow: 0.01ms;
  }
}

/* ========================================================================
   Primitives
   ======================================================================== */

.pm {
  background: var(--ca-bg);
  color: var(--ca-ink);
  font-family: var(--ca-font-body);
  font-size: var(--ca-text-body);
  line-height: var(--ca-leading-body);
}

.pm *,
.pm *::before,
.pm *::after {
  box-sizing: border-box;
}

/* One focus treatment everywhere, and it is never removed. A keyboard user who
   cannot see where they are is locked out of the page. */
.pm :focus-visible {
  outline: 2px solid var(--ca-accent);
  outline-offset: 2px;
  border-radius: var(--ca-radius-sm);
}

/* ---------------------------------------------------------------- headings */

.ca-display,
.ca-h1,
.ca-h2,
.ca-h3 {
  font-family: var(--ca-font-display);
  color: var(--ca-ink);
  margin: 0;
  text-wrap: balance;
}

.ca-display {
  font-size: var(--ca-text-display);
  font-weight: var(--ca-weight-display);
  line-height: var(--ca-leading-tight);
  letter-spacing: var(--ca-tracking-display);
}

.ca-h1 {
  font-size: var(--ca-text-h1);
  font-weight: var(--ca-weight-display);
  line-height: var(--ca-leading-heading);
  letter-spacing: var(--ca-tracking-display);
}

.ca-h2 {
  font-size: var(--ca-text-h2);
  font-weight: var(--ca-weight-heading);
  line-height: var(--ca-leading-heading);
  letter-spacing: -0.015em;
}

.ca-h3 {
  font-size: var(--ca-text-h3);
  font-weight: var(--ca-weight-heading);
  line-height: 1.35;
}

.ca-lede {
  margin: 0;
  color: var(--ca-ink-muted);
  font-size: clamp(1rem, 1.6vw, 1.15rem);
  line-height: 1.6;
  max-width: 60ch;
  text-wrap: pretty;
}

.ca-muted {
  color: var(--ca-ink-muted);
}

.ca-caption {
  color: var(--ca-ink-faint);
  font-size: var(--ca-text-caption);
  line-height: 1.5;
}

/*
 * The section label above a heading.
 *
 * Small, spaced, and in the accent — it is what tells the reader which part of
 * the page they have scrolled into without another heading competing with the
 * one below it.
 */
.ca-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--ca-space-2);
  font-family: var(--ca-font-display);
  font-size: var(--ca-text-caption);
  font-weight: 800;
  letter-spacing: var(--ca-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--ca-accent);
}

.ca-eyebrow--gold {
  color: var(--ca-gold);
}

/* ----------------------------------------------------------------- buttons */

/*
 * One button, four intents.
 *
 * `primary` acts, `gold` spends, `soft` is the secondary action beside them and
 * `ghost` is a link that happens to be button-shaped. The minimum height is 48
 * so every one of them is a real target on a phone.
 */
.ca-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ca-space-2);
  min-height: 48px;
  padding: 0 var(--ca-space-5);
  border: 1px solid transparent;
  border-radius: var(--ca-radius-sm);
  font-family: var(--ca-font-display);
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--ca-fast) var(--ca-ease), box-shadow var(--ca-fast) var(--ca-ease),
    background-color var(--ca-fast) var(--ca-ease), border-color var(--ca-fast) var(--ca-ease);
}

/* Vellum's filled-button hover is a brightness lift, not a move; the quieter
   variants get a background instead. Nothing jumps. */
.ca-btn--primary:hover:not(:disabled),
.ca-btn--gold:hover:not(:disabled) {
  filter: brightness(1.12);
}

.ca-btn:active:not(:disabled) {
  filter: brightness(0.96);
}

.ca-btn:disabled,
.ca-btn[aria-disabled='true'] {
  opacity: 0.35;
  cursor: not-allowed;
}

.ca-btn--primary {
  background: var(--ca-grad-accent);
  color: var(--ca-accent-ink);
  box-shadow: var(--ca-shadow-accent);
}

/* Gold says "this costs something", so a price belongs on it. */
.ca-btn--gold {
  background: var(--ca-grad-gold);
  color: var(--ca-gold-ink);
  box-shadow: var(--ca-shadow-gold);
}

.ca-btn--soft {
  background: var(--ca-surface-2);
  color: var(--ca-ink);
  border-color: var(--ca-border);
}

.ca-btn--soft:hover:not(:disabled) {
  background: var(--ca-hover);
  border-color: var(--ca-border-strong);
}

.ca-btn--ghost {
  background: transparent;
  color: var(--ca-ink);
  border-color: var(--ca-border-strong);
}

.ca-btn--ghost:hover:not(:disabled) {
  background: var(--ca-hover);
}

.ca-btn--sm {
  min-height: 40px;
  padding: 0 var(--ca-space-4);
  font-size: 0.85rem;
}

.ca-btn--lg {
  min-height: 56px;
  padding: 0 var(--ca-space-6);
  font-size: 1.05rem;
}

.ca-btn--block {
  width: 100%;
}

/* The price carried inside a button, so the cost is never a surprise on the
   screen after the press. */
.ca-btn__cost {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--ca-radius-sm);
  background: rgba(0, 0, 0, 0.18);
  font-size: 0.8rem;
  font-weight: 800;
}

/* ------------------------------------------------------------------- cards */

.ca-card {
  background: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-lg);
  padding: var(--ca-space-5);
  box-shadow: var(--ca-shadow-sm);
}

.ca-card--flush {
  padding: 0;
  overflow: hidden;
}

.ca-card--raised {
  box-shadow: var(--ca-shadow);
}

.ca-card--accent {
  border-color: color-mix(in srgb, var(--ca-accent) 45%, transparent);
  background: linear-gradient(180deg, var(--ca-accent-soft), transparent 60%), var(--ca-surface);
}

/*
 * The framed card: a labelled outer shell holding a darker inner panel.
 *
 * It is the reference's most useful idea and it earns its place — the label
 * names the thing ("Digital HD", "Poster"), and the panel inside holds the
 * claim and its action. One card can then carry two levels of information
 * without a heading fighting a subheading.
 */
.ca-card--framed {
  padding: var(--ca-space-3);
  background: var(--ca-surface-2);
}

.ca-card__label {
  display: block;
  padding: var(--ca-space-2) var(--ca-space-3) var(--ca-space-3);
  font-family: var(--ca-font-display);
  font-size: var(--ca-text-caption);
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ca-gold);
  text-align: center;
}

.ca-card__panel {
  background: var(--ca-bg-deep);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  padding: var(--ca-space-5);
}

/* A whole card that is a link: the hover belongs to the card, not to the words
   inside it, because the whole thing is the target. */
.ca-card--link {
  display: block;
  text-decoration: none;
  color: inherit;
  transition: transform var(--ca-fast) var(--ca-ease), border-color var(--ca-fast) var(--ca-ease);
}

.ca-card--link:hover {
  border-color: var(--ca-accent);
}

/* ------------------------------------------------------------------ inputs */

/*
 * Fields say what they want inside the box.
 *
 * The heading-above-the-box pattern was removed from the app for the same
 * reason it is absent here: it doubles the height of every form and the words
 * are more useful where the member is already looking. `.ca-field__label` is
 * kept for the cases that genuinely need a visible name, and is a real label
 * element either way so the control is always named.
 */
.ca-field {
  display: grid;
  gap: 6px;
}

.ca-field__label {
  font-size: var(--ca-text-caption);
  font-weight: 700;
  color: var(--ca-ink-muted);
}

.ca-input,
.ca-select,
.ca-textarea {
  width: 100%;
  min-height: 46px;
  padding: 0 var(--ca-space-4);
  border: 1px solid transparent;
  border-radius: var(--ca-radius-sm);
  background: var(--ca-field);
  color: var(--ca-ink);
  font-family: inherit;
  font-size: 0.95rem;
  transition: border-color var(--ca-fast) var(--ca-ease);
}

.ca-textarea {
  min-height: 108px;
  padding: var(--ca-space-3) var(--ca-space-4);
  line-height: 1.55;
  resize: vertical;
}

.ca-input:hover,
.ca-select:hover,
.ca-textarea:hover {
  border-color: var(--ca-border);
}

.ca-input::placeholder,
.ca-textarea::placeholder {
  color: var(--ca-ink-faint);
}

/* Vellum: focus is the accent border alone, no glow ring. */
.ca-input:focus,
.ca-select:focus,
.ca-textarea:focus {
  outline: none;
  border-color: var(--ca-accent);
}

.ca-input[aria-invalid='true'],
.ca-textarea[aria-invalid='true'] {
  border-color: var(--ca-danger);
}

/* The native control keeps its own menu — a custom one that cannot be operated
   by keyboard is worse than the platform's. Only the chrome is ours. */
.ca-select {
  appearance: none;
  padding-right: var(--ca-space-7);
  background-image: linear-gradient(45deg, transparent 50%, var(--ca-ink-muted) 50%),
    linear-gradient(135deg, var(--ca-ink-muted) 50%, transparent 50%);
  background-position: calc(100% - 20px) 21px, calc(100% - 14px) 21px;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

.ca-field__hint {
  font-size: var(--ca-text-caption);
  color: var(--ca-ink-faint);
}

.ca-field__error {
  font-size: var(--ca-text-caption);
  color: var(--ca-danger);
}

/* ------------------------------------------------------- chips, badges, tabs */

/* The filter row above a grid: one line, scrollable sideways rather than
   wrapping into a wall of options. */
.ca-chips {
  display: flex;
  gap: var(--ca-space-2);
  overflow-x: auto;
  padding-bottom: var(--ca-space-2);
  scrollbar-width: none;
}

.ca-chips::-webkit-scrollbar {
  display: none;
}

.ca-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 38px;
  padding: 0 var(--ca-space-4);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
  background: var(--ca-surface-2);
  color: var(--ca-ink-muted);
  font-size: var(--ca-text-small);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
}

.ca-chip[aria-selected='true'],
.ca-chip.is-active {
  background: var(--ca-accent-soft);
  border-color: var(--ca-accent);
  color: var(--ca-ink);
}

.ca-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: var(--ca-radius-pill);
  font-size: var(--ca-text-caption);
  font-weight: 800;
  letter-spacing: 0.02em;
  background: var(--ca-surface-3);
  color: var(--ca-ink-muted);
}

.ca-badge--gold {
  background: var(--ca-gold-soft);
  color: var(--ca-gold);
}
.ca-badge--success {
  background: var(--ca-success-soft);
  color: var(--ca-success);
}
.ca-badge--warning {
  background: var(--ca-warning-soft);
  color: var(--ca-warning);
}
.ca-badge--danger {
  background: var(--ca-danger-soft);
  color: var(--ca-danger);
}

.ca-tabs {
  display: flex;
  gap: var(--ca-space-1);
  padding: 4px;
  border-radius: var(--ca-radius-sm);
  background: var(--ca-surface-2);
  border: 1px solid var(--ca-border);
  overflow-x: auto;
  scrollbar-width: none;
}

.ca-tabs::-webkit-scrollbar {
  display: none;
}

.ca-tab {
  flex: 1 0 auto;
  min-height: 40px;
  padding: 0 var(--ca-space-4);
  border: 0;
  border-radius: var(--ca-radius-sm);
  background: transparent;
  color: var(--ca-ink-muted);
  font-family: var(--ca-font-display);
  font-size: var(--ca-text-small);
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}

.ca-tab[aria-selected='true'],
.ca-tab.is-active {
  background: var(--ca-surface-3);
  color: var(--ca-ink);
  box-shadow: var(--ca-shadow-sm);
}

/* ---------------------------------------------------------------- avatars */

.ca-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--ca-radius-pill);
  background: var(--ca-grad-accent);
  color: var(--ca-accent-ink);
  font-family: var(--ca-font-display);
  font-weight: 800;
  font-size: 0.9rem;
  overflow: hidden;
  flex: none;
}

.ca-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ca-avatar--lg {
  width: 56px;
  height: 56px;
  font-size: 1.3rem;
}

/* ------------------------------------------------------------------ tables */

/*
 * A table that survives a phone.
 *
 * The wrapper scrolls sideways rather than the page: a wide table that pushes
 * the whole document sideways breaks every other column on the screen.
 */
.ca-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  background: var(--ca-surface);
}

.ca-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--ca-text-small);
}

.ca-table th {
  position: sticky;
  top: 0;
  padding: var(--ca-space-3) var(--ca-space-4);
  background: var(--ca-surface-2);
  color: var(--ca-ink-muted);
  font-size: var(--ca-text-caption);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: start;
  white-space: nowrap;
}

.ca-table td {
  padding: var(--ca-space-3) var(--ca-space-4);
  border-top: 1px solid var(--ca-border);
  color: var(--ca-ink);
  vertical-align: middle;
}

.ca-table tbody tr:hover td {
  background: var(--ca-surface-2);
}

/* Figures line up when they are compared, which is the only reason to put them
   in a table at all. */
.ca-table__num {
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.ca-table__empty {
  padding: var(--ca-space-7);
  text-align: center;
  color: var(--ca-ink-faint);
}

/* -------------------------------------------------------------- pagination */

.ca-pagination {
  display: flex;
  align-items: center;
  gap: var(--ca-space-2);
  flex-wrap: wrap;
}

.ca-page {
  min-width: 40px;
  min-height: 40px;
  padding: 0 var(--ca-space-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
  background: var(--ca-surface-2);
  color: var(--ca-ink-muted);
  font-size: var(--ca-text-small);
  font-weight: 700;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.ca-page[aria-current='page'] {
  background: var(--ca-accent-soft);
  border-color: var(--ca-accent);
  color: var(--ca-ink);
}

/* ------------------------------------------------------------------ modals */

.ca-modal {
  position: fixed;
  inset: 0;
  z-index: var(--ca-z-modal);
  display: grid;
  place-items: center;
  padding: var(--ca-gutter);
  background: rgba(0, 0, 0, 0.44);
  backdrop-filter: blur(6px);
}

.ca-modal[hidden] {
  display: none;
}

.ca-modal__dialog {
  width: min(560px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  background: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-xl);
  box-shadow: var(--ca-shadow-modal, var(--ca-shadow));
  padding: var(--ca-space-6);
  display: grid;
  gap: var(--ca-space-4);
}

.ca-modal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ca-space-4);
}

.ca-modal__close {
  border: 1px solid var(--ca-border);
  background: var(--ca-surface-2);
  color: var(--ca-ink-muted);
  width: 36px;
  height: 36px;
  border-radius: var(--ca-radius-sm);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
}

/* On a phone a centred dialog with a keyboard open is unusable; it becomes a
   sheet attached to the bottom edge instead. */
@media (max-width: 640px) {
  .ca-modal {
    place-items: end center;
    padding: 0;
  }

  .ca-modal__dialog {
    width: 100%;
    max-height: 92vh;
    border-radius: var(--ca-radius-lg) var(--ca-radius-lg) 0 0;
  }
}

/* ------------------------------------------------------------------ layout */

.ca-container {
  width: 100%;
  max-width: var(--ca-measure);
  margin-inline: auto;
  padding-inline: var(--ca-gutter);
}

.ca-section {
  padding-block: var(--ca-section);
}

.ca-section--tint {
  background: var(--ca-bg-deep);
}

.ca-stack {
  display: grid;
  gap: var(--ca-space-4);
}

.ca-stack--lg {
  gap: var(--ca-space-6);
}

.ca-row {
  display: flex;
  align-items: center;
  gap: var(--ca-space-3);
  flex-wrap: wrap;
}

/*
 * The one grid every collection uses.
 *
 * `auto-fit` with a minimum means the same markup is one column on a phone and
 * four on a desktop without a media query per collection — and nothing ever
 * gets narrower than a card can survive.
 */
.ca-grid {
  display: grid;
  gap: var(--ca-space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}

.ca-grid--tight {
  grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
}

.ca-grid--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
}

/* A square picture tile: the shape the whole product is built out of. */
.ca-tile {
  aspect-ratio: 1;
  border-radius: var(--ca-radius);
  background: var(--ca-surface-2);
  overflow: hidden;
  display: grid;
  place-items: center;
}

.ca-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Available to a screen reader, invisible to everyone else. */
.ca-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
