/* portfolio.css — the apex /vacation-rentals rebirth (2026-08-29).
 *
 * Scope: ONLY the new owner/client-facing sections on the portfolio page —
 * the guide book (branch index), the standard, the evidence, the invitation,
 * and the book-routing link in the lens bar. It adds nothing to any other
 * page and overrides nothing in shared.css / browse.css.
 *
 * Depends on shared.css tokens (--gold, --gold-line, --parchment, --sage,
 * --display, --body, --ease-out, --radius-sm). Per callable-css-modular-method
 * every colour and easing here is a token call, never a restated value.
 *
 * Design law applied (knowledge\Design-Language-Elec.md):
 *  - navy is AIR, gold is LINE-WORK. Nothing here is a filled brick; every
 *    grouping is a hairline on air.
 *  - labels are ALL-CAPS, 600, tracked 0.09-0.16em.
 *  - ONE HEARTBEAT: every pulse is 2.6s, no delays, so separately mounted
 *    elements stay phase-synced to the page epoch by construction. The gesture
 *    plays in the first quarter of the beat and RESTS for the rest of it.
 *  - entries land with the back-out overshoot.
 *  - band upper bounds end .98 (the DPR-fraction crack, 2026-08-17).
 */

/* ── TIER 2. the complete portfolio catalogue ────────────────────────────── */
/* Text-first by design: this replaced a 29-card photo grid. Rows are hairlines
   on air, two columns on desktop so 29 entries stay scannable without a wall of
   scrolling, one column from the tablet band down. No thumbnails in this pass -
   see build_tier2.py for why, and it is one change to add them. */

.cat-section { padding: 3.6rem 4vw 4.5rem; }
.cat-inner   { max-width: 1080px; margin: 0 auto; }

.cat-list {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 3rem;
}

.cat-link {
  display: block;
  position: relative;
  padding: 1.05rem 0 1.15rem;
  color: inherit;
}
/* Hairline above each row, drawn as a pseudo-element so adjacent rows can never
   double their borders into a 2px seam (design law: no doubled adjacent bars). */
.cat-link::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background-color: var(--gold-line);
  opacity: 0.5;
}
.cat-link::after {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 0; height: 1px;
  background-color: var(--gold);
  transition: width 0.5s var(--ease-out);
}
.cat-link:hover::after, .cat-link:focus-visible::after { width: 100%; }
.cat-link:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }

.cat-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.9rem;
  margin-bottom: 0.2rem;
}
.cat-name {
  font-family: var(--display);
  font-size: 1.16rem;
  line-height: 1.28;
  color: var(--parchment);
}
.cat-link:hover .cat-name { color: var(--highlight); }

.cat-rate {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--parchment);
  white-space: nowrap;
}
.cat-star { color: var(--gold); margin-right: 0.18rem; }
.cat-rc   { color: var(--sage); font-weight: 400; margin-left: 0.2rem; }

.cat-street {
  display: block;
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold);
  opacity: 0.85;
  margin-bottom: 0.3rem;
}
.cat-facts {
  display: block;
  font-size: 0.84rem;
  color: var(--sage);
  margin-bottom: 0.42rem;
}
.cat-facts strong { color: var(--parchment); font-weight: 600; }

.cat-amen { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.cat-tag {
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--sage);
  border: 1px solid var(--gold-line);
  border-radius: 999px;
  padding: 0.16rem 0.55rem;
}
.cat-link:hover .cat-tag { color: var(--parchment); border-color: var(--gold); }

.cat-foot {
  font-family: var(--display);
  font-style: italic;
  font-size: 1rem;
  color: var(--sage);
  text-align: center;
  margin: 0;
}
.cat-foot a {
  color: var(--gold);
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--gold-line);
}
.cat-foot a:hover { color: var(--parchment); border-bottom-color: var(--parchment); }

@media (max-width: 1024.98px) {
  .cat-section { padding: 3rem 5vw 3.6rem; }
  .cat-list { grid-template-columns: 1fr; }
}
@media (max-width: 767.98px) {
  .cat-section { padding: 2.4rem 6vw 3rem; }
  .cat-name { font-size: 1.08rem; }
}

/* ── shared furniture ────────────────────────────────────────────────────── */

