/* ===========================================================================
   RR Elevate — Shared Design System
   ===========================================================================
   Loaded via <link rel="stylesheet" href="css/design-system.css"> BEFORE a
   page's own inline <style> block, so page-specific rules can still extend
   or override anything here without a specificity fight. This file replaces
   the design-token block every page used to duplicate inline (colors, type,
   spacing, radii, shadows, easing) plus formalizes patterns that already
   existed by convention (buttons, section heads, ph-img placeholders,
   loading/empty/error states) and adds a few genuinely new ones the visual
   redesign needs (badges, alerts/validation states, icon sizing).

   Deliberately NOT a rewrite of any page's layout CSS — grid structure,
   card component names (.listing-card, .service-card, etc.), and every
   element ID/data-attribute a page's own <script> depends on stay exactly
   where they are, in that page's own inline <style>/<script>. This file
   only owns tokens and a small set of new reusable utility classes.
   =========================================================================== */

:root {
  /* ---- Color: updated to the approved mockup package's exact values
     (RR Elevate Realty High-Fidelity Mockup Prototype, approved after the
     locality-explorer + second revision pass). Same variable names as
     before so every page's existing var(--color-*) references repaint
     automatically — no page needs its own CSS touched for a color to
     update. ---- */
  --color-obsidian: #0B0B0C;
  --color-graphite: #17171A;
  --color-graphite-elevated: #1E1E21;
  --color-graphite-hover: #232327;
  --color-ivory: #F5F1EA;
  --color-mist: #9A968C;
  --color-mist-dim: #8B877D;
  --color-accent: #2BAE7E;
  --color-accent-hover: #34C48D;
  --color-accent-ink: #04120C;
  --color-line: rgba(245, 241, 234, 0.10);
  --color-line-strong: rgba(245, 241, 234, 0.18);

  /* ---- Semantic surface + state colors (values approved in the mockup) ---- */
  --color-error: #D9695F;
  --color-error-bg: rgba(217, 105, 95, 0.12);
  --color-warning: #E0B34D;
  --color-warning-bg: rgba(224, 179, 77, 0.12);
  --color-success: var(--color-accent);
  --color-success-bg: rgba(43, 174, 126, 0.12);

  /* ---- Type ---- */
  --font-display: "Fraunces", Georgia, serif;
  --font-body: "Inter", -apple-system, sans-serif;

  /* ---- Named type scale. --text-xs stays reserved for genuine metadata
     (eyebrows, badges, tags) only — the approved mockup's accessibility
     pass explicitly moved anything read as normal content (validation
     helper text, body copy) to --text-sm or larger; never back down to
     --text-xs for that. ---- */
  --text-xs: 11.5px;
  --text-sm: 13px;
  --text-base: 14px;
  --text-md: 15px;
  --text-lg: 17px;
  --display-sm: 26px;
  --display-md: 32px;
  --display-lg: 52px;
  --display-xl: 64px;

  /* ---- 4px-based spacing scale (unchanged — already matched the
     approved mockup's own scale) ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-24: 96px;

  /* ---- Radii: the approved mockup uses noticeably softer corners than
     the original redesign pass (6/10/16 vs 2/4/8) — a real, approved
     visual change, not a rounding error. ---- */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-full: 999px;

  --ease-luxury: cubic-bezier(0.19, 1, 0.22, 1);
  --duration-fast: 250ms;
  --duration-base: 400ms;
  --duration-slow: 700ms;

  /* ---- Motion — RR Elevate Motion Specification v2.0 (Architectural Flow).
     Five tokens added on top of the live ease-luxury/duration-* set above,
     which stay exactly as-is (nothing renamed). ---- */
  --duration-micro: 120ms;
  --ease-exit: cubic-bezier(0.33, 0, 0.55, 1);
  --reveal-distance: 18px;
  --stagger-step: 70ms;
  --hover-lift: -4px;

  --shadow-md: 0 12px 32px -12px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 24px 60px -20px rgba(0, 0, 0, 0.6);

  /* ---- Container / breakpoint reference (documented, not enforced here —
     breakpoints stay as plain @media queries per page, matching the
     no-build-step architecture: 640px small / 768px tablet / 1024px desktop) ---- */
  --container-padding-mobile: 20px;
  --container-padding-tablet: 40px;
  --container-padding-desktop: 80px;
  --container-max: 1440px;
}

