/* ─────────────────────────────────────────────────────────────────────
 * pwa/styles/base.css — shared design-system base layer
 * ─────────────────────────────────────────────────────────────────────
 *
 * Established 2026-05-03 to consolidate recurring shapes that had drifted
 * across 15+ per-view stylesheets:
 *
 *   - 172 `*-card` selectors duplicating border-radius / padding / border
 *   - 6 modal-scrim implementations
 *   - 6 grid-layout recipes (auto-fit minmax(320px) for cards,
 *     minmax(140px) for stats)
 *   - 24 empty-state fallbacks with identical text-align / padding / color
 *   - 11 ad-hoc display:none toggles, no central `.hidden`
 *   - 5+ section headers with identical uppercase + letter-spacing
 *
 * ── Composition contract ─────────────────────────────────────────────
 *
 * BASE CLASSES ARE ADDITIVE — they never replace per-view classes. The
 * intended pattern is multi-class composition:
 *
 *     <div class="base-card fin-rec-card">  …finance recurring card…
 *     <div class="base-card ppl-stat-card"> …person stat tile…
 *
 * Cascade order (set in pwa/index.html `<link>` tags): base.css loads
 * FIRST, per-view CSS loads AFTER. Both classes carry specificity (0,1,0)
 * so the LATER rule wins ties — i.e. per-view overrides win automatically
 * without per-view authors having to write `!important`.
 *
 * ── Token-only ───────────────────────────────────────────────────────
 *
 * Every value resolves to a token from pwa/styles/tokens.css. No hex,
 * no rgba literals, no opaque pixel values that don't have a semantic
 * intent. If you need a new token, add it to tokens.css FIRST and then
 * reference it here.
 *
 * ── Adding new base classes ──────────────────────────────────────────
 *
 * Bar to add: at least 3 distinct per-view files duplicate the shape.
 * Two-file overlap is not enough — extract via shared component or
 * leave per-view. Each new class needs a one-line comment explaining
 * its semantic intent + a "composes with: …" example.
 *
 * Maintained as the substrate for the spec-driven design system that
 * the per-view redesigns (chat / travel / household / people / finance /
 * utility) all consume. See `.claude/CLAUDE.md` "📐 Architectural
 * Patterns" + `pwa/components/CATALOG.md` for the consuming surfaces.
 */

/* ─── Hidden utility ─────────────────────────────────────────────────
   Centralized display:none. Use a class instead of inline
   `style="display:none"` (caught by the AC-03 lock-down tests) or
   imperative `.style.display = 'none'`. The !important keeps the rule
   from being accidentally overridden by per-view layout rules. */
.hidden {
  display: none !important;
}

/* ─── Card primitive ─────────────────────────────────────────────────
   The most-duplicated shape across the codebase (172 variants). All
   per-view `*-card` classes mirror these 4 properties; consolidating
   the shell here means per-view classes only need to express what's
   DIFFERENT (accent stripe, tone, hover state, layout-specific gap).
   Composes with: any per-view `*-card` class. */
.base-card {
  background: var(--color-surface-container);
  border: 1px solid var(--color-outline-variant);
  border-radius: 12px;
  padding: 16px;
}

/* Compact borderless variant — used for stat tiles, run rows, chart
   wrappers, and section containers that pack densely (automation
   stats grid, observability sections). Same surface tone as .base-card
   but tighter radius + padding, and no border (relies on bg-tone for
   shape). Composes with: any `*-card` / `*-tile` / `*-section` class
   that overrides margin-bottom or hover state. */
.base-card-compact {
  background: var(--color-surface-container);
  border-radius: 10px;
  padding: 12px;
}

/* ─── Modal/sheet shells ─────────────────────────────────────────────
   Bottom-sheet modal pattern (most prevalent across portal, wardrobe,
   chat reply menu, people detail, finance modals). The scrim is the
   full-viewport overlay; the card is the content surface. Override
   `max-width` per-view if a different content density is needed.
   Composes with: per-view `*-modal-overlay` + `*-modal-card` classes. */