.pf-section { padding: 4.5rem 4vw; }
.pf-inner   { max-width: 1080px; margin: 0 auto; }
.pf-inner-narrow { max-width: 760px; margin: 0 auto; }

.pf-eyebrow {
  font-family: var(--body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 0.7rem;
}

.pf-h2 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.75rem, 1.2rem + 1.6vw, 2.5rem);
  line-height: 1.18;
  color: var(--parchment);
  margin: 0 0 0.9rem;
}

.pf-lede {
  font-size: 1.02rem;
  line-height: 1.72;
  color: var(--sage);
  margin: 0 0 2.4rem;
  max-width: 62ch;
}

/* The one fading hairline used as a section lid. Longhands, not a shorthand:
   a var() inside a border shorthand becomes a pending-substitution value that
   can out-rank a more specific longhand rule (VERIFIED-METHODS, 2026-08-15). */
.pf-rule {
  height: 1px;
  border: 0;
  margin: 0 0 2.6rem;
  background-image: linear-gradient(90deg, transparent, var(--gold), transparent);
}

/* ── the route to book, in the lens bar ──────────────────────────────────── */

.pf-datelink {
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--sage);
  white-space: nowrap;
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: transparent;
  transition: color 0.22s var(--ease-out), border-bottom-color 0.22s var(--ease-out);
}
.pf-datelink strong { color: var(--gold); font-weight: 600; }
.pf-datelink:hover { color: var(--parchment); border-bottom-color: var(--gold-line); }
.pf-datelink:hover strong { color: var(--parchment); }
.pf-datelink:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* ── the count node, on a bar that is NOT .has-dates ─────────────────────── */
/* browse.js writes two spans into #filterCount — .fc-main ("29 homes") and
   .fc-low ("as low as $74/night"). The engine's .has-dates grid puts them on
   separate lines; this bar is a single row, so they ran together as
   "29 homesas low as $74/night". Restored to the recorded count grammar with
   a gold middot. Scoped :not(.has-dates) so the engine's bar is untouched. */
.filter-bar:not(.has-dates) .fc-low::before {
  content: "\00B7";
  color: var(--gold);
  margin-left: 0.45rem;
  margin-right: 0.45rem;
}

/* ── I. the guide book — the branch index ────────────────────────────────── */

.pf-branches {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 3.2rem;
}

.pf-branch > a {
  display: grid;
  grid-template-columns: 2.6rem 1fr;
  column-gap: 1rem;
  align-items: baseline;
  padding: 1.15rem 0 1.2rem;
  position: relative;
  color: inherit;
}

/* The hairline is a pseudo-element at top:0 of each row, never a border on a
   neighbour — no doubled adjacent bars, no seams (design law §3). It draws
   ACROSS on approach: that is the page's "ability", revealed by moving. */
.pf-branch > a::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background-color: var(--gold-line);
  opacity: 0.55;
}
.pf-branch > a::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 1px;
  background-color: var(--gold);
  transition: width 0.55s var(--ease-out);
}
.pf-branch > a:hover::after,
.pf-branch > a:focus-visible::after { width: 100%; }
.pf-branch > a:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }

.pf-num {
  font-family: var(--display);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--gold);
  opacity: 0.7;
  text-align: right;
  transition: opacity 0.35s var(--ease-out), color 0.35s var(--ease-out);
}
.pf-branch > a:hover .pf-num { opacity: 1; color: var(--highlight); }

.pf-branch-t {
  display: block;
  font-family: var(--display);
  font-size: 1.32rem;
  line-height: 1.25;
  color: var(--parchment);
  margin-bottom: 0.28rem;
}
.pf-branch-d {
  display: block;
  grid-column: 2;
  font-size: 0.88rem;
  line-height: 1.6;
  color: var(--sage);
}
.pf-branch > a:hover .pf-branch-d { color: var(--parchment); }

/* ── II. the standard — the steps ────────────────────────────────────────── */

.pf-steps { list-style: none; margin: 0; padding: 0; }

.pf-step {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  column-gap: 1.6rem;
  padding: 1.6rem 0 1.75rem;
  position: relative;
}
.pf-step::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background-image: linear-gradient(90deg, var(--gold-line), transparent 72%);
}