/* Motion tokens: mobile distances/timings are shorter than desktop
   (Motion Specification §02). 768px matches this file's own existing
   mobile/tablet cutover (see --container-padding-tablet above). */
@media (max-width: 767px) {
  :root {
    --reveal-distance: 12px;
    --stagger-step: 50ms;
  }
}

/* ===== Global reset (identical to every page's existing rule) ===== */
* { margin: 0; padding: 0; box-sizing: border-box; }
@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;
  }
  /* R3 (Motion Specification §05): loops stop and hold at a static, still
     legible opacity rather than snapping to the pulse's final keyframe. */
  .skeleton-bar { animation: none; opacity: 0.7; }
}
body { background: var(--color-obsidian); color: var(--color-ivory); font-family: var(--font-body); -webkit-font-smoothing: antialiased; }
a { text-decoration: none; color: inherit; }
button, input, select, textarea { font-family: var(--font-body); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--color-ivory); outline-offset: 3px;
}

/* ===== Skip link (already present on the pages that have a <main>) ===== */
.skip-link { position: absolute; top: -100px; left: 12px; z-index: 1000; background: var(--color-accent); color: var(--color-obsidian); padding: 10px 18px; border-radius: 6px; font-size: var(--text-sm); font-weight: 600; text-decoration: none; }
.skip-link:focus { top: 12px; }

/* ===== Photo placeholder (identical to every page's existing .ph-img) ===== */
.ph-img { display: block; position: relative; width: 100%; height: 100%; background: #28282a center/cover no-repeat; }
.ph-img:not([style*="background-image"])::after { content: "Photo coming soon"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--font-body); font-size: var(--text-xs); letter-spacing: 0.04em; color: var(--color-mist); opacity: 0.75; pointer-events: none; }

/* ===== Motion — Architectural Flow scroll reveals (Motion Specification
   v2.0, §1, driven by js/motion.js). [data-reveal] elements are fully
   visible in the markup by default — only motion.js ever adds
   .reveal-pending, so a blocked or failed script load never leaves
   content invisible (progressive enhancement). data-reveal-children
   stages direct children individually instead of the block as a whole. ===== */
.reveal-pending {
  opacity: 0;
  transform: translateY(var(--reveal-distance));
  transition: opacity var(--duration-slow) var(--ease-luxury), transform var(--duration-slow) var(--ease-luxury);
}
.reveal-pending.reveal-visible { opacity: 1; transform: none; }
.reveal-instant.reveal-pending { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal-pending { transform: none; transition: opacity 150ms linear; }
}

/* ===== Containers ===== */
.wrap { max-width: var(--container-max); margin: 0 auto; }
section, header, .wrap-pad { padding-left: var(--container-padding-mobile); padding-right: var(--container-padding-mobile); }
@media (min-width: 768px) { section, header, .wrap-pad { padding-left: var(--container-padding-tablet); padding-right: var(--container-padding-tablet); } }
@media (min-width: 1024px) { section, header, .wrap-pad { padding-left: var(--container-padding-desktop); padding-right: var(--container-padding-desktop); } }

/* ===== Buttons — same visual result as every page's existing .btn-primary/
   .btn-secondary, plus two new restrained variants for the editorial
   direction (a quiet outline button and a plain text-link-as-button) ===== */
