/* TRA Frontend (public site) — component-atom library (S25, DA25.2).
 * Growing companion to tra.css: Tier 2 of ARCHITECTURE.md Pattern 13's
 * three-tier design token system (Tier 0 raw values -> Tier 1 semantic
 * tokens, both in tra.css's own :root -- unlike ops, Frontend has no
 * separate tokens.css file -> Tier 2 here, named reusable component
 * classes built from Tier 1). (The prior requirement that every visual
 * pattern be named/rendered in design-system/ui-preview.html before use
 * is retired, S196 — that file is deleted, no replacement documented yet.)
 * No existing tra.css content moved here — atoms already shipped in
 * tra.css before this file existed (.card, .chip, .btn, .accordion, etc.)
 * stay exactly where they are, migrating them is a future, separately-
 * authorized prompt. Linked from templates/public/base.html.
 *
 * S25 interaction-states audit (buttons/forms) — this file's first real
 * atoms. Everything below is ADDITIVE: nothing in tra.css's existing
 * .btn/.field rules was touched; new selectors layer on top via the
 * normal cascade (components.css loads after tra.css).
 */

/* ---- Focus-visible ring — AUDIT: unlike Ops, this surface already HAS a
   real one, tra.css:270 (`:focus-visible { outline: 3px solid
   var(--navy-700); outline-offset: 2px; border-radius: 2px; }`), applying
   site-wide to every focusable element including all .btn variants — no
   gap here, no new rule added. Noted for the record, not duplicated. */

/* ---- Button active/disabled — real gap: unlike Ops, this file has
   NO :active or :disabled rule anywhere for .btn (confirmed by grep —
   .btn only has a base state + per-variant :hover). Matches Ops's
   .btn:active/.btn:disabled pattern by value. */
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* ---- Disabled form fields — real gap: .field input/.field select had no
   :disabled rule anywhere in tra.css (confirmed by grep). */
.field input:disabled, .field select:disabled {
  opacity: .5;
  cursor: not-allowed;
  background: var(--sand-50);
}

/* ---- Loading / pending button — no booking/submit flow with a
   dedicated "submitting" state exists on the public site today (that
   pattern lives in apps/ops's booking.js/Alpine forms) — this is a
   forward-looking atom for a future contact/booking form, not a retrofit.
   Same convention as ops/components.css: pair with :disabled + a text
   swap; .btn-spinner is the optional visual addition:
     <button class="btn btn--primary" :disabled="submitting">
       <span x-show="submitting" class="btn-spinner" aria-hidden="true"></span>
       <span x-show="!submitting">Send enquiry</span>
       <span x-show="submitting">Sending…</span>
     </button> */
.btn-spinner {
  display: inline-block; width: 14px; height: 14px; flex: none;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spin .8s linear infinite;
  opacity: .8;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .btn-spinner { animation: none; border-style: dotted; } }

/* ---- Icon-only button — genuinely absent as a shared atom: .nav-burger
   and .carousel__btn are two independent, hand-rolled implementations of
   the same square-icon-button concept (both happen to land on 2.75rem,
   confirmed by grep — duplicated, not shared). This atom consolidates
   the pattern for future use; .nav-burger/.carousel__btn themselves are
   NOT retrofitted onto it (no-refactor constraint). Real markup pattern
   (icon-only — the visible label is for assistive tech only):
     <button class="icon-btn" aria-label="Close">…</button> */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; padding: 0; flex: none;
  border-radius: 50%;
  border: 1px solid var(--line); background: var(--surface); color: var(--navy-900);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard);
}
.icon-btn:hover { background: var(--navy-50); }
.icon-btn:active { transform: translateY(1px); }
.icon-btn:disabled { opacity: .5; cursor: not-allowed; }
.icon-btn-ghost { border-color: transparent; background: transparent; }
.icon-btn-ghost:hover { background: var(--navy-50); }

/* ---- Button group / segmented control — genuinely absent anywhere on
   this surface (confirmed by grep). */
.btn-group { display: inline-flex; border: 1px solid var(--line); border-radius: var(--r-pill); overflow: hidden; }
.btn-group button {
  border: none; border-right: 1px solid var(--line);
  background: var(--surface); color: var(--navy-900);
  height: 2.5rem; padding: 0 var(--s-4);
  font: 600 var(--fs-sm)/1.2 var(--font-text);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard);
}
.btn-group button:last-child { border-right: none; }
.btn-group button:hover { background: var(--navy-50); }
.btn-group button.active,
.btn-group button[aria-pressed="true"] { background: var(--navy-800); color: var(--ink-inverse); }
.btn-group button:disabled { opacity: .5; cursor: not-allowed; }