.base-modal-scrim {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: color-mix(in srgb, var(--color-on-surface-inverse, black) 55%, transparent);
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.base-modal-scrim.hidden { display: none; }
.base-modal-card {
  width: 100%;
  max-width: 520px;
  background: var(--color-surface);
  border-radius: 20px 20px 0 0;
  padding: 22px 22px env(safe-area-inset-bottom, 22px);
  max-height: 88vh;
  overflow-y: auto;
}

/* ─── Grid layouts ───────────────────────────────────────────────────
   Two recipes that recur literally identically across people, school,
   schedule (and now wardrobe, finance for new uses):
     - .base-grid-cards: 320px-min auto-fit (3 columns at 1280px desktop,
       2 at 768px tablet, 1 at <768px mobile).
     - .base-grid-stats: 140px-min auto-fit (5-7 columns at 1280px, drops
       gracefully on smaller widths).
   Composes with: any container that wants the responsive auto-fit
   layout. Set per-view `gap` on a wrapper if you need a different rhythm. */
.base-grid-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
}
.base-grid-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
}

/* ─── Vertical stack ─────────────────────────────────────────────────
   Section/card stack used by overview-style bodies. 16px gap is the
   canonical rhythm; override on a wrapper if a tab needs tighter
   density. Composes with: any container holding multiple sections. */
.base-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* Tighter vertical-stack rhythms for sub-section grouping (kanban
   columns / day-card content / sub-task lists). Pulled in from
   per-view duplicates: .sched-stack-v-tight, .bl-flex-col-8,
   .sched-stack-v-tighter (= .base-stack-tighter). */
.base-stack-tight {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.base-stack-tighter {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ─── Horizontal row ─────────────────────────────────────────────────
   The most-duplicated horizontal layout across the codebase: header
   action rows, button clusters, badge strips, search + button pairs,
   icon + label pairs. 8px gap + center alignment is the canonical
   default; override `gap` / `flex-wrap` / `justify-content` per-view.
   Composes with: any horizontally-laid-out container. */
.base-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Justified variant: row with `space-between` for label-on-left,
   action-on-right layouts (e.g. section headers with an inline button,
   "Blocks: + Add" patterns in backlog detail, schedule card headers).
   Pulled in from per-view duplicates: .sched-card-header (drops the
   margin-bottom override into the per-view class), .bl-row-between. */
.base-row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
/* `.base-row-wrap` is the flex-wrap variant — used by filter chip rows
   that overflow the viewport on narrow screens. */
.base-row-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* ─── Section header ─────────────────────────────────────────────────
   The "ANNOUNCEMENTS" / "REPORTS" small-caps header pattern used in
   school, finance, people, automation. Uses on-surface-variant so it
   reads as a label, not a heading. Per-view authors who want a true
   <h2>-style heading should NOT use this — they should use uxSectionHeader
   or finance's `.fin-section-header`. This is for the small UI-label
   case only. */
.base-section-header {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--color-on-surface-variant);
  margin: 16px 0 8px;
}

/* ─── Empty-state fallback ───────────────────────────────────────────
   Rendered when the uxEmpty primitive isn't loaded yet (cold cache /
   first paint), or for truly trivial empty states that don't justify
   the primitive. Per-view CSS may set its own padding density via an
   override class. Composes with: nothing typically — used solo. */
.base-empty-fallback {
  text-align: center;
  padding: 40px;
  color: var(--hint, var(--color-on-surface-variant));
}

/* ─── Attribute grid (2-column) ──────────────────────────────────────
   Detail-view attribute pairs (label + value) repeated across wardrobe
   item modal, finance budget detail, people contact card. 2-col grid is
   the canonical default; override `grid-template-columns` per-view if
   the data has a different shape. Composes with: per-view `*-attr` cells. */
.base-attr-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

/* ─── Reduced-motion accessibility guard ────────────────────────────
   System-wide override: when the user has set "Reduce motion" at the OS
   level, neutralize every transition + animation across the entire PWA.
   `!important` is required because per-view rules (people.js detail
   overlay slide, status-dot pulse, card hover transforms, etc.) declare
   `transition:` and `animation:` directly without a media-query guard.
   This single rule replaces 30+ per-file @media wrappers we'd otherwise
   need.

   Caveat: a 0.01ms duration is preferable to `none` because some scripts
   listen for `transitionend` events to chain logic — instant duration
   still fires the event, `transition: none` doesn't.

   Reference: WCAG 2.3.3 (Animation from Interactions, AAA). The /review-ui
   audit on 2026-05-03 (pwa/views/people.js) flagged the absence of any
   prefers-reduced-motion handling as a vestibular-disorder accessibility
   gap. This closes it for every view simultaneously.
*/
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