.btn-primary { background: var(--color-accent); color: var(--color-obsidian); font-weight: 600; font-size: var(--text-base); padding: 16px 30px; border-radius: var(--radius-sm); border: none; cursor: pointer; transition: background var(--duration-fast) var(--ease-luxury); display: inline-block; min-height: 44px; }
.btn-primary:hover { background: var(--color-accent-hover); }
.btn-secondary { background: rgba(245, 241, 234, 0.06); backdrop-filter: blur(6px); color: var(--color-ivory); font-weight: 600; font-size: var(--text-base); padding: 16px 30px; border-radius: var(--radius-sm); border: 1px solid var(--color-line-strong); cursor: pointer; transition: border-color var(--duration-fast) var(--ease-luxury); display: inline-block; min-height: 44px; }
.btn-secondary:hover { border-color: var(--color-ivory); }
/* New — quiet-luxury restrained variant: thin rule, no fill, widens its own
   letter-spacing on hover instead of changing color/background. Used where
   a solid button would read as too "salesy" for the editorial tone. */
.btn-quiet { display: inline-flex; align-items: center; gap: var(--space-2); background: none; border: none; border-bottom: 1px solid var(--color-line-strong); color: var(--color-ivory); font-weight: 600; font-size: var(--text-base); padding: var(--space-2) 0; cursor: pointer; letter-spacing: 0; transition: letter-spacing var(--duration-fast) var(--ease-luxury), border-color var(--duration-fast) var(--ease-luxury); min-height: 44px; }
.btn-quiet:hover { letter-spacing: 0.02em; border-color: var(--color-accent); color: var(--color-accent); }

/* ===== Section heads (identical to every page's existing rules) ===== */
.section-eyebrow { font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-accent); margin-bottom: var(--space-3); }
.section-title { font-family: var(--font-display); font-weight: 300; font-size: var(--display-sm); margin-bottom: var(--space-2); }
@media (min-width: 1024px) { .section-title { font-size: var(--display-md); } }
.section-head-row { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: var(--space-8); gap: var(--space-4); flex-wrap: wrap; }
.section-sub { font-size: var(--text-base); color: var(--color-mist); max-width: 520px; }
.section-link { font-size: var(--text-sm); color: var(--color-accent); white-space: nowrap; }
.section-link:hover { color: var(--color-accent-hover); }

/* ===== New: badges — small inline trust/status labels. Used for genuine,
   code-verifiable states only ("Verified" ties to the real admin-review
   gate; "Pending"/"Coming soon" ties to real absence of content) — never a
   fabricated claim. ===== */
.badge { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; padding: 4px 10px; border-radius: var(--radius-full); line-height: 1.4; }
.badge-verified { background: var(--color-success-bg); color: var(--color-accent); }
.badge-pending { background: rgba(245, 241, 234, 0.08); color: var(--color-mist); border: 1px dashed var(--color-line-strong); }
.badge svg { width: 12px; height: 12px; }

/* ===== New: alerts / validation states — formalizes the pattern already
   used ad hoc as .featured-state.error / role="alert" regions across the
   site into one shared, reusable set of classes. ===== */
.alert { display: flex; align-items: flex-start; gap: var(--space-2); font-size: var(--text-sm); line-height: 1.5; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); }
.alert-error { background: var(--color-error-bg); color: var(--color-error); border: 1px solid rgba(217, 105, 95, 0.3); }
.alert-warning { background: var(--color-warning-bg); color: var(--color-warning); border: 1px solid rgba(224, 179, 77, 0.3); }
.alert-success { background: var(--color-success-bg); color: var(--color-accent); border: 1px solid rgba(43, 174, 126, 0.3); }
/* §8.2/15.3 — plays automatically whenever one of these becomes part of
   the render tree (e.g. a script setting display:block/flex), no JS
   changes needed: CSS keyframe animations restart on display:none->shown. */
@keyframes rrAlertIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.alert-error, .alert-success, .alert-warning { animation: rrAlertIn 200ms var(--ease-luxury); }
@media (prefers-reduced-motion: reduce) { .alert-error, .alert-success, .alert-warning { animation: none; } }
/* §8.5 — success/confirmation panel crossfade (used by each form page's own
   .confirmation-state.show rule); same auto-replay-on-show principle as
   rrAlertIn above. The existing global reduced-motion kill (top of this
   file) already collapses its duration to imperceptible, so no per-page
   override is needed. */