.pf-step-n {
  font-family: var(--display);
  font-size: 1.85rem;
  line-height: 1;
  color: var(--gold);
  opacity: 0.55;
}
.pf-step-h {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.36rem;
  line-height: 1.28;
  color: var(--parchment);
  margin: 0 0 0.45rem;
}
.pf-step p {
  margin: 0;
  font-size: 0.98rem;
  line-height: 1.7;
  color: var(--sage);
}
.pf-step p a {
  color: var(--gold);
  border-bottom-width: 1px;
  border-bottom-style: solid;
  border-bottom-color: var(--gold-line);
}
.pf-step p a:hover { color: var(--parchment); border-bottom-color: var(--parchment); }

/* -- the standard, as one-line pops (homepage) --------------------------- */
/* The full six write-ups live on /vacation-rentals' ancestor and on each
   service page; on the root each step is a single statement. Same numbered
   hairline rows as the long form, minus the paragraph, so the two read as the
   same component at two densities rather than as two components. */
.pf-step-pop { padding: 1.05rem 0 1.15rem; align-items: baseline; }
.pf-step-pop .pf-step-n { font-size: 1.4rem; }
.pf-step-pop .pf-step-h {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.24rem;
  line-height: 1.35;
  color: var(--parchment);
  margin: 0;
}
@media (max-width: 767.98px) {
  .pf-step-pop .pf-step-h { font-size: 1.08rem; }
  .pf-step-pop .pf-step-n { font-size: 1.2rem; }
}

/* ── III. the evidence — by the numbers ──────────────────────────────────── */

.pf-figures {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 3.2rem 3rem;
}
.pf-figure { padding-top: 1.1rem; position: relative; }
.pf-figure::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 2.2rem;
  height: 1px;
  background-color: var(--gold);
}
.pf-fig-n {
  display: block;
  font-family: var(--display);
  font-size: clamp(2.1rem, 1.5rem + 1.9vw, 2.9rem);
  line-height: 1.05;
  color: var(--parchment);
  margin-bottom: 0.35rem;
  /* One heartbeat: 2.6s, no delay, gesture in the first quarter then rest. */
  animation: pf-ember 2.6s var(--ease-out) infinite;
}
.pf-fig-l {
  display: block;
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--sage);
}

@keyframes pf-ember {
  0%   { text-shadow: 0 0 0 rgba(201,169,110,0); }
  10%  { text-shadow: 0 0 18px rgba(201,169,110,0.30); }
  25%  { text-shadow: 0 0 0 rgba(201,169,110,0); }
  100% { text-shadow: 0 0 0 rgba(201,169,110,0); }
}

/* -- the portfolio band (homepage), compressed to a strip ---------------- */
/* Elec 2026-08-29: "compress the band to a strip". It arrived at 813px desktop
   / 717px phone because it is the /vacation-rentals PAGE hero reused, and
   .page-hero carries padding-top: calc(14rem + 82px) - 14rem of air plus the
   fixed-nav offset, both of which only make sense when the hero is the first
   thing on a page. Mid-page that offset is dead space, and a second band that
   tall competes with the index hero above it.
   Same treatment the homepage hero already got in the thinning pass: ALL
   content kept, the fixed height replaced by padding that carries the
   breathing room. Compound selector because .page-hero (0,1,0) would otherwise
   win on order within shared.css. */
.page-hero.portfolio-band {
  padding-top: clamp(3.4rem, 7svh, 5rem);
  padding-bottom: clamp(3.6rem, 7.5svh, 5.4rem);
}
@media (max-width: 767.98px) {
  .page-hero.portfolio-band {
    padding-top: clamp(2.6rem, 6svh, 3.6rem);
    padding-bottom: clamp(2.8rem, 6.5svh, 3.8rem);
  }
}

/* ── the record strip (homepage, replaced the guest/owner fork) ──────────── */
/* Deliberately quiet: an eyebrow, the figures, one route out - and NO h2. The
   hero above it is the page's voice ("unbeatable", his word) and a second
   headline immediately under it would compete. Tighter vertical padding than
   .pf-section because this is a strip, not a chapter. */
.pf-strip { padding-top: 4.4rem; padding-bottom: 4.8rem; }
.pf-strip .pf-eyebrow { margin-bottom: 2.1rem; }