/* ============================================================
   S25 feedback & overlay audit — same pass as static/ops/components.css,
   findings for the record (see that file for the full modal write-up,
   which applies here too — Frontend has NO modal/dialog pattern at all,
   confirmed by grep, zero .modal-like class or JS anywhere. A focus-
   trapped modal atom needs real JS this task's scope lock doesn't cover
   (components.css + ui-preview.html, the latter since retired S196) —
   not added here; flagged as a
   candidate for its own scoped follow-up rather than shipping a modal
   shell with no accessible focus handling behind it. */

/* Alerts/toasts — AUDIT: no alert/toast pattern of any kind exists on
   this surface (grepped tra.css — zero hits for "toast"/"alert"). Ops's
   .tc-toast doesn't apply here (tapechart.css isn't linked from
   templates/public). Genuinely missing — added below, same shape as
   Ops's new .alert atom, this surface's own tokens/naming convention. */
.alert {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-3) var(--s-4); border-radius: var(--r-md);
  border-left: 3px solid transparent; font-size: var(--fs-sm); line-height: 1.4;
  color: var(--ink);
}
.alert--ok   { background: var(--ok-soft);   border-left-color: var(--ok); }
.alert--warn { background: var(--warn-soft); border-left-color: var(--warn); }
.alert--err  { background: var(--err-soft);  border-left-color: var(--err); }
.alert__close {
  flex: none; margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; padding: 0; border: none; border-radius: var(--r-sm);
  background: none; color: inherit; opacity: .65; cursor: pointer; font-size: var(--fs-sm); line-height: 1;
}
.alert__close:hover { opacity: 1; background: rgba(0, 0, 0, .06); }
.alert--toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
  z-index: 90; box-shadow: var(--shadow-3); max-width: 90vw;
}

/* Badges/chips — AUDIT: .chip/.chip--* (tra.css) already exist as a
   generic display chip, but none of them has a dismiss/remove action
   (confirmed by grep). .chip__remove is additive — composes onto the
   EXISTING .chip/.chip--* rules via the cascade, nothing in tra.css
   touched; drops into .chip's own inline-flex + gap layout as a child. */
.chip__remove {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin: 0 -0.25rem 0 0; padding: 0;
  border: none; border-radius: 50%; background: none; color: inherit;
  opacity: .65; cursor: pointer; font-size: var(--fs-xs); line-height: 1;
}
.chip__remove:hover { opacity: 1; background: rgba(0, 0, 0, .08); }

/* Tooltips — AUDIT: no generic tooltip pattern exists (grepped tra.css —
   zero hits for "tooltip"). Ops's .tc-hovercard/.tc-pop don't apply here
   either (calendar-only, tapechart.css isn't linked). Same lightweight,
   CSS-only, single-line pattern as Ops, this surface's dark-chip color
   pairing (reused from the site-header eyebrow bar, tra.css). */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute; left: 50%; bottom: calc(100% + 6px);
  transform: translateX(-50%) translateY(4px);
  background: var(--navy-950); color: var(--navy-200);
  font-size: var(--fs-xs); font-weight: 600;
  padding: var(--s-1) var(--s-2); border-radius: var(--r-sm); white-space: nowrap;
  opacity: 0; pointer-events: none; z-index: 85;
  transition: opacity var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard);
}
[data-tooltip]:hover::after, [data-tooltip]:focus-visible::after {
  opacity: 1; transform: translateX(-50%) translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  [data-tooltip]::after { transition: opacity var(--dur-fast) linear; transform: translateX(-50%); }
}

/* Skeleton loaders — AUDIT: no loading-placeholder pattern anywhere on
   this surface (grepped tra.css — zero hits), beyond the .btn-spinner
   just built for buttons. */
.skeleton {
  position: relative; overflow: hidden; background: var(--sand-100);
  border-radius: var(--r-sm);
}
.skeleton::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .5), transparent);
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .skeleton::after { animation: none; } }
.skeleton-text { height: .85em; margin: var(--s-1) 0; }
.skeleton-text:last-child { width: 70%; }

/* Empty states — UI_STANDARDS.md §8 mandate. AUDIT: this surface has no
   {% empty %} table/loop rendering pattern today (grepped templates/
   public — zero hits), so there's nothing actively violating the rule
   here the way Ops's templates are — but no atom exists to back the rule
   for whenever this surface does grow one (e.g. a future "no stays match
   your search" results page). Added proactively, same shape as Ops's. */
.empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--s-2); padding: var(--s-6) var(--s-4); color: var(--muted);
}
.empty-state__icon { width: 48px; height: 48px; color: var(--muted); opacity: .5; }
.empty-state h3 { margin: 0; color: var(--ink); font-size: var(--fs-h4); }
.empty-state p { margin: 0; max-width: 40ch; }
.empty-state .btn { margin-top: var(--s-2); }

/* ============================================================
   S25 navigation audit — findings for the record (full write-up was in
   ui-preview.html's Components tab, retired S196):

   Pagination — genuinely absent (grepped templates/public + inventory
   views — no Paginator/page_obj anywhere on this surface at all, not
   even ad-hoc). Added proactively, same shape as Ops's new atom, for
   whenever a listing page needs it (e.g. a future search-results page).

   Breadcrumb — NOT absent as this task's premise assumed (S20.2's real
   .crumb lives on Engine, a different surface entirely — see Ops's
   components.css for that correction). This surface has its OWN,
   separate breadcrumb-like nav, hand-duplicated across 6 templates
   (apartment_detail/contact/faqs/location/property_detail/
   type_landing.html): `<nav class="small muted" aria-label="Breadcrumb"
   style="margin-bottom:var(--s-2)">`, no dedicated class, no shared
   atom. This task only asked to confirm/document S20.2 (explicitly "not
   rebuilding") — flagging this second, genuinely ad-hoc pattern for the
   record, not adding an atom for it unprompted (out of this task's
   actual ask).

   Testimonial/pull-quote — NOT absent, this task's premise was wrong:
   .quote-card + .avatar (tra.css, "---- testimonials" section) is a
   complete, real, tokenized testimonial block — background/border/
   shadow/blockquote/figcaption/avatar circle, all real values. It's
   simply unused in any current template today (grepped every templates/
   public file — zero references), i.e. built ahead of a page that
   hasn't shipped rather than genuinely missing. Documented as existing,
   not duplicated. */
.pagination {
  display: flex; align-items: center; justify-content: center;
  gap: var(--s-2); margin-top: var(--s-4);
}
.pagination .page-info { color: var(--muted); font-size: var(--fs-sm); }

/* Rating / review stars — genuinely absent as a reusable atom. .star
   (tra.css) is real but narrower: a single decorative glyph used inline
   with a plain number ("★ 5.0"), confirmed by grep across every real
   usage (home.html, apartment_detail.html, property_detail.html,
   type_landing.html) — never a multi-star visual score with a review
   count. No live review-submission feature exists yet to back an
   interactive version, so this is static display only, same spirit as
   the existing .star usage (reuses --brass-600, already the decorative-
   star color everywhere else on this surface). Numeric rating carries
   the real meaning via aria-label — the glyphs are aria-hidden, same
   pattern the existing .star already uses. */
.rating { display: inline-flex; align-items: center; gap: var(--s-1); }
.rating__stars { color: var(--brass-600); letter-spacing: .0625rem; font-size: var(--fs-sm); }
.rating__count { color: var(--muted); font-size: var(--fs-xs); }

/* Skip-link — confirmed absent (grepped templates/public/base.html), a
   real accessibility floor. Wired live into templates/public/base.html
   — visually hidden until focused, first focusable element on the page. */
.skip-link {
  position: absolute; top: -40px; left: var(--s-2); z-index: 100;
  background: var(--navy-800); color: var(--ink-inverse);
  padding: var(--s-2) var(--s-4); border-radius: var(--r-md);
  font-size: var(--fs-sm); font-weight: 700; text-decoration: none;
  transition: top var(--dur-fast) var(--ease-standard);
}
.skip-link:focus { top: var(--s-2); }

/* FAQ/House Rules — category icon (S226). The vendored SVG (inlined by
   apps.inventory.templatetags.public_faq_icons, not the ops {% icon %}
   tag) carries stroke="currentColor" already, so it just inherits the
   accordion summary's own text color — no color rule needed here. */
.faq-category-heading { font-size: var(--fs-h4); color: var(--navy-900); margin: var(--s-5) 0 var(--s-3); }
.faq-category-heading:first-child { margin-top: 0; }
.faq-q { display: flex; align-items: center; gap: var(--s-3); }
.faq-icon { width: 1.25rem; height: 1.25rem; flex: 0 0 auto; }