@keyframes rrPanelIn { from { opacity: 0; } to { opacity: 1; } }

/* §8.3 — one restrained ±4px cycle on invalid submit, applied to the form
   panel via RRMotion.nudge(el) (js/motion.js). Not a shake loop. */
@keyframes rrNudge { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.rr-nudge { animation: rrNudge 250ms var(--ease-luxury); }
@media (prefers-reduced-motion: reduce) { .rr-nudge { animation: none; } }
.field-helper { font-size: var(--text-xs); color: var(--color-mist); margin-top: var(--space-1); }
.field-helper.field-error-text { color: var(--color-error); }

/* ===== New: generic form field wrapper — formalizes the label/input/helper
   pattern already repeated ad hoc on every form across the site (contact,
   auth, add-listing, admin). Purely additive: existing page-specific input
   selectors keep working untouched; a page can opt into this wrapper for
   new markup without having to restyle what's already there. ===== */
.field { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-5); }
.field label { font-size: var(--text-sm); font-weight: 600; color: var(--color-ivory); }
.field input, .field select, .field textarea {
  background: var(--color-graphite-elevated); border: 1px solid var(--color-line-strong); border-radius: var(--radius-sm);
  color: var(--color-ivory); font-size: var(--text-base); font-family: var(--font-body); padding: 13px var(--space-4);
  min-height: 44px; transition: border-color var(--duration-fast) var(--ease-luxury);
}
.field input::placeholder, .field textarea::placeholder { color: var(--color-mist); }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--color-accent); }
.field.field-invalid input, .field.field-invalid select, .field.field-invalid textarea { border-color: var(--color-error); }
.field textarea { resize: vertical; min-height: 120px; }

/* ===== New: generic card surface — the base look already shared by
   .listing-card / .service-card / .insight-card etc. Additive only; those
   page-specific classes keep their own layout rules and simply already
   match this visual language. ===== */
.card { background: var(--color-graphite); border: 1px solid var(--color-line); border-radius: var(--radius-lg); overflow: hidden; transition: border-color var(--duration-fast) var(--ease-luxury), transform var(--duration-fast) var(--ease-luxury); }
.card:hover { border-color: var(--color-line-strong); }

/* ===== Loading / empty / error states — generalizes the existing
   .featured-state / .skeleton-card pattern from homepage.html so any page
   can reuse the same visual language for a data-driven section. ===== */
.state-empty, .state-error { text-align: center; padding: var(--space-12) var(--space-5); color: var(--color-mist); font-size: var(--text-sm); grid-column: 1 / -1; animation: rrPanelIn 400ms var(--ease-luxury); }
.state-error { color: var(--color-error); }
.state-empty a, .state-error a { color: var(--color-accent); }
.skeleton-card { background: var(--color-graphite-elevated); border-radius: var(--radius-md); overflow: hidden; }
.skeleton-bar { height: 12px; background: var(--color-graphite); border-radius: 2px; margin-bottom: var(--space-3); animation: rr-pulse 1.4s ease-in-out infinite; }
@keyframes rr-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }

/* ===== Icon sizing — the site already uses real inline SVG (Lucide-style
   outline) icons rather than glyph characters; this just standardizes the
   sizes so every page draws from the same scale instead of ad hoc px
   values. Icons themselves stay inline per-page (no build step, no sprite
   loader), consistent with the rest of the architecture. ===== */
