/* ==========================================================================
   Hallmark Homes — Customer Portal
   Static export of the approved design. Values are ported 1:1 from the
   approved comp; do not "improve" them.
   ========================================================================== */

:root {
  --gold: #be955c;
  --gold-soft: #dcc59a;
  /* Added 2026-09-08: Outstanding Items count red-when-nonzero treatment
     (request #1). No prior alert/red color existed in this token set. */
  --alert: #c0392b;
  --navy: #0d1b3e;
  --navy-mid: #16265a;
  --navy-deep: #0a142e;
  --bone: #f3f1ec;
  --line: #eae6df;
  --line-soft: #f2efe9;
  --font-display: "Cormorant Garamond", Georgia, serif;
  --font-body: "Plus Jakarta Sans", Helvetica, Arial, sans-serif;
  --band-a: linear-gradient(135deg, #0d1b3e, #16265a);
  --band-b: linear-gradient(135deg, #be955c, #8a6a35);
  --band-c: linear-gradient(135deg, #3a4259, #0d1b3e);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bone); }
body { font-family: var(--font-body); color: var(--navy); font-size: 15px; -webkit-font-smoothing: antialiased; }
h1, h2, h3, h4, p { margin: 0; font-weight: inherit; }
figure { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { display: block; max-width: 100%; }
figure { margin: 0; }
button { font-family: inherit; }
a { color: var(--gold); text-decoration: none; }
a:hover { color: var(--navy); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #d8d2c6; border-radius: 99px; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.portal { min-height: 100vh; display: flex; flex-direction: column; background: var(--bone); }

/* ------------------------------------------------------------------ header */
.hdr {
  background: var(--navy); padding: 20px 40px;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  position: sticky; top: 0; z-index: 50;
}
.hdr__left { display: flex; align-items: center; gap: 14px; }
.hdr__logo { height: 40px; width: auto; }
.hdr__rule { width: 1px; height: 30px; background: rgba(255,255,255,.18); }
.hdr__kicker { font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: rgba(255,255,255,.62); font-weight: 700; }
.hdr__center { text-align: center; }
.hdr__title { font-family: var(--font-display); color: #fff; font-size: 28px; font-weight: 600; letter-spacing: .01em; }
.hdr__welcome { color: var(--gold); font-size: 11px; letter-spacing: .26em; text-transform: uppercase; font-weight: 700; margin-top: 2px; }
/* PORTAL TEST AUTH MODE indicator (added 2026-08-12) — small but clearly
   visible: high-contrast red chip, deliberately not gold/navy so it never
   reads as normal portal branding. */
.test-mode-badge { display: inline-block; margin-top: 6px; padding: 2px 10px; border-radius: 99px; background: #c0392b; color: #fff; font-size: 10px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.hdr__right { display: flex; align-items: center; justify-content: flex-end; gap: 16px; }
.hdr__who { text-align: right; line-height: 1.2; }
.hdr__name { font-size: 13px; font-weight: 700; color: #fff; }
.hdr__meta { font-size: 11px; color: rgba(255,255,255,.55); }
.hdr__avatar {
  width: 38px; height: 38px; border-radius: 50%; background: var(--gold); color: var(--navy);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px; flex: none;
}

/* ---------------------------------------------------------- profile menu */
.profile { position: relative; }
.profile__trigger {
  display: flex; align-items: center; gap: 12px; background: none; border: none; padding: 4px; cursor: pointer;
  border-radius: 8px;
}
.profile__trigger:hover { background: rgba(255,255,255,.06); }
.profile__menu {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 160px;
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 12px 28px rgba(13,27,62,.18); padding: 6px; z-index: 60;
}
.profile__item {
  display: block; width: 100%; padding: 10px 12px; border-radius: 7px;
  font-size: 13px; font-weight: 600; color: var(--navy); text-align: left;
  box-sizing: border-box;
}
.profile__item:hover { background: var(--line-soft); color: var(--navy); }

/* --------------------------------------------------------------------- nav */
.nav {
  background: #fff; border-bottom: 1px solid #ece8e1; padding: 0 40px;
  display: flex; gap: 32px; align-items: stretch; flex-wrap: wrap;
  /* Centered (item #1A, added 2026-09-08) — was left-justified (flex
     default). Explicitly overridden back to flex-start in the existing
     @media (max-width: 760px) block below so the already-approved
     horizontally-scrollable mobile nav is completely unaffected. */
  justify-content: center;
  position: sticky; top: 80px; z-index: 49;
}
.nav__tab {
  padding: 17px 0; font-size: 14px; font-weight: 500; color: #6e7280;
  background: none; border: none; border-bottom: 3px solid transparent;
  white-space: nowrap; cursor: pointer; font-family: inherit; text-decoration: none;
  transition: color .2s ease, border-bottom-color .25s ease, transform .2s ease, box-shadow .25s ease;
}
/* Glow-up (added 2026-08-14) — these are real navigation, so a richer hover/
   active treatment is an honest cue, not a false one: a soft gold-soft
   underline preview + gentle lift on hover, and a warm glow under the
   current tab's existing gold underline so it reads as clearly "lit up"
   rather than just bold text. No layout properties touched (padding/gap/
   font-size all unchanged), so nothing shifts or reflows differently. */
.nav__tab:hover {
  color: var(--navy);
  border-bottom-color: var(--gold-soft);
  transform: translateY(-1px);
  box-shadow: 0 4px 10px -6px rgba(190,149,92,.55);
}
.nav__tab[aria-current="page"] {
  font-weight: 700; color: var(--navy); border-bottom-color: var(--gold);
  box-shadow: 0 4px 12px -5px rgba(190,149,92,.75);
}
.nav__tab[aria-current="page"]:hover {
  transform: none;
  box-shadow: 0 5px 16px -5px rgba(190,149,92,.85);
}

/* -------------------------------------------------------------------- main */
.main { flex: 1; width: 100%; max-width: 1180px; margin: 0 auto; padding: 34px 40px 10px; }

.eyebrow { font-size: 13px; color: var(--gold); font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.page-title { font-family: var(--font-display); font-size: 38px; font-weight: 600; line-height: 1.05; margin-top: 2px; }
.page-title--lg { font-size: 42px; margin-top: 0; }
/* Home Type secondary line (added 2026-08-12) — small uppercase metadata
   directly beneath the large Plan Short Name; softer gold + smaller size
   than .eyebrow above keeps it clearly subordinate to .page-title--lg. */
.home-type { font-size: 12px; color: var(--gold-soft); font-weight: 700; letter-spacing: .05em; text-transform: uppercase; margin-top: 4px; }
.page-lede { font-size: 14px; color: #6e7280; margin-top: 4px; }
/* Test-mode login lede color only (added 2026-08-12) — color override on top
   of .page-lede above; no size/margin/layout change, and .page-lede itself
   (used elsewhere: app.js's error card, ui.js's pageHead) is untouched. */
.login-lede--test { color: #c0392b; }
.label { font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: #9b958a; font-weight: 700; }
.group-title { font-size: 13px; font-weight: 800; color: var(--navy); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 10px; }

.card { border: 1px solid var(--line); border-radius: 16px; padding: 22px; background: #fff; }
.card--24 { padding: 24px; }
.card--26 { padding: 26px; }
.stack22 { display: flex; flex-direction: column; gap: 22px; margin-top: 22px; }
.card--hero { margin-top: 24px; padding: 30px 32px; background: linear-gradient(180deg, #fbfaf8, #fff); }
.card--col { display: flex; flex-direction: column; }

/* Shared "friendly builder note" callout (added 2026-08-25; restyled
   2026-08-25 to read as a quiet caption/footnote rather than a boxed
   notice) — used by both My Home at a Glance's illustration note and My
   Build Details' Your Selections note. No fill, no border box, no heavy
   accent bar: just a thin gold top divider separating it from the content
   above, a small muted ⓘ, and secondary-sized body text in the app's
   established muted color (#9b958a, used throughout for labels/meta text).
   Still always visible (no accordion/modal behavior); one shared class so
   both notes stay visually identical without duplicated rules. */
.info-callout {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid rgba(190, 149, 92, .35);
}
.info-callout__icon {
  flex: 0 0 auto;
  margin-top: 1px;
  font-size: 11px;
  line-height: 1;
  color: var(--gold);
}
.info-callout__text { min-width: 0; }
.info-callout__heading { margin: 0 0 2px; font-size: 12.5px; font-weight: 700; color: var(--navy); }
.info-callout__body { margin: 0; font-size: 11.5px; line-height: 1.6; color: #9b958a; }

.row-between { display: flex; justify-content: space-between; align-items: flex-end; flex-wrap: wrap; gap: 12px; }
.mt5 { margin-top: 5px; }
.mt14 { margin-top: 14px; }
.mt16 { margin-top: 16px; }
.mt18 { margin-top: 18px; }
.mt22 { margin-top: 22px; }
.stack { display: flex; flex-direction: column; gap: 18px; }
.grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 18px; margin-top: 18px; }
.grid2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; margin-top: 18px; }
.grid-docs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.grid-gal { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.split { display: grid; grid-template-columns: 1.5fr 1fr; gap: 18px; margin-top: 22px; align-items: start; }
.split--warranty { grid-template-columns: 1.3fr 1fr; margin-top: 18px; }
/* My Build Details' Construction Timeline / Your Selections row only
   (added 2026-08-26) — the global .split rule above is unchanged and still
   1.5fr/1fr for every other use.
   MATCHED HEIGHT (added 2026-08-27): align-items: stretch overrides the
   base .split's own align-items: start, so the shorter of the two cards
   stretches to match the taller one — purely content-driven (no fixed or
   min height anywhere here). At the existing @media (max-width: 1040px)
   breakpoint below, .split (which .split--build elements also carry)
   already collapses to a single column; with only one card per row at
   that point, "stretch to match the row" has nothing else to match
   against, so each card naturally returns to its own content height with
   no separate mobile override needed. */
.split--build { grid-template-columns: 1fr 1fr; align-items: stretch; }
/* Added 2026-09-08 (punch-list item #2): Contract Summary (left) / Contract
   Related documents (right, stacked vertically). Left column matches
   .fin's own existing max-width (560px) so the grid track never forces it
   wider than it already renders at; right column takes the remainder.
   .split--contract .fin neutralizes .fin's own baked-in margin-top here
   only — as a normal block-flow section .fin still gets that spacing from
   pageHead everywhere else it might ever be used; as a grid item alongside
   Contract Related it would otherwise sit lower than its sibling. */
.split--contract { grid-template-columns: minmax(0, 560px) 1fr; }
.split--contract .fin { margin-top: 0; }
/* "stacked vertically" — .grid-docs is shared with Documents/Build Details'
   own 3-column layouts elsewhere, so this override is scoped tightly to
   Contract Related's own right-column instance only. */
.split--contract .contract-related .grid-docs { grid-template-columns: 1fr; }

.stat { text-align: right; }
.stat__k { font-size: 12px; color: #9b958a; text-transform: uppercase; letter-spacing: .08em; font-weight: 700; }
.stat__v { font-size: 19px; font-weight: 800; color: var(--navy); }

/* ---------------------------------------------------------- progress (hero) */
.hero__phase { font-size: 19px; color: var(--navy); font-weight: 700; margin-top: 4px; }
.bignum { font-size: 48px; font-weight: 800; color: var(--navy); line-height: 1; letter-spacing: -.03em; }
.bignum span { font-size: 24px; color: var(--gold); }
.bar { height: 8px; background: #eef0f3; border-radius: 99px; margin-top: 18px; overflow: hidden; }
.bar__fill { height: 100%; background: linear-gradient(90deg, var(--navy), var(--gold)); border-radius: 99px; transition: width .6s ease; }

.phases { display: flex; gap: 14px; margin-top: 24px; }
.phase { flex: 1; display: flex; flex-direction: column; gap: 7px; }
.phase__bar { height: 6px; border-radius: 99px; background: #eef0f3; }
.phase--done .phase__bar { background: var(--gold); }
/* Hard color-stop at --phase-fill (set inline per-phase from
   dashboard.phases[].fillPercent) so only the completed portion of the
   ACTIVE phase's bar reads as gold; falls back to a fully-gold bar when
   --phase-fill isn't set (e.g. no Mile Marker data yet). */
.phase--active .phase__bar { background: linear-gradient(90deg, var(--gold) var(--phase-fill, 100%), var(--gold-soft) var(--phase-fill, 100%)); }
.phase__name { font-size: 11.5px; color: #9b958a; font-weight: 600; }
.phase--done .phase__name { color: var(--navy); font-weight: 700; }
.phase--active .phase__name { color: var(--navy); font-weight: 800; }
.phase__sub { font-size: 10px; font-weight: 600; color: #c4c0b8; }
.phase--done .phase__sub { color: #9b958a; }
.phase--active .phase__sub { color: var(--gold); }

/* Preconstruction/CAD phase grid (added 2026-08-11) — same .phase/.phase__bar
   look as the construction phase strip above, just laid out as a 6-column
   grid (2 rows of 6) to fit 12 steps instead of 6 in a flex row. */
.phases--pre { display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; }

/* Outstanding Items (preconstruction mode only, added 2026-08-11). */
.outstanding { margin-top: 24px; border: 1px solid var(--line); border-radius: 16px; padding: 26px 32px; background: #fff; }
.outstanding__count { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--gold); }
/* Added 2026-09-08 (request #1): red ONLY when there's something actually
   awaiting the customer. Base .outstanding__count above is unchanged for
   the zero-count case — it must not read as an alert when nothing's due. */
.outstanding__count--alert { color: var(--alert); }
.outstanding__list { margin-top: 16px; display: flex; flex-direction: column; gap: 12px; }
.outstanding__item { display: flex; gap: 13px; align-items: flex-start; }
.outstanding__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--gold); flex: none; margin-top: 7px; }
.outstanding__body { flex: 1; min-width: 0; }
.outstanding__title { font-size: 14.5px; font-weight: 700; color: var(--navy); }
.outstanding__desc { font-size: 12.5px; color: #6e7280; margin-top: 2px; line-height: 1.5; }
.outstanding__due { font-size: 11.5px; font-weight: 700; color: #9b958a; white-space: nowrap; flex: none; padding-top: 2px; }

/* ------------------------------------------------------------------ metrics */
.metrics { display: flex; gap: 8px; margin-top: 16px; }
.metric { flex: 1; }
.metric__v { font-size: 19px; font-weight: 800; color: var(--navy); }
.metric__k { font-size: 10px; color: #9b958a; text-transform: uppercase; letter-spacing: .06em; font-weight: 600; }

/* --------------------------------------------------------------- key/value */
.kv { display: flex; flex-direction: column; }
.kv--glance { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line-soft); }
.kv--glance .kv__row { display: flex; justify-content: space-between; gap: 10px; padding: 8px 0; border-bottom: 1px solid #f7f5f0; font-size: 13px; }
.kv--glance .kv__row:last-child { border-bottom: 0; }
.kv--glance .kv__k { color: #9b958a; }
.kv--specs { margin-top: 14px; }
.kv--specs .kv__row { display: flex; justify-content: space-between; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; }
.kv--specs .kv__k { color: #6e7280; }
.kv__v { color: var(--navy); font-weight: 700; text-align: right; }

/* Home Specifications horizontal strip (added 2026-08-26, replacing the
   vertical kvRows() list for this one card only — kvRows()/.kv--specs
   above are untouched and still used by Your Selections). Six equal
   columns on desktop, each item's label centered above its value
   centered beneath; column count steps down at narrower widths, staying
   centered at every breakpoint. */
.spec-strip { display: grid; grid-template-columns: repeat(6, 1fr); gap: 18px 14px; margin-top: 4px; }
.spec-strip__item { text-align: center; }
.spec-strip__label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: #9b958a; margin-bottom: 6px; }
.spec-strip__value { font-size: 15px; font-weight: 800; color: var(--navy); }
@media (max-width: 1040px) {
  .spec-strip { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 640px) {
  .spec-strip { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 380px) {
  .spec-strip { grid-template-columns: 1fr; }
}

/* --------------------------------------------------- construction manager */
.cm__who { display: flex; gap: 12px; align-items: center; margin-top: 14px; }
.avatar-navy {
  width: 42px; height: 42px; border-radius: 50%; background: var(--navy); color: var(--gold);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px; flex: none;
}
.cm__name { font-size: 14px; font-weight: 800; color: var(--navy); }
.cm__role { font-size: 11px; color: #9b958a; }
/* min-height/overflow:hidden removed (2026-08-12) — the visible update count
   is now controlled exactly by JS (5 by default, all once expanded), not by
   clipping an arbitrary pixel height; .cm__more (hidden via the native
   `hidden` attribute) takes no box, so .cm__fade below still lands correctly
   at the bottom edge of whatever is currently visible. */
.cm__feed { position: relative; flex: 1; margin-top: 14px; }
.cm__list { display: flex; flex-direction: column; gap: 12px; }
/* .cm__more[hidden] fix (2026-08-12): the [hidden] attribute's implicit
   `display:none` and .cm__list's `display:flex` are equal specificity, and
   the author rule above wins in source order — so a "hidden" .cm__more
   still rendered as flex in the browser. This selector's higher specificity
   (class+attribute vs. class alone) forces display:none while hidden;
   removing the attribute via JS lets .cm__list's flex rule apply again. */
.cm__more[hidden] { display: none; }
.cm__item { font-size: 13px; color: #3a4259; line-height: 1.5; }
.cm__item strong { font-weight: 800; color: var(--navy); }
.cm__fade { position: absolute; left: 0; right: 0; bottom: 0; height: 38px; background: linear-gradient(180deg, rgba(255,255,255,0), #fff); }
.cm__foot { display: flex; justify-content: flex-end; margin-top: 12px; }
/* cursor: not-allowed -> pointer (2026-08-12) — the button is now a real
   View More/View Less toggle instead of a permanently-disabled placeholder;
   same background/border/color/size otherwise, plus a small hover state for
   affordance. */
.btn-expand { background: var(--bone); border: 1px solid var(--line); color: #9b958a; padding: 7px 16px; border-radius: 8px; font-size: 12.5px; font-weight: 700; cursor: pointer; }
.btn-expand:hover { background: var(--line); color: var(--navy); }
/* Added 2026-09-08 (request #3): Previous/Next month paging replaces the
   old "View More" expand-to-long-list pattern, so the button now needs a
   disabled state (both ends of the available months). */
.btn-expand:disabled { opacity: .4; cursor: not-allowed; }
.btn-expand:disabled:hover { background: var(--bone); color: #9b958a; }

/* Construction Manager Update — month grouping (request #3, 2026-09-08).
   Replaces .cm__more/.cm__fade's "reveal a long hidden list" pattern: now
   exactly one .cm__month block is visible at a time (toggled via the
   existing [hidden] attribute, same mechanism already used elsewhere in
   this file), with Previous/Next paging between months instead of a
   single ever-growing list. .cm__more/.cm__fade rules above are no longer
   emitted by dashboard.js but are left in place — harmless, unused. */
.cm__month-label { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--gold); margin-bottom: 8px; }
.cm__foot--nav { justify-content: space-between; }

/* --------------------------------------------------- blueprints to reality */
.bp { position: relative; height: 118px; margin-top: 14px; }
.bp__a { position: absolute; left: 0; top: 0; width: 62%; height: 96px; }
.bp__b { position: absolute; right: 0; bottom: 0; width: 62%; height: 96px; border: 3px solid #fff; box-shadow: 0 6px 18px rgba(13,27,62,.14); }

/* Plot Plan behind Consumer Plans/Blueprint (added 2026-08-12) — stacking
   only; .bp__a/.bp__b's own position/dimensions above are unchanged. */
.bp__a { z-index: 2; }
.bp__b { z-index: 1; }

/* Suppress the striped placeholder background once either placard in this
   two-image composition is populated (added 2026-08-12) — scoped to .bp so
   every other .slot placeholder elsewhere in the portal keeps its stripe. */
.bp .slot--filled { background-color: #fff; background-image: none; }

/* Plot Plan's own filled/fallback state (added 2026-08-12) — same
   suppression as above, named explicitly for this placard per its own
   dedicated class. */
.plot-plan-placard.slot--filled { background-color: #fff; background-image: none; }

.bp-links { margin-top: 16px; display: flex; flex-direction: column; gap: 9px; }
.bp-link { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--navy); font-weight: 600; }
.bp-link .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--gold); flex: none; }
.bp-link .arw { color: var(--gold); font-weight: 700; }

/* My Home — Blueprints to Reality plan-preview height correction
   (2026-09-09, build-page only). The shared .bp/.bp__a/.bp__b base rules
   directly above stay completely unchanged (Dashboard's own dead copy of
   this composition, and any other portal usage, are unaffected). This
   override only enlarges My Build Details' own live Consumer Plans/Plot
   Plan preview so it's no longer visibly cropped — image and container
   heights are scaled by the same factor (~1.8x) so the existing
   overlapped composition's proportions (and each image's own aspect
   ratio) are preserved exactly, just larger; width (62%) is untouched.
   Consumer Plans additionally switches from cover to the same
   contain-fit Plot Plan already uses, so its full page is visible instead
   of cropped top/bottom — Plot Plan's own object-fit is untouched. */
.build-page .bp { height: 212px; }
.build-page .bp__a,
.build-page .bp__b { height: 173px; }
.build-page [data-image-slot="build-gallery-blueprint"] .slot__img { object-fit: contain; object-position: center; }

/* Quick Links menu (request #4, 2026-09-08) — replaces the Blueprints to
   Reality Consumer Plans/Plot Plan placards in this one card. Those images
   and the underlying planLinks documents remain fully available on My
   Build Details ("My Home") — see build.js — so nothing about customer
   access to them changes, only this dashboard card's content. The .bp/
   .bp__a/.bp__b/.bp-links rules above are untouched and still apply to My
   Build Details' own Photo Gallery, which reuses the same class names. */
.qnav { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 14px; }
.qnav__btn {
  background: var(--bone);
  border: 1px solid var(--line);
  color: var(--navy);
  padding: 9px 14px;
  border-radius: 8px;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  transition: background-color .18s ease, color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.qnav__btn:hover { background: var(--gold); color: #fff; transform: translateY(-2px); box-shadow: 0 7px 16px rgba(13,27,62,.12); }
.link-btn { margin-top: 14px; background: none; border: none; color: var(--gold); font-weight: 700; font-size: 13px; cursor: pointer; padding: 0; text-align: left; }

/* ------------------------------------------------ dashboard interaction */
/* All motion is scoped to the Dashboard so shared cards and components on
   the other portal pages retain their existing behavior.
   RECALIBRATED 2026-08-14: the first pass gave every hover state the same
   lift+shadow+shift language normally reserved for buttons and links, so
   whole cards (and several purely-informational rows inside them) looked
   clickable when only specific sub-elements actually are. This pass keeps
   every effect that's tied to something real (the elevation photo, the
   Blueprint/Plot Plan thumbnails+links, View More/Less, View gallery, Refer
   a Friend) and removes or softens the ones that weren't — see inline notes
   below for what changed and why. */
.dashboard-page .card--hero {
  position: relative;
  overflow: hidden;
  box-shadow: 0 8px 24px rgba(13,27,62,.045);
}
.dashboard-page .card--hero::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 35%, rgba(190,149,92,.08) 50%, transparent 65%);
  transform: translateX(-110%);
  transition: transform .7s ease;
}
.dashboard-page .card--hero:hover::after { transform: translateX(110%); }

/* Progress bar (removed 2026-08-14): the original hover state grew the bar
   and revealed a white-ringed circular handle at the fill's edge — the
   literal shape of a slider/scrubber control — on a value that's entirely
   read-only. The fill-in animation on load stays; there's no longer any
   hover-triggered change on the bar itself. */
.dashboard-page .bar__fill {
  animation: dashboard-progress-fill .9s cubic-bezier(.22,.8,.24,1) backwards;
}
@keyframes dashboard-progress-fill {
  from { width: 0; }
}

/* Phase strip (softened 2026-08-14): kept the entrance stagger (plays once
   on load, not hover-gated). Removed the hover behavior that dimmed every
   other phase to .58 opacity and popped the hovered one forward — that
   "spotlight" pattern reads as a picker/selector, but these are a static
   status timeline; nothing happens when you click one. */
.dashboard-page .phase {
  animation: dashboard-phase-in .45s ease backwards;
}
.dashboard-page .phase:nth-child(2) { animation-delay: .04s; }
.dashboard-page .phase:nth-child(3) { animation-delay: .08s; }
.dashboard-page .phase:nth-child(4) { animation-delay: .12s; }
.dashboard-page .phase:nth-child(5) { animation-delay: .16s; }
.dashboard-page .phase:nth-child(6) { animation-delay: .20s; }
.dashboard-page .phase:nth-child(n+7) { animation-delay: .24s; }
@keyframes dashboard-phase-in {
  from { opacity: 0; transform: translateY(6px); }
}

/* Metric tiles / key-value rows / Construction Manager Update items /
   Outstanding items (softened 2026-08-14): dropped the translateY/translateX
   shift — that directional "move out of the way" motion combined with a
   color/background change is the standard "clickable row" cue, and none of
   these rows do anything on click. A quiet background-only tint stays, more
   like a reading highlight than a button state, and with no cursor change
   it doesn't suggest interactivity. */
.dashboard-page .metric,
.dashboard-page .kv--glance .kv__row,
.dashboard-page .cm__item,
.dashboard-page .outstanding__item {
  border-radius: 7px;
  transition: background-color .18s ease;
}
.dashboard-page .metric:hover,
.dashboard-page .kv--glance .kv__row:hover,
.dashboard-page .cm__item:hover,
.dashboard-page .outstanding__item:hover {
  background: rgba(190,149,92,.06);
}
.dashboard-page .cm__item { padding: 5px 7px; margin: -5px -7px; }

/* An outstanding item's title is a real link only when the item genuinely
   has a live action (added 2026-08-27 — e.g. the Selections Sheet once a
   usable document URL exists). Scoped to .outstanding__title a
   specifically so the established "quiet reading highlight, no cursor
   change" treatment on .outstanding__item above is completely unchanged
   for every item without a real link. */
.dashboard-page .outstanding__title a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid rgba(190,149,92,.4);
  transition: color .18s ease, border-color .18s ease;
}
.dashboard-page .outstanding__title a:hover,
.dashboard-page .outstanding__title a:focus-visible {
  color: var(--gold);
  border-color: var(--gold);
}
.dashboard-page .outstanding__title a:focus-visible {
  outline: 2px solid rgba(190,149,92,.45);
  outline-offset: 2px;
}

/* Blueprint / Plot Plan images (fixed 2026-08-14): the tilt-apart hover used
   to fire for BOTH images any time you hovered the .bp container, even when
   one of them was the plain, non-clickable placeholder (a blank/invalid
   Consumer Plans or Plot Plan field renders no <a> at all). :has() scopes
   the tilt to only the image that's actually wrapped in a real link — the
   fallback tile no longer implies it's clickable when it isn't. */
.dashboard-page .bp__a,
.dashboard-page .bp__b,
.dashboard-page .slot__img {
  transition: transform .24s ease, box-shadow .24s ease;
}
.dashboard-page .bp:hover .bp__a:has(a.slot__link) { transform: translate(-3px, -3px) rotate(-.5deg); }
.dashboard-page .bp:hover .bp__b:has(a.slot__link) { transform: translate(3px, 3px) rotate(.5deg); }
.dashboard-page .slot--filled:hover .slot__img { transform: scale(1.025); }
/* Same fix for the text links below the images: a blank/invalid plan link
   renders as plain <span class="bp-link"> text (no href) — scoping to
   a.bp-link keeps the hover feedback only on the real, clickable version. */
.dashboard-page .bp-link { border-radius: 6px; }
.dashboard-page a.bp-link { transition: color .18s ease, background-color .18s ease, transform .18s ease; }
.dashboard-page a.bp-link:hover { color: var(--navy); background: rgba(190,149,92,.08); transform: translateX(3px); }
.dashboard-page a.bp-link .arw { transition: transform .18s ease; }
.dashboard-page a.bp-link:hover .arw { transform: translate(2px, -2px); }
.dashboard-page .link-btn,
.dashboard-page .btn-expand,
.dashboard-page .referral__btn { transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease, color .18s ease; }
.dashboard-page .link-btn:hover { color: var(--navy); transform: translateX(3px); }
.dashboard-page .btn-expand:hover,
.dashboard-page .referral__btn:hover { transform: translateY(-2px); box-shadow: 0 7px 16px rgba(13,27,62,.12); }
/* Added 2026-09-08 (request #3): a disabled Previous/Next button (at
   either end of the available months) must not lift on hover. */
.dashboard-page .btn-expand:disabled:hover { transform: none; box-shadow: none; }

.dashboard-page > .card--hero,
.dashboard-page > .outstanding,
.dashboard-page > [data-component="home-specifications"],
.dashboard-page > .grid3,
.dashboard-page > [data-component="construction-timeline"],
.dashboard-page > [data-component="preconstruction-timeline"],
.dashboard-page > [data-component="photo-gallery"],
.dashboard-page > .referral {
  animation: dashboard-section-in .48s ease backwards;
}
.dashboard-page > .grid3 { animation-delay: .08s; }
/* Added 2026-09-08 (item #2, My Home/My Progress content split) — Home
   Specs/Construction Timeline/Photo Gallery are new to this page, staggered
   consistently with the existing sections above/below them. */
.dashboard-page > [data-component="construction-timeline"],
.dashboard-page > [data-component="preconstruction-timeline"] { animation-delay: .10s; }
.dashboard-page > [data-component="photo-gallery"] { animation-delay: .12s; }
.dashboard-page > .referral { animation-delay: .16s; }
@keyframes dashboard-section-in {
  from { opacity: 0; transform: translateY(8px); }
}

.dashboard-elevation { position: relative; cursor: zoom-in; }
.dashboard-elevation__hint {
  position: absolute;
  right: 10px;
  bottom: 10px;
  margin: 0 !important;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .18s ease, transform .18s ease;
}
.dashboard-elevation:hover .dashboard-elevation__hint,
.dashboard-elevation:focus-visible .dashboard-elevation__hint { opacity: 1; transform: none; }
body.has-elevation-lightbox { overflow: hidden; }
.elevation-lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 28px;
  animation: elevation-lightbox-in .2s ease backwards;
}
.elevation-lightbox[hidden] { display: none; }
.elevation-lightbox__backdrop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: rgba(6,13,30,.88);
  cursor: zoom-out;
}
.elevation-lightbox__panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: min(1200px, 94vw);
  max-height: 92vh;
  padding: 12px;
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 30px 80px rgba(0,0,0,.45);
}
.elevation-lightbox__image { max-width: 100%; max-height: calc(92vh - 68px); object-fit: contain; border-radius: 8px; }
.elevation-lightbox__close {
  position: absolute;
  top: -14px;
  right: -14px;
  width: 38px;
  height: 38px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--navy);
  color: #fff;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.elevation-lightbox__open { align-self: flex-end; margin-top: 9px; font-size: 12px; font-weight: 800; }
@keyframes elevation-lightbox-in { from { opacity: 0; } }

@media (hover: none) {
  .dashboard-elevation__hint { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .dashboard-page *,
  .dashboard-page *::before,
  .dashboard-page *::after,
  .elevation-lightbox,
  .elevation-lightbox * {
    animation-duration: .01ms !important;
    animation-delay: 0ms !important;
    transition-duration: .01ms !important;
  }
}

/* ------------------------------------------------------- image placeholder */
.slot {
  border-radius: 10px; overflow: hidden;
  background-color: #faf8f4;
  background-image: repeating-linear-gradient(135deg, rgba(13,27,62,.055) 0 8px, transparent 8px 16px);
  border: 1px solid var(--line);
  display: flex; align-items: flex-end; padding: 8px;
}
.slot span {
  font-family: ui-monospace, Menlo, monospace; font-size: 9.5px; letter-spacing: .04em;
  text-transform: uppercase; color: #9b958a; background: rgba(255,255,255,.82);
  padding: 2px 6px; border-radius: 4px;
}
/* Responsive 4:3 aspect ratio (updated 2026-08-12) — matches the
   standardized 1200x900 elevation source images, replacing the old fixed
   height: 118px so the placard grows/shrinks with card width instead of
   letterboxing a 4:3 photo inside a much wider fixed-height box. Width,
   margin-top, and every other .slot/.slot--filled/.slot__img rule above
   are unchanged. */
.slot--glance { width: 100%; height: auto; aspect-ratio: 4 / 3; margin-top: 14px; }
/* No diagonal striping anywhere in this gallery (added 2026-08-13) — filled
   (Blueprint/Site photo) and empty (Foundation/Framing) states alike, per
   instruction. .slot--gal is used exclusively by My Build Details' photo
   gallery (assets/js/views/build.js), so this doesn't touch any other
   .slot placeholder elsewhere in the portal. .slot's own background-color
   (#faf8f4, a warm white) is unaffected and still shows through. */
.slot--gal { width: 100%; height: 140px; background-image: none; }

/* Filled Blueprint placard (added 2026-08-12, fixed 2026-08-12). Purely
   additive: .slot / .slot span / .bp__a / .bp__b above are completely
   unchanged, so dimensions, rounded corners (border-radius + overflow:hidden,
   both on .slot), shadow/border (.bp__b), overlap (.bp), and card layout are
   all inherited exactly as before. CSS Grid (not absolute positioning)
   stacks the thumbnail behind the existing "Blueprint" label — grid items
   paint in DOM order when z-index is unset, so the label (declared after
   the image in the markup) sits on top with no extra z-index rule needed.
   FIX: the single grid track needs an explicit size (grid-template) — an
   auto-sized track resolves percentage heights/widths on its children
   against their own content instead of the track, so the image was
   rendering at its own small intrinsic size instead of filling the card.
   Also, align-items/justify-items on .slot__link position the LABEL
   (bottom-left, matching the original placeholder) but as a side effect
   turn off Grid's default stretch sizing for every child — .slot__img
   explicitly opts back into stretch via align-self/justify-self so it still
   fills the entire card edge-to-edge. The 8px inset that used to come from
   the figure's own padding (now 0, so the image can reach the edges) moves
   to the label itself via a scoped margin, affecting only this filled
   variant — the shared, still-untouched .slot span rule keeps its old
   padding/background/font styling exactly as before. */
.slot--filled { padding: 0; }
.slot__link { display: grid; grid-template: 1fr / 1fr; align-items: end; justify-items: start; width: 100%; height: 100%; text-decoration: none; }
.slot__link > * { grid-area: 1 / 1; }
.slot__img { align-self: stretch; justify-self: stretch; width: 100%; height: 100%; object-fit: cover; }
.slot--filled .slot__link span { margin: 8px; }

/* My Home at a Glance elevation photo (added 2026-08-12) — narrowly scoped
   modifier so the elevation photo shows uncropped (object-fit: contain,
   centered, against the existing .slot background) without touching
   .slot__img's own object-fit: cover, which the Blueprint/Consumer Plans
   thumbnail still relies on unchanged. */
.slot__img--contain { object-fit: contain; object-position: center; }

/* ---------------------------------------------------------------- timeline */
.tl { display: grid; grid-template-columns: 24px 1fr; gap: 14px; }
.tl__rail { display: flex; flex-direction: column; align-items: center; }
.tl__dot { width: 15px; height: 15px; border-radius: 50%; flex: none; background: #fff; border: 2px solid #dcd6cb; }
.tl--done .tl__dot { background: var(--gold); border-color: var(--gold); }
.tl--active .tl__dot { background: var(--gold); border-color: #fff; }
.tl__line { width: 2px; flex: 1; background: #eef0f3; min-height: 34px; }
.tl__body { padding-bottom: 18px; }
.tl__head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.tl__name { font-size: 15px; font-weight: 800; color: var(--navy); }
.tl--up .tl__name { color: #9b958a; }
.tl__status { font-size: 11px; font-weight: 700; color: #9b958a; text-transform: uppercase; letter-spacing: .06em; white-space: nowrap; }
.tl--active .tl__status { color: var(--gold); }
.tl--up .tl__status { color: #c4c0b8; }
.tl__desc { font-size: 12.5px; color: #6e7280; margin-top: 3px; line-height: 1.5; }
.tl__date { font-size: 11px; color: #9b958a; margin-top: 4px; font-weight: 600; }

/* Timeline in My Progress' grid3 third column (moved 2026-09-09, punch-list
   correction — was previously a full-width card). Presentation-only fit
   adjustment for the narrower card: name/status stack instead of being
   squeezed onto one line via .tl__head's row layout above. No timeline
   data/state/mode logic touched, and the base .tl__head rule (used
   wherever else this component appears) is unchanged. */
.dashboard-page [data-component="preconstruction-timeline"] .tl__head,
.dashboard-page [data-component="construction-timeline"] .tl__head {
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

/* ----------------------------------------------------------- plan doc tile */
.plan { display: flex; align-items: center; gap: 12px; background: #faf8f4; border: 1px solid #eee9e0; border-radius: 10px; padding: 14px 16px; }
.plan__tag { width: 34px; height: 42px; border-radius: 5px; background: var(--navy); color: var(--gold); display: flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 800; flex: none; }
.plan__body { flex: 1; min-width: 0; }
.plan__name { font-size: 14px; font-weight: 700; color: var(--navy); }
.plan__meta { font-size: 11px; color: #9b958a; }
.plan__arw { color: var(--gold); font-weight: 700; font-size: 16px; flex: none; }

/* ------------------------------------------------------------ document rows */
.doclist { border: 1px solid var(--line); border-radius: 14px; background: #fff; overflow: hidden; }
.docrow { display: flex; align-items: center; gap: 16px; padding: 15px 20px; border-bottom: 1px solid var(--line-soft); }
.docrow:last-child { border-bottom: 0; }
.docrow__tag { width: 38px; height: 46px; border-radius: 5px; background: var(--navy); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 800; flex: none; }
.docrow__tag--pdf { background: #c0392b; }
.docrow__tag--xls { background: #1e7d4f; }
.docrow__body { flex: 1; min-width: 0; }
.docrow__name { font-size: 14px; font-weight: 700; color: var(--navy); }
.docrow__meta { font-size: 12px; color: #9b958a; }
.btn-dl { background: var(--navy); color: #fff; border: none; padding: 8px 16px; border-radius: 7px; font-size: 12.5px; font-weight: 700; cursor: pointer; flex: none; text-decoration: none; }
.btn-dl:hover { color: #fff; }

/* ------------------------------------------------------- contract related */
.ctile { display: flex; align-items: center; gap: 12px; background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; }
.ctile__tag { width: 34px; height: 42px; border-radius: 5px; background: var(--navy); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 800; flex: none; }
.ctile__tag--gold { background: var(--gold); }
.ctile__body { flex: 1; min-width: 0; }
.ctile__name { font-size: 14px; font-weight: 700; color: var(--navy); }
.ctile__meta { font-size: 11px; color: #9b958a; }
.ctile__desc { font-size: 11px; color: #9b958a; margin-top: 2px; }
.ctile__action { flex: none; font-weight: 700; font-size: 16px; color: var(--gold); }
.ctile__action--date { font-size: 12px; color: var(--navy); }

/* Non-clickable availability states (added 2026-08-27) — Pending/Coming
   Soon/Not Available occupy the exact same action-slot markup Download
   normally uses, but as plain non-interactive text: no href, no '#', no
   click handler, so no focus ring or hover lift is possible in the first
   place (an inert <span>/<div> was never a control to begin with — no
   extra ARIA needed to "un-role" it). Reuses colors already established
   elsewhere on this exact page rather than inventing new ones: #9b958a is
   the same muted tone already used for .docrow__meta/.ctile__meta, and
   var(--line) is the same border already used for .ctile's own default
   border. */
.btn-dl--status {
  background: transparent;
  color: #9b958a;
  border: 1px solid var(--line);
  cursor: default;
}
.ctile--status {
  cursor: default;
}
.ctile__action--status {
  font-size: 12px;
  font-weight: 700;
  color: #9b958a;
}

/* --------------------------------------------------------------- financials */
.fin { max-width: 560px; margin-top: 22px; padding: 30px; }
.fin__rows { margin-top: 18px; }
.fin__row { display: flex; justify-content: space-between; padding: 14px 0; border-bottom: 1px solid var(--line-soft); font-size: 15px; }
.fin__k { color: #6e7280; }
.fin__v { color: var(--navy); font-weight: 700; }
.fin__total { display: flex; justify-content: space-between; align-items: center; margin-top: 14px; background: var(--navy); border-radius: 12px; padding: 18px 22px; }
.fin__total-k { color: #fff; font-weight: 800; font-size: 16px; }
.fin__total-v { color: var(--gold); font-weight: 800; font-size: 24px; }

/* ------------------------------------------------------- change order audit */
/* Added 2026-08-25 for Contract & Financials' Change Order Audit section.
   Current-revision cards use the portal's normal card look (no override
   needed below); superseded cards get a muted palette + explicit badge —
   visible for audit purposes, never hidden, but never confused for the
   active revision either.

   CORRECTED 2026-08-25: no dollar figure (per-card subtotal or an overall
   "current total") is ever rendered in this section — Knack's field_4473
   (Change Orders Total, shown in the Finance Summary card instead) is the
   only authoritative Change Orders dollar value. .co-audit__current-total
   and .co-card__subtotal are removed as dead rules for that reason. */
.co-audit { display: flex; flex-direction: column; gap: 16px; margin-top: 14px; }

.co-card { border: 1px solid var(--line); border-radius: 14px; background: #fff; overflow: hidden; }
.co-card--superseded { background: #faf9f6; border-color: #ece7dc; }

.co-card__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; padding: 16px 20px; border-bottom: 1px solid var(--line-soft); }
.co-card--superseded .co-card__head { border-bottom-color: #ece7dc; }
.co-card__head-text { display: flex; flex-direction: column; gap: 5px; }
.co-card__version { font-size: 14.5px; font-weight: 800; color: var(--navy); }
.co-card--superseded .co-card__version { color: #8a8577; }
.co-card__badge {
  display: inline-block; width: fit-content;
  font-size: 10.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: #a3401e; background: #f6e7de; padding: 3px 9px; border-radius: 99px;
}
.co-card__badge--current { color: var(--navy); background: var(--gold-soft); }
.co-card__count { font-size: 11px; font-weight: 700; color: #9b958a; text-transform: uppercase; letter-spacing: .04em; }

.co-card__note { font-size: 12.5px; color: #8a8577; line-height: 1.55; padding: 12px 20px 0; margin: 0; }
/* Added 2026-09-08 (item #3): Show/Hide History toggle, superseded
   revisions only. Reuses .btn-expand — same control already used for the
   Dashboard's CM Update Previous/Next paging. */
.co-card__toggle { margin: 10px 20px 16px; }
.co-card__empty { font-size: 13px; color: #6e7280; font-style: italic; padding: 16px 20px 20px; margin: 0; }

.co-card__rows { display: flex; flex-direction: column; }
.co-row {
  display: grid; grid-template-columns: 1.6fr .7fr auto; align-items: center; gap: 14px;
  padding: 14px 20px; border-bottom: 1px solid var(--line-soft);
  transition: background-color .18s ease, padding-left .18s ease, box-shadow .18s ease;
}
.co-card__rows .co-row:last-child { border-bottom: 0; }
.co-row__main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.co-row__label { font-size: 13px; font-weight: 800; color: var(--navy); font-family: ui-monospace, Menlo, monospace; }
.co-card--superseded .co-row__label { color: #8a8577; }
.co-row__desc { font-size: 12.5px; color: #6e7280; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.co-row__amount { font-size: 13.5px; font-weight: 800; color: var(--navy); text-align: right; }
.co-card--superseded .co-row__amount { color: #8a8577; }
.co-row__action {
  font-size: 12px; font-weight: 800; color: var(--gold); text-decoration: none; white-space: nowrap;
  padding: 5px 9px; border-radius: 7px; transition: transform .18s ease, background-color .18s ease;
}
.co-row__action--none { color: #c4c0b8; }

/* Column header row — same grid as .co-row above so labels line up exactly
   with the data beneath them. No :has(a.co-row__action) match here (there's
   no real link inside it), so the hover/focus treatment further down never
   fires on it — it's inert by construction, not by an extra override. */
.co-row--head { border-bottom-color: var(--line); }
.co-row__head { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: #9b958a; }
.co-row__head--amount { text-align: right; }

/* Hover/focus only fires when the row actually contains a real "View CO"
   link — same "never imply an action that doesn't exist" posture as
   build.js's .slot--gal:has(a.slot__link) and .plan hover rules elsewhere
   in this file. :focus-within (keyboard-focusing the link) gets the exact
   same row treatment as :hover, and the link itself gets its own strong
   :focus-visible outline below so keyboard focus is never ambiguous even
   before the row-level highlight kicks in. */
@media (hover: hover) and (pointer: fine) {
  .co-row:has(a.co-row__action):hover,
  .co-row:has(a.co-row__action):focus-within {
    background: #fdf8e3;
    padding-left: 24px;
    box-shadow: inset 3px 0 0 var(--gold);
  }
  .co-row:has(a.co-row__action):hover .co-row__action,
  .co-row:has(a.co-row__action):focus-within .co-row__action {
    transform: translateX(2px);
    background: rgba(190,149,92,.14);
  }
}
.co-row:has(a.co-row__action):focus-within {
  background: #fdf8e3;
}
.co-row__action:focus-visible {
  outline: 3px solid rgba(190,149,92,.45);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .co-row, .co-row__action { transition: none !important; }
}

@media (max-width: 760px) {
  .co-row { grid-template-columns: 1fr; row-gap: 6px; }
  .co-row__amount { text-align: left; }
  .co-card__head { flex-direction: column; }
}

/* ---------------------------------------------- financials page interaction */
/* Added 2026-08-25, scoped entirely to .financials-page so Documents' own
   .ctile hover/lift rules (.documents-page .ctile--download:hover etc.,
   above) and every other page are completely unaffected — same shared
   .ctile component, two independent page-scoped rulesets. The .co-*
   interaction rules directly above this are untouched. */

/* Contract Related tiles are real links (contractTile() in ui.js renders
   an <a>), so they get the portal's usual "this is clickable" treatment:
   lift + soft shadow + a stronger border accent on hover/focus. */
.financials-page .ctile {
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.financials-page .ctile:hover,
.financials-page .ctile:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px rgba(13,27,62,.12);
  border-color: rgba(190,149,92,.55);
}
.financials-page .ctile:focus-visible {
  outline: 3px solid rgba(190,149,92,.45);
  outline-offset: 2px;
}

/* Contract Summary rows are informational only (plain text, no link, no
   click handler) — cursor stays default and nothing lifts, so hovering one
   never implies an action that doesn't exist. Just a quiet reading
   highlight: pale-yellow background + a slim gold left accent. */
.financials-page .fin__row {
  cursor: default;
  border-radius: 6px;
  transition: background-color .18s ease, padding-left .18s ease, box-shadow .18s ease;
}
.financials-page .fin__row:hover {
  background: #fdf8e3;
  padding-left: 10px;
  box-shadow: inset 3px 0 0 var(--gold);
}

@media (prefers-reduced-motion: reduce) {
  .financials-page .ctile,
  .financials-page .fin__row {
    transition: none !important;
  }
}

/* ----------------------------------------------------------------- contacts */
.cmcard { border: 1px solid var(--line); border-radius: 16px; padding: 28px; background: linear-gradient(110deg, var(--navy), var(--navy-mid)); color: #fff; margin-top: 22px; display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }

/* Warranty Manager card (added 2026-09-08, punch-list item #3) — a
   shallow horizontal intro/contact card, NOT a hero: existing card
   radius/spacing/typography, navy/gold accents matching .contact/.cmcard's
   own established language. Photo is thumbnail-sized (84px, within the
   72-96px target) and circular; object-fit: cover keeps a non-square
   source photo from distorting. Missing/failed photo falls back to the
   same initials-circle treatment (see warranty.js's onerror handler and
   its own no-photo branch), so contact info is never blocked on the image. */
.wm-card { display: flex; align-items: center; gap: 20px; padding: 22px 26px; }
.wm-card__photo { flex: none; width: 84px; height: 84px; }
.wm-card__img {
  width: 84px; height: 84px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--gold-soft); display: block;
}
.wm-card__initials {
  width: 84px; height: 84px; border-radius: 50%; background: var(--bone);
  color: var(--navy); border: 2px solid var(--gold-soft);
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 26px;
}
.wm-card__body { flex: 1; min-width: 0; }
.wm-card__role { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--gold); font-weight: 700; }
.wm-card__name { font-size: 17px; font-weight: 800; color: var(--navy); margin-top: 1px; }
.wm-card__intro { font-size: 13px; color: #6e7280; line-height: 1.5; margin: 6px 0 0; max-width: 62ch; }
.wm-card__contact { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 8px; }
.wm-card__contact-line { font-size: 12.5px; color: #6e7280; }
.wm-card__contact-line a { color: var(--navy); font-weight: 600; }
.wm-card__contact-line a:hover { color: var(--gold); }
.cmcard__avatar { width: 72px; height: 72px; border-radius: 16px; background: var(--gold); color: var(--navy); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 24px; flex: none; }
.cmcard__body { flex: 1; min-width: 200px; }
.cmcard__role { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--gold); font-weight: 700; }
.cmcard__name { font-size: 22px; font-weight: 800; margin-top: 3px; }
.cmcard__meta { font-size: 13px; color: #c6cee0; margin-top: 2px; }
.cmcard__meta a { color: #c6cee0; }
.cmcard__meta a:hover { color: #fff; }
.cmcard__actions { display: flex; gap: 10px; }

.btn-gold { background: var(--gold); color: var(--navy); border: none; padding: 11px 20px; border-radius: 8px; font-size: 13px; font-weight: 800; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; text-decoration: none; }
.btn-gold:hover { color: var(--navy); background: var(--gold-soft); }
.btn-light { background: rgba(255,255,255,.12); color: #fff; border: 1px solid rgba(255,255,255,.25); padding: 11px 20px; border-radius: 8px; font-size: 13px; font-weight: 700; cursor: pointer; text-decoration: none; }
.btn-light:hover { color: #fff; background: rgba(255,255,255,.2); }
.btn-navy { display: inline-flex; align-items: center; justify-content: center; gap: 8px; background: var(--navy); color: #fff; padding: 10px 16px; border-radius: 8px; font-size: 13px; font-weight: 700; text-decoration: none; border: none; cursor: pointer; }
.btn-navy:hover { color: #fff; background: var(--navy-mid); }
.btn-navy--lg { padding: 11px 22px; font-weight: 800; margin-top: 16px; }

.contact { display: flex; gap: 16px; align-items: center; }
.contact__avatar { width: 54px; height: 54px; border-radius: 50%; background: var(--bone); color: var(--navy); border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 17px; flex: none; }
.contact__body { flex: 1; min-width: 0; }
.contact__role { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--gold); font-weight: 700; }
.contact__name { font-size: 16px; font-weight: 800; color: var(--navy); margin-top: 1px; }
.contact__line { font-size: 12.5px; color: #6e7280; }
.contact__line a { color: #6e7280; }
.contact__line a:hover { color: var(--navy); }
/* Added 2026-09-08 (punch-list items #4/#6): "Tap to call"/"Click to
   email" helper text. Base rule below is for the light-background contact
   grid cards; .cmcard__meta's own override further down (dark navy
   gradient background) keeps it legible there instead of nearly
   invisible. */
.contact-hint { display: inline-block; margin-left: 6px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: #b7bcc7; }
.cmcard__meta .contact-hint { color: #8fa0c4; }

/* ---------------------------------------------------------------- resources */
.res { border: 1px solid var(--line); border-radius: 16px; background: #fff; overflow: hidden; display: flex; flex-direction: column; }
.res__band { height: 96px; display: flex; align-items: flex-end; padding: 14px; }
.res__tag { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: #fff; background: rgba(13,27,62,.35); padding: 4px 10px; border-radius: 99px; }
.res__body { padding: 18px; flex: 1; display: flex; flex-direction: column; }
.res__title { font-size: 15.5px; font-weight: 800; color: var(--navy); line-height: 1.25; }
.res__desc { font-size: 13px; color: #6e7280; margin-top: 6px; line-height: 1.5; flex: 1; }

/* Interaction pass (added 2026-08-27) — reuses the exact established
   portal values below verbatim, nothing invented. .res is used exclusively
   by this page (confirmed — no other view renders it), so these rules are
   inherently scoped without needing a page-wrapper class. */

/* Card hover/focus lift — identical values to .financials-page .ctile
   (translateY(-3px), the same navy-tinted shadow, a stronger gold border
   accent, .18s ease, gold focus-visible outline). */
.res {
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.res:hover,
.res:focus-within {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px rgba(13,27,62,.12);
  border-color: rgba(190,149,92,.55);
}
.res:focus-within {
  outline: 3px solid rgba(190,149,92,.45);
  outline-offset: 2px;
}

/* View Document button lift — identical values to .dashboard-page's
   .btn-expand/.referral__btn (translateY(-2px), the same navy-tinted
   shadow, .18s ease). Scoped to .res .btn-navy specifically, not the base
   .btn-navy rule, since that class is shared with other pages (e.g. the
   connection-error screen) this pass isn't touching. */
.res .btn-navy {
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease, color .18s ease;
}
.res .btn-navy:hover,
.res .btn-navy:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 7px 16px rgba(13,27,62,.12);
}

/* Entrance fade-rise — same mechanics/timing as .dashboard-page .phase
   (.48s ease backwards, translateY(8px), the identical .04s-per-card
   stagger capped at .24s). Applied per-card via the unique .res class
   rather than animating the shared .grid3 wrapper as one block (unlike
   Dashboard's own .grid3 entrance) — .grid3 is also used by Dashboard and
   Warranty, so animating it here would leak onto both; .res is unique to
   this page, and per-card stagger also scales correctly to Resources' own
   arbitrary live record count (0-20+), which a single fixed-row fade
   would not. */
.res {
  animation: resources-card-in .48s ease backwards;
}
.res:nth-child(2) { animation-delay: .04s; }
.res:nth-child(3) { animation-delay: .08s; }
.res:nth-child(4) { animation-delay: .12s; }
.res:nth-child(5) { animation-delay: .16s; }
.res:nth-child(6) { animation-delay: .20s; }
.res:nth-child(n+7) { animation-delay: .24s; }
@keyframes resources-card-in {
  from { opacity: 0; transform: translateY(8px); }
}

@media (prefers-reduced-motion: reduce) {
  .res,
  .res .btn-navy {
    transition: none !important;
    animation: none !important;
  }
}

/* ----------------------------------------------------------------- warranty */
.wterm { font-size: 32px; font-weight: 800; color: var(--gold); }
.wtitle { font-size: 15px; font-weight: 800; color: var(--navy); margin-top: 4px; }
.wdesc { font-size: 13px; color: #6e7280; margin-top: 6px; line-height: 1.5; }
.steps { margin-top: 18px; display: flex; flex-direction: column; gap: 18px; }
.step { display: flex; gap: 15px; align-items: flex-start; }
.step__n { width: 30px; height: 30px; border-radius: 50%; background: var(--navy); color: var(--gold); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 13px; flex: none; }
.step__body { flex: 1; padding-top: 2px; }
.step__t { font-size: 14.5px; font-weight: 800; color: var(--navy); }
.step__d { font-size: 13px; color: #6e7280; margin-top: 3px; line-height: 1.5; }
.btn-gold--tut { margin-top: 22px; }
/* Added 2026-09-08 (item #9): Submit Claim Now, directly below the
   tutorial button — smaller gap than .btn-gold--tut's own 22px since the
   two buttons are visually grouped together at the bottom of the card. */
.btn-navy--claim { margin-top: 12px; }
.wlink { display: flex; align-items: center; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--line-soft); }
.wlink:last-child { border-bottom: 0; }
.wlink__tag { width: 38px; height: 46px; border-radius: 5px; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 800; flex: none; background: var(--navy); }
.wlink__tag--pdf { background: #c0392b; }
.wlink__tag--doc { background: #1e7d4f; }
.wlink__body { flex: 1; min-width: 0; }
.wlink__t { font-size: 14px; font-weight: 700; color: var(--navy); }
.wlink__m { font-size: 12px; color: #9b958a; }
.wlink__arw { font-size: 18px; color: var(--gold); font-weight: 700; flex: none; }
.emerg { background: var(--navy); color: #fff; }
.emerg .label { color: var(--gold); }
.emerg__body { font-size: 14px; line-height: 1.55; margin-top: 10px; color: #dfe4ef; }
.emerg__body strong { color: #fff; font-weight: 800; }
.emerg__phone { font-size: 21px; font-weight: 800; margin-top: 12px; }
.emerg__note { font-size: 12px; color: #9fb0d6; margin-top: 2px; }

/* ---------------------------------------------------------------- referral */
.referral { margin-top: 34px; text-align: center; padding: 0 20px; }
.referral__hr { height: 1px; background: #e3ddd2; }
.referral__hr--top { margin-bottom: 28px; }
.referral__hr--bottom { margin-top: 28px; }
.referral__kicker { font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--gold); font-weight: 800; }
.referral__text { font-size: 17px; color: #3a4259; line-height: 1.6; max-width: 760px; margin: 14px auto 0; }
.referral__text strong { color: var(--navy); font-weight: 800; }
.referral__btn { display: inline-block; margin-top: 20px; border: 1.5px solid var(--gold); color: var(--navy); padding: 12px 28px; border-radius: 99px; font-size: 13px; font-weight: 800; text-decoration: none; }
.referral__btn:hover { background: var(--gold); color: var(--navy); }

/* ------------------------------------------------------------------ footer */
.ftr { background: var(--navy-deep); padding: 26px 40px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 14px; margin-top: 30px; }
.ftr__left { display: flex; align-items: center; gap: 14px; }
.ftr__logo { height: 30px; width: auto; opacity: .92; }
.ftr__copy { font-size: 12px; color: rgba(255,255,255,.4); }
.ftr__links { display: flex; gap: 26px; font-size: 13px; }
.ftr__links a { color: rgba(255,255,255,.7); }
.ftr__links a:hover { color: var(--gold); }

/* ---------------------------------------------------------- boot + toast */
.boot { display: flex; flex-direction: column; gap: 14px; }
.boot__line, .boot__card { border-radius: 12px; background: linear-gradient(90deg, #eeebe4, #f6f4ef, #eeebe4); background-size: 200% 100%; animation: shimmer 1.3s linear infinite; }
.boot__line { height: 14px; }
.boot__card { height: 190px; }
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

.toast {
  position: fixed; left: 50%; bottom: 22px; z-index: 200; transform: translate(-50%, 160%);
  background: var(--navy); color: #fff; padding: 12px 20px; border-radius: 99px;
  font-size: 13.5px; font-weight: 700; box-shadow: 0 18px 46px rgba(13,27,62,.22);
  transition: transform .3s cubic-bezier(.2,.9,.2,1); max-width: calc(100vw - 32px);
}
.toast[data-show="true"] { transform: translate(-50%, 0); }

.err { border: 1px solid var(--line); border-radius: 16px; padding: 26px; background: #fff; }

/* ------------------------------------------------------------------ login (Subsystem 1, 2026-08-08) */
.login-shell { min-height: 100vh; display: flex; flex-direction: column; background: var(--bone); }
.login-hdr { background: var(--navy); padding: 24px 40px; }
.login-hdr__logo { height: 36px; width: auto; }
.login-main { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 20px; }
.login-card { max-width: 420px; width: 100%; }
.login-form { margin-top: 22px; display: flex; flex-direction: column; gap: 10px; }
.login-label { font-size: 12px; font-weight: 700; color: var(--navy); text-transform: uppercase; letter-spacing: .04em; }
.login-input { font-family: var(--font-body); font-size: 15px; padding: 12px 14px; border-radius: 8px; border: 1px solid var(--line); background: #fff; color: var(--navy); }
.login-input:focus { border-color: var(--gold); }
.login-submit { margin-top: 6px; }
.login-error { color: #a83c3c; font-size: 13.5px; margin-top: 14px; line-height: 1.5; }
.login-success { color: var(--navy); font-size: 14.5px; margin-top: 18px; line-height: 1.5; }
.login-ftr { text-align: center; padding: 20px; font-size: 12px; color: #9b958a; }

/* --------------------------------------------- Choose a Home (2026-09-09) */
.home-picker { margin-top: 22px; display: flex; flex-direction: column; gap: 10px; }
.home-picker__item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; text-align: left; padding: 14px 16px; border-radius: 10px;
  border: 1px solid var(--line); background: #fff; cursor: pointer;
  font-family: var(--font-body);
}
.home-picker__item:hover { border-color: var(--gold); background: var(--line-soft); }
.home-picker__item:disabled { opacity: .6; cursor: default; }
.home-picker__job { font-size: 14.5px; font-weight: 700; color: var(--navy); }
.home-picker__stage { font-size: 12px; color: #9b958a; }

/* =========================================================================
   Responsive fallbacks. Desktop rendering above is the approved comp and is
   unchanged; these only prevent horizontal overflow on smaller screens.
   ========================================================================= */

/* --------------------------------------------------- My Build Details interaction */
/* Mirrors the Dashboard's restrained motion language: informative content gets
   gentle entrance/highlight states, while lift/translation is reserved for
   elements that are actually clickable (plan documents and linked gallery
   thumbnails). Scoped to .build-page so no other portal view changes. */
.build-page > .split {
  animation: build-section-in .48s ease backwards;
  animation-delay: .08s;
}
@keyframes build-section-in {
  from { opacity: 0; transform: translateY(8px); }
}

/* Timeline stages arrive in sequence, but remain visually read-only. */
.build-page .tl {
  animation: build-timeline-in .42s ease backwards;
}
.build-page .tl:nth-child(2) { animation-delay: .04s; }
.build-page .tl:nth-child(3) { animation-delay: .08s; }
.build-page .tl:nth-child(4) { animation-delay: .12s; }
.build-page .tl:nth-child(5) { animation-delay: .16s; }
.build-page .tl:nth-child(6) { animation-delay: .20s; }
.build-page .tl:nth-child(n+7) { animation-delay: .24s; }
@keyframes build-timeline-in {
  from { opacity: 0; transform: translateY(6px); }
}
.build-page .tl__body {
  border-radius: 7px;
  padding-left: 7px;
  margin-left: -7px;
  transition: background-color .18s ease;
}
.build-page .tl:hover .tl__body { background: rgba(190,149,92,.06); }

/* Specifications and selections are informational: a reading highlight only. */
.build-page .kv--specs .kv__row {
  border-radius: 7px;
  padding-left: 7px;
  padding-right: 7px;
  margin-left: -7px;
  margin-right: -7px;
  transition: background-color .18s ease;
}
.build-page .kv--specs .kv__row:hover { background: rgba(190,149,92,.06); }

/* Real document links get the stronger interaction cue. */
.build-page .plan {
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease, background-color .18s ease;
}
.build-page .plan__tag,
.build-page .plan__arw { transition: transform .18s ease; }
.build-page .plan:hover,
.build-page .plan:focus-visible {
  transform: translateY(-2px);
  border-color: rgba(190,149,92,.45);
  background: #fff;
  box-shadow: 0 8px 18px rgba(13,27,62,.09);
}
.build-page .plan:hover .plan__tag,
.build-page .plan:focus-visible .plan__tag { transform: translateY(-1px); }
.build-page .plan:hover .plan__arw,
.build-page .plan:focus-visible .plan__arw { transform: translate(2px,-2px); }

/* Gallery motion only when the slot contains a real link. Placeholder tiles
   stay still so they never imply an action that does not exist. */
.build-page .slot--gal:has(a.slot__link) {
  transition: transform .22s ease, box-shadow .22s ease;
}
.build-page .slot--gal:has(a.slot__link) .slot__img {
  transition: transform .24s ease;
}
.build-page .slot--gal:has(a.slot__link):hover,
.build-page .slot--gal:has(a.slot__link):focus-within {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px rgba(13,27,62,.12);
}
.build-page .slot--gal:has(a.slot__link):hover .slot__img,
.build-page .slot--gal:has(a.slot__link):focus-within .slot__img { transform: scale(1.025); }

@media (prefers-reduced-motion: reduce) {
  .build-page *,
  .build-page *::before,
  .build-page *::after {
    animation-duration: .01ms !important;
    animation-delay: 0ms !important;
    transition-duration: .01ms !important;
  }
}

@media (max-width: 1040px) {
  .grid3 { grid-template-columns: 1fr 1fr; }
  .grid-docs { grid-template-columns: 1fr 1fr; }
  .split, .split--warranty, .split--contract { grid-template-columns: 1fr; }
  .grid-gal { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
  .hdr { position: static; grid-template-columns: 1fr; gap: 14px; padding: 16px 20px; }
  .hdr__center { text-align: left; }
  .hdr__right { justify-content: flex-start; }
  .hdr__right .hdr__logo, .hdr__right .hdr__rule { display: none; }
  .nav { top: 0; padding: 0 20px; gap: 22px; overflow-x: auto; flex-wrap: nowrap; justify-content: flex-start; }
  .main { padding: 24px 20px 10px; }
  .card--hero { padding: 22px; }
  .grid3, .grid2, .grid-docs, .grid-gal { grid-template-columns: 1fr; }
  .phases { flex-wrap: wrap; }
  .phase { flex: 1 1 44%; }
  .phases--pre { grid-template-columns: repeat(3, 1fr); }
  .outstanding { padding: 20px; }
  .fin { padding: 24px; }
  .cmcard { padding: 22px; }
  /* Added 2026-09-08 (item #3): stack naturally on mobile, photo stays
     thumbnail-sized (not enlarged) and centered above the text. */
  .wm-card { flex-direction: column; align-items: flex-start; text-align: left; padding: 20px; }
  .ftr { padding: 22px 20px; }
  .page-title, .page-title--lg { font-size: 32px; }
}

@media print {
  .nav, .toast { display: none; }
  .hdr { position: static; }
}


/* Live milestone-grouped construction gallery */
.grid-gal--groups { align-items: stretch; }
.gallery-group {
  appearance: none;
  border: 1px solid var(--line, #e4e7eb);
  border-radius: 14px;
  padding: 0;
  overflow: hidden;
  background: #fff;
  color: inherit;
  text-align: left;
  cursor: pointer;
  min-width: 0;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.gallery-group__image-wrap { display: block; width: 100%; height: 140px; overflow: hidden; background: #f4f5f6; }
.gallery-group__image { width: 100%; height: 100%; display: block; object-fit: cover; transition: transform .24s ease; }
.gallery-group__meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 11px 13px 12px; }
.gallery-group__meta strong { font-size: 13px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gallery-group__meta span { flex: 0 0 auto; font-size: 11px; font-weight: 800; color: var(--muted, #6b7280); text-transform: uppercase; letter-spacing: .04em; }
.gallery-group:focus-visible { outline: 3px solid rgba(190, 30, 45, .24); outline-offset: 3px; }

/* Restored Blueprints preview card (added 2026-08-26) — sits first in the
   Photo Gallery grid, reusing the Dashboard's existing .bp/.bp__a/.bp__b
   composition and .gallery-group__meta rules completely as-is for layout
   (no changes to either rule set); this only fits that composition into a
   .gallery-group-shaped slot and turns off the pointer-cursor affordance
   the base .gallery-group class assumes for its button variant, since this
   card's own two placards (not the card as a whole) are the real links.
   The hover lift/shadow (.gallery-group:hover, below) is explicitly
   cancelled for this modifier too — see that block. */
.gallery-group--blueprints { padding: 14px 13px 12px; cursor: default; }
.gallery-group--blueprints .gallery-group__meta { padding: 12px 0 0; }

/* Same tilt-apart hover Dashboard's Blueprint/Plot Plan images use at rest
   (see the .dashboard-page-scoped rules above), added here 2026-08-26 so
   this page's copy of that composition feels identical. UNLIKE the
   Dashboard's version, this is bound to each image's OWN :hover, not
   `.bp:hover` — hovering one placard tilts only that one, never both at
   once, since Consumer Plans and Plot Plan are two independent links. */
.build-page .bp__a,
.build-page .bp__b,
.build-page .slot__img {
  transition: transform .24s ease, box-shadow .24s ease;
}
.build-page .bp__a:has(a.slot__link):hover { transform: translate(-3px, -3px) rotate(-.5deg); }
.build-page .bp__b:has(a.slot__link):hover { transform: translate(3px, 3px) rotate(.5deg); }
.build-page .slot--filled:hover .slot__img { transform: scale(1.025); }

body.has-build-gallery-lightbox { overflow: hidden; }
.build-gallery-lightbox { position: fixed; inset: 0; z-index: 1200; display: grid; place-items: center; padding: 24px; }
.build-gallery-lightbox[hidden] { display: none; }
.build-gallery-lightbox__backdrop { position: absolute; inset: 0; background: rgba(10, 12, 16, .88); }
.build-gallery-lightbox__panel {
  position: relative;
  z-index: 1;
  width: min(1180px, 96vw);
  max-height: 94vh;
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 56px;
  align-items: center;
  gap: 12px;
}
.build-gallery-lightbox__figure { margin: 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 10px; }

/* Zoom/pan viewport (added 2026-08-25) — wraps the image so a CSS
   transform can scale/translate it without disturbing the figure's own
   layout. max-height carries the same budget the image itself used to
   carry directly, minus room for the caption + new toolbar below it. */
.build-gallery-lightbox__viewport {
  position: relative;
  width: 100%;
  max-height: calc(94vh - 158px);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.build-gallery-lightbox__viewport.is-zoomed { cursor: grab; touch-action: none; }
.build-gallery-lightbox__viewport.is-dragging { cursor: grabbing; }
.build-gallery-lightbox__image {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 10px;
  background: #111;
  transform-origin: center center;
  transition: transform .15s ease;
  user-select: none;
  -webkit-user-drag: none;
}
.build-gallery-lightbox__viewport.is-dragging .build-gallery-lightbox__image { transition: none; }

/* Caption (revised 2026-08-25) — "Framing — Photo 4 of 7" as one headline
   (title, now includes the position count that used to be its own third
   column), the existing caption/date line beneath it, centered under the
   image. [hidden] when there's nothing to show — never an empty line. */
.build-gallery-lightbox__caption { width: 100%; padding-top: 0; color: #fff; display: flex; flex-direction: column; gap: 3px; align-items: center; text-align: center; font-size: 13px; }
.build-gallery-lightbox__caption strong { font-size: 14px; font-weight: 800; }
.build-gallery-lightbox__caption span { color: rgba(255,255,255,.72); }
.build-gallery-lightbox__caption[hidden] { display: none; }

/* Toolbar (added 2026-08-25) — Zoom Out/percent/Zoom In/Fit/Fullscreen/
   Download/Print. Sits below the caption, in normal flow, so it never
   overlaps the photo. Same frosted-glass-on-dark language as the existing
   Close/Prev/Next controls, with a warm gold hover/focus accent (this
   portal's established navy/gold language) rather than plain white. */
.build-gallery-lightbox__toolbar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 4px;
  padding: 5px 8px;
  border-radius: 999px;
  background: rgba(255,255,255,.08);
}
.build-gallery-lightbox__tool {
  border: 0;
  background: transparent;
  color: rgba(255,255,255,.85);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  padding: 7px 10px;
  border-radius: 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  transition: background-color .18s ease, color .18s ease, transform .12s ease;
}
.build-gallery-lightbox__tool:hover,
.build-gallery-lightbox__tool:focus-visible {
  background: rgba(190,149,92,.24);
  color: #fff;
}
.build-gallery-lightbox__tool:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.build-gallery-lightbox__tool:active { transform: scale(.94); }
.build-gallery-lightbox__tool[disabled] { opacity: .35; cursor: default; pointer-events: none; }
.build-gallery-lightbox__tool[aria-pressed="true"] { background: rgba(190,149,92,.34); color: #fff; }
.build-gallery-lightbox__zoom-level { font-size: 12px; font-weight: 700; color: rgba(255,255,255,.75); min-width: 40px; text-align: center; }
.build-gallery-lightbox__tool-sep { width: 1px; height: 18px; background: rgba(255,255,255,.18); margin: 0 2px; }

.build-gallery-lightbox__close,
.build-gallery-lightbox__nav {
  border: 0;
  background: rgba(255,255,255,.12);
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.build-gallery-lightbox__close { position: absolute; right: 0; top: -48px; width: 42px; height: 42px; border-radius: 50%; font-size: 30px; line-height: 1; }
.build-gallery-lightbox__nav { width: 52px; height: 72px; border-radius: 12px; font-size: 44px; }
.build-gallery-lightbox__nav:hover,
.build-gallery-lightbox__close:hover { background: rgba(255,255,255,.22); }

/* Fullscreen (added 2026-08-25) — when the panel itself is the fullscreen
   element, let it use the real viewport instead of the usual 94vh/96vw
   card sizing; the backdrop dimming is irrelevant at that point (nothing
   else is visible) but stays harmless underneath. */
.build-gallery-lightbox__panel:fullscreen {
  width: 100vw;
  max-height: 100vh;
  background: #0a0c10;
  padding: 24px;
  border-radius: 0;
}
.build-gallery-lightbox__panel:fullscreen .build-gallery-lightbox__viewport { max-height: calc(100vh - 190px); }

/* Baseline placeholder card — shown when a milestone group has no photos yet. */
.gallery-group--empty { cursor: default; background: #fafafa; }
.gallery-group__image-wrap--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(45deg, #f4f5f6, #f4f5f6 10px, #eef0f1 10px, #eef0f1 20px);
}
.gallery-group__empty-note {
  font-style: italic;
  color: var(--muted, #6b7280) !important;
  text-transform: none !important;
  font-weight: 600 !important;
  letter-spacing: 0 !important;
}

@media (hover: hover) and (pointer: fine) {
  .gallery-group:hover { transform: translateY(-3px); box-shadow: 0 12px 26px rgba(0,0,0,.10); }
  .gallery-group:hover .gallery-group__image { transform: scale(1.035); }
  .gallery-group--empty:hover { transform: none; box-shadow: none; }
  .gallery-group--blueprints:hover { transform: none; box-shadow: none; }
}
@media (max-width: 640px) {
  .build-gallery-lightbox { padding: 14px; }
  .build-gallery-lightbox__panel { width: 100%; grid-template-columns: 42px minmax(0,1fr) 42px; gap: 6px; }
  .build-gallery-lightbox__nav { width: 40px; height: 58px; font-size: 34px; }
  .build-gallery-lightbox__viewport { max-height: calc(94vh - 176px); }
  .build-gallery-lightbox__toolbar { gap: 2px; padding: 4px 6px; }
  .build-gallery-lightbox__tool { padding: 6px 8px; font-size: 12px; min-width: 30px; }
  .build-gallery-lightbox__zoom-level { min-width: 34px; font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .gallery-group, .gallery-group__image { transition: none !important; }
  .build-gallery-lightbox__image,
  .build-gallery-lightbox__tool { transition: none !important; }
}


/* Documents — download-only interaction + restrained motion */
.documents-page .docrow--alive,
.documents-page .ctile--alive {
  animation: doc-enter .34s ease both;
  animation-delay: calc(var(--doc-i, 0) * 42ms);
}
.documents-page .docrow--alive {
  transition: background-color .18s ease, padding-left .18s ease, box-shadow .18s ease;
}
.documents-page .btn-dl--alive {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  transition: transform .18s ease, background-color .18s ease, box-shadow .18s ease;
}
.documents-page .btn-dl__arrow,
.documents-page .ctile__arrow {
  display: inline-block;
  transition: transform .18s ease;
}
.documents-page .ctile--download {
  text-decoration: none;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.documents-page .ctile--date {
  cursor: default;
}
.documents-page .ctile__action--download {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--navy);
}
.documents-page .btn-dl--alive:focus-visible,
.documents-page .ctile--download:focus-visible {
  outline: 3px solid rgba(194, 155, 81, .28);
  outline-offset: 3px;
}

@keyframes doc-enter {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (hover: hover) and (pointer: fine) {
  .documents-page .docrow--alive:hover {
    background: #fbfaf7;
    padding-left: 24px;
    box-shadow: inset 3px 0 0 var(--gold);
  }
  .documents-page .docrow--alive:hover .btn-dl--alive {
    transform: translateY(-1px);
    box-shadow: 0 6px 14px rgba(17, 31, 54, .14);
  }
  .documents-page .btn-dl--alive:hover .btn-dl__arrow,
  .documents-page .ctile--download:hover .ctile__arrow {
    transform: translateY(2px);
  }
  .documents-page .ctile--download:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 26px rgba(17, 31, 54, .10);
    border-color: #d8d0c1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .documents-page .docrow--alive,
  .documents-page .ctile--alive {
    animation: none !important;
  }
  .documents-page .docrow--alive,
  .documents-page .btn-dl--alive,
  .documents-page .btn-dl__arrow,
  .documents-page .ctile--download,
  .documents-page .ctile__arrow {
    transition: none !important;
  }
}

/* --------------------------------------------------- key contacts interaction */
/* Added 2026-08-26 — interaction-polish only, reusing patterns already
   established elsewhere in the portal rather than inventing new ones.
   .cmcard/.cmcard__*, .contact/.contact__* (from ui.js's contactCard()),
   and .grid2 are used EXCLUSIVELY by this page (confirmed: no other view
   renders them), so these selectors are inherently scoped to Key Contacts
   without needing a wrapper class — no markup change was required for
   this pass. Layout, dimensions, spacing, typography, colors, and content
   are all untouched below; every rule here only adds transition/hover/
   focus/entrance treatment on top of what already exists. */

/* Card-level hover lift — same numeric treatment as .financials-page's
   .ctile and .build-page's .plan (translateY + navy-tinted shadow + gold
   border tint, .18s ease), applied here to the individual team cards per
   explicit instruction that hovering a contact card should lift like
   everywhere else. :focus-within mirrors :hover the same way
   .slot--gal:has(a.slot__link) does on My Build Details, so keyboard-
   focusing the email/phone link inside gets the same feedback as a mouse
   hover. */
.contact {
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.contact:hover,
.contact:focus-within {
  transform: translateY(-3px);
  box-shadow: 0 10px 22px rgba(13,27,62,.12);
  border-color: rgba(190,149,92,.55);
}
.contact__line a { transition: color .18s ease; }

/* Construction Manager card: the card itself is not a link (it's a fixed
   featured section, not one of several equal choices), so it does not
   lift as a whole — same "don't imply an action the container itself
   doesn't perform" posture as .gallery-group--blueprints on My Build
   Details. Its real actions (Message/Call) get the portal's established
   button-hover treatment instead, matching .dashboard-page's
   .link-btn/.btn-expand/.referral__btn exactly (translateY(-2px) + the
   same navy-tinted shadow, .18s ease). The existing mailto/tel meta links
   just gain a smooth color transition for the hover state they already
   have. */
.cmcard__actions a {
  transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease, color .18s ease;
}
.cmcard__actions a:hover,
.cmcard__actions a:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 7px 16px rgba(13,27,62,.12);
}
.cmcard__meta a { transition: color .18s ease; }

/* Focus visibility — same gold focus-visible outline used on
   .financials-page .ctile and elsewhere, extended here since .contact and
   .cmcard__actions a are both real interactive/focusable elements. */
.contact:focus-within {
  outline: 3px solid rgba(190,149,92,.24);
  outline-offset: 3px;
}
.cmcard__actions a:focus-visible {
  outline: 3px solid rgba(190,149,92,.6);
  outline-offset: 2px;
}

/* Entrance animation — reusing the exact same pattern already established
   on Dashboard (.dashboard-page > .card--hero/.outstanding/.grid3/
   .referral) and My Build Details (.build-page's own equivalent): a brief
   fade+rise on the page's top-level sections, staggered slightly, backwards
   fill so it doesn't flash unstyled content first. Same duration/easing/
   distance (.48s ease, translateY(8px)) as those two — not a new style. */
.cmcard,
.grid2 {
  animation: contacts-section-in .48s ease backwards;
}
.grid2 { animation-delay: .08s; }
@keyframes contacts-section-in {
  from { opacity: 0; transform: translateY(8px); }
}

@media (prefers-reduced-motion: reduce) {
  .contact,
  .contact__line a,
  .cmcard__actions a,
  .cmcard__meta a {
    transition: none !important;
  }
  .cmcard,
  .grid2 {
    animation: none !important;
  }
}


/* My Build Details — persistent Plan Documents availability states. Missing
   expected plan documents remain visible, but only real downloadable files
   retain the existing interactive .plan behavior. */
.build-page .plan--status {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  column-gap: 12px;
  row-gap: 4px;
  align-items: center;
  cursor: default;
  transition: none;
}

.build-page .plan--status .plan__tag {
  grid-column: 1;
  grid-row: 1 / span 2;
}

.build-page .plan--status .plan__body {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;
}

.build-page .plan--status .plan__status {
  grid-column: 2;
  grid-row: 2;
  justify-self: start;
  font-size: 12px;
  font-weight: 700;
  color: #9b958a;
}
.build-page .plan__status {
  flex: none;
  font-size: 12px;
  font-weight: 700;
  color: #9b958a;
}
.build-page .plan--status:hover,
.build-page .plan--status:focus-visible {
  transform: none;
  box-shadow: none;
  border-color: #eee9e0;
  outline: none;
}
.build-page .plan--status:hover .plan__tag,
.build-page .plan--status:focus-visible .plan__tag {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .build-page .plan--status {
    transition: none !important;
  }
}