.pf-strip-foot { margin: 3.1rem 0 0; }
.pf-strip-foot a {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  transition: gap 0.25s var(--ease-out), color 0.25s var(--ease-out);
}
.pf-strip-foot a:hover { gap: 1.2rem; color: var(--parchment); }
.pf-strip-foot a:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }

@media (max-width: 767.98px) {
  .pf-strip { padding-top: 3.2rem; padding-bottom: 3.5rem; }
  /* TWO ACROSS on the phone (Elec 2026-08-29). Six figures stacked one per row
     ran 837px - a full screen of numbers before the homes, against a brief that
     asks for pops and a fast landing. The numerals are short, so two columns
     halve it without shrinking any type.
     ⚠ It wins on SPECIFICITY, not order: the generic phone rule that forces
     .pf-figures to one column sits LATER in this file (still inside the same
     767.98 block), so order would lose. .pf-strip .pf-figures is (0,2,0) against
     (0,1,0). Verified with getComputedStyle rather than assumed - a rule you
     wrote is a hypothesis until the computed value agrees. */
  .pf-strip .pf-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.2rem 1.4rem; }
  .pf-strip .pf-fig-l { font-size: 0.78rem; line-height: 1.5; }
}

/* ── IV. the invitation ──────────────────────────────────────────────────── */

.pf-invite { text-align: center; padding: 4.5rem 4vw 5rem; }
.pf-invite .pf-lede { margin-left: auto; margin-right: auto; }
.pf-invite-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  justify-content: center;
  margin-top: 0.4rem;
}
.pf-btn {
  display: inline-block;
  padding: 0.85rem 1.9rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sage);
  border: 1px solid var(--gold-line);
  border-radius: 999px;
  transition: color 0.22s var(--ease-out), border-color 0.22s var(--ease-out),
              background-color 0.22s var(--ease-out), letter-spacing 0.22s var(--ease-out);
}
.pf-btn:hover { color: var(--parchment); border-color: var(--gold); letter-spacing: 0.16em; }
.pf-btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.pf-btn-primary { color: var(--parchment); border-color: var(--gold); background-color: var(--gold-dim); }

/* ── entries land with the back-out overshoot ────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
  .pf-rise {
    animation: pf-rise 0.72s cubic-bezier(0.34, 1.42, 0.42, 1) both;
  }
}
@keyframes pf-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .pf-fig-n { animation: none; }
  .pf-branch > a::after { transition: none; }
}

/* ── bands. Upper bounds end .98 — never N / N+1 (2026-08-17). ───────────── */

/* panel 1025-1279.98 + tablet 768-1024.98: figures drop to two across; the
   branch index keeps its two columns while the row still has the width. */
@media (max-width: 1279.98px) {
  .pf-figures { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1024.98px) {
  .pf-section { padding: 3.6rem 5vw; }
  .pf-branches { column-gap: 2.2rem; }
  .pf-branch-t { font-size: 1.22rem; }
}

/* phone <= 767.98: one column everywhere; the guide book becomes a single
   run of hairlined rows, which is what it is on paper anyway. */
@media (max-width: 767.98px) {
  /* The route-to-book link is nowrap by design (a phrase, not a wrap point), so
     at phone width it pushed the lens bar 18px past the viewport. The lead-in
     goes and the verb stays - one line, no horizontal scroll, nothing truncated
     mid-thought. The count + link then take their own row under the chips. */
  .pf-dl-lead { display: none; }
  .filter-bar:not(.has-dates) .filter-right {
    margin-left: 0;
    width: 100%;
    justify-content: space-between;
    gap: 0.5rem;
  }
  .pf-section { padding: 3rem 6vw; }
  .pf-branches { grid-template-columns: 1fr; }
  .pf-figures  { grid-template-columns: 1fr; gap: 1.9rem; }
  .pf-branch > a { grid-template-columns: 2rem 1fr; column-gap: 0.8rem; padding: 1rem 0 1.05rem; }
  .pf-step { grid-template-columns: 3.2rem 1fr; column-gap: 1rem; }
  .pf-step-n { font-size: 1.5rem; }
  .pf-invite { padding: 3rem 6vw 3.6rem; }
  .pf-btn { padding: 0.8rem 1.5rem; }
}