.icon { display: inline-block; vertical-align: middle; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.icon-sm { width: 16px; height: 16px; }
.icon-md { width: 20px; height: 20px; }
.icon-lg { width: 24px; height: 24px; }

/* ===== New: shared site header (navigation) — the approved mockup's
   always-solid sticky header, replacing the old transparent-over-hero/
   scroll-to-solid special case homepage used to have. Purely additive
   new classes: pages keep their own duplicated <nav class="navbar">
   markup/CSS untouched until they're individually migrated onto these
   shared classes (see design-system handoff notes). ===== */
.site-header { position: sticky; top: 0; z-index: 200; border-bottom: 1px solid transparent; background: rgba(11, 11, 12, 0.9); backdrop-filter: blur(10px); transition: border-color var(--duration-fast) var(--ease-luxury); }
.site-header.scrolled { border-bottom-color: var(--color-line); }
.site-header .wrap { display: flex; align-items: center; justify-content: space-between; padding: 18px var(--container-padding-mobile); }
@media (min-width: 768px) { .site-header .wrap { padding: 18px var(--container-padding-tablet); } }
@media (min-width: 1024px) { .site-header .wrap { padding: 18px var(--container-padding-desktop); } }
.logo-mark { display: flex; align-items: center; gap: 9px; font-family: var(--font-display); font-size: 16px; font-weight: 600; letter-spacing: 0.02em; color: var(--color-ivory); }
.logo-mark svg { width: 22px; height: 22px; }
.main-nav { display: none; align-items: center; gap: 30px; list-style: none; }
@media (min-width: 1024px) { .main-nav { display: flex; } }
.main-nav a { font-size: 13.5px; color: var(--color-mist); transition: color var(--duration-fast) var(--ease-luxury); }
.main-nav a:hover, .main-nav a.current { color: var(--color-ivory); }
.header-actions { display: flex; align-items: center; gap: 14px; }
.icon-btn { width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--color-line-strong); background: transparent; display: flex; align-items: center; justify-content: center; color: var(--color-mist); cursor: pointer; }
.icon-btn:hover { border-color: var(--color-ivory); color: var(--color-ivory); }
.hamburger-btn { display: flex; width: 44px; height: 44px; align-items: center; justify-content: center; background: none; border: none; color: var(--color-ivory); cursor: pointer; }
.header-desktop-only { display: none; }
@media (min-width: 1024px) { .header-desktop-only { display: inline-flex; } .hamburger-btn { display: none; } }

/* ===== New: mobile footer accordion — collapses each footer column
   behind a toggle below the mobile breakpoint; every column stays fully
   expanded and visible above it regardless of state. Opt-in via
   data-footer-col/data-footer-toggle + RRNav.initFooterAccordion(), so
   unmigrated pages' existing footer markup is entirely unaffected. ===== */
.footer-col-toggle { display: block; width: 100%; text-align: left; background: none; border: none; padding: 0; margin-bottom: 16px; cursor: default; color: var(--color-mist); }
.footer-col-toggle span:first-child { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-mist); font-weight: 600; }
.footer-col-chevron { display: none; width: 14px; height: 14px; color: var(--color-mist); transition: transform var(--duration-fast) var(--ease-luxury); }
@media (max-width: 900px) {
  .footer-col-toggle { display: flex; align-items: center; justify-content: space-between; cursor: pointer; padding: 14px 0; margin-bottom: 0; min-height: 44px; }
  .footer-col-chevron { display: flex; }
  .footer-col.open .footer-col-chevron { transform: rotate(180deg); }
  .footer-col-links { display: grid; grid-template-rows: 0fr; overflow: hidden; transition: grid-template-rows 200ms var(--ease-exit); }
  .footer-col-links-inner { min-height: 0; overflow: hidden; }
  .footer-col.open .footer-col-links { grid-template-rows: 1fr; transition: grid-template-rows 250ms var(--ease-luxury); }
  .footer-col.open .footer-col-links-inner { padding-top: 10px; }
  .footer-col[data-footer-col] { border-bottom: 1px solid var(--color-line); padding: 16px 0; }
}

/* ===== §9.1 Calculator result-value dip — real recomputed values only;
   see js/motion.js RRMotion.watchValueDip(). ===== */
@keyframes rrValueDip { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
.rr-value-dip { animation: rrValueDip 150ms var(--ease-luxury); }

/* ===== Borders / dividers (documents the existing convention) ===== */
.divider { border: none; border-top: 1px solid var(--color-line); }
