/* ============================================================================
   /realestaterell - Omnikom x Rise Real Estate Solutions list builder.
   Scoped .p-realestaterell.

   The builder is a DASHBOARD: a step rail on the left, one panel at a time on the
   right, and a generated review step before submit. Long forms lose people, and
   150 inputs on one screen is the worst version of that; one group at a time with
   a visible map of what is left is the version people finish.

   Progressive enhancement: panel hiding and the panel nav are scoped behind
   :where(.js). With JS off every panel is on the page, the rail is a list of jump
   links, and the form is one long native POST - nothing is unreachable.

   The field grammar mirrors /consultation's .pc-*. ENGINEERING-RULES §3 says a
   block copied between page files should be promoted to components.css; that
   promotion is recorded as a follow-up rather than done here. Do not copy it a
   third time - promote it.
   ============================================================================ */

/* ============================================================================
   HERO - "overprint". Scoped .p-realestaterell.

   MEASURED THIS SESSION (headless chromium canvas alpha + relative-luminance
   scan of the real files; the source brief was wrong and these numbers replace
   every coordinate in it):

   rise-hero-portrait.webp  1100x835, opaque bbox x177..977 / y8..834.
     -> 16.09% dead TRANSPARENT margin left, 11.09% right, 0.96% top, 0 bottom.
     -> opaque width 801/1100 = 72.818%. CANCELLATION so the opaque figure
        exactly fills its frame:  width:137.329%; margin-inline-start:-22.098%.
        Without it he floats behind an invisible gutter and never reaches an edge.
     -> hair / crown, y0..18%: mean relative luminance 0.008..0.06
        = 1.15:1..2.2:1 on --ink-0. THE CROWN IS INVISIBLE and cannot be
        rescued by any committed token (--ink-20 1.02:1, --ink-30 1.05:1,
        --royal 1.57:1 against the hair - all computed). Therefore NOTHING in
        this composition may depend on the top of his head reading, and no
        "type descends over his head" move is available: the occluder is not
        visible, so the interleave would not read.
     -> shirt / shoulder, y28..70%: mean luminance 0.36 rising to 0.76.
        --paper-full on it is 1.2:1..1.8:1 and --lime is 1.0:1..1.3:1.
        NOTHING light may cross it. It is, however, the best OCCLUDER in the
        photograph, and that is the only job it is given here.
     -> bottom row y=834 is 790/1100 px opaque at 4.3:1 on --ink-0, and the
        clasped hands sit at y700..760. The cut is a hard, visible amputation.
        It is NOT faded (a gradient over khaki at 0.2..0.3 is a grey haze, not
        a dissolve) - it LANDS on the ledger rule, by grid construction.
        FALLBACK LEVER, only if the render gate rejects the landing:
        mask-image:linear-gradient(to bottom,#000 90%,rgba(0,0,0,0) 100%)
        on .rre-hero__cut. Last 10% only. Never more - more eats the hands.

   SHELL FACT: tools/lib/shell.mjs sets OFFER_ROUTE='realestaterell'
   and assemble-pages.mjs suppresses the bar on its own route, so the generated
   index.html has NO .has-offer: --offer-h is 0px and --nav-clear is 76px HERE,
   unlike every other page. The fold budget below uses 76.
   ========================================================================== */

/* Top padding. base.css owns this at (0,5,1) via
   `main > *:first-child:not(.s-hero) > .section:first-child:not(.s-hero)`, so a
   `.p-realestaterell .rre-hero` retune at (0,2,0) is DEAD CODE. This
   selector is (0,5,1) - it ties and wins on order, because the page sheet loads
   after base.css. It can match no other page. */
main > .p-realestaterell:first-child > .section.rre-hero:first-child{
  padding-block-start:calc(var(--nav-clear) + var(--s-7));
}
@media (max-width:639px){
  main > .p-realestaterell:first-child > .section.rre-hero:first-child{
    padding-block-start:calc(var(--nav-clear) + var(--s-5));
  }
}

.p-realestaterell .rre-hero{
  --rre-display:clamp(2.5rem,6vw,5.5rem);   /* 40px floor / 88px cap (craft ceiling ~6rem) */
  /* clip, not hidden: clip is the one value that legally pairs with
     overflow-y:visible, so it creates no scroll container and nothing above the
     top padding is cropped. It absorbs the figure's transparent overscan and the
     datum's lime bleed. KEEP IT ON THE HERO ONLY - an overflow ancestor would
     kill position:sticky on #rre-builder's step rail. */
  overflow-x:clip;
}
/* structural guard: no decorative layer can ever eat a pointer event */
.p-realestaterell .rre-hero [aria-hidden="true"]{ pointer-events:none }

/* ---- masthead ---- */
.p-realestaterell .rre-hero__masthead{
  position:relative; z-index:2;            /* the invisible crown rises behind this rule;
                                              without the z the img would paint over the
                                              hairline and simply delete 594px of it */
  display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between;
  gap:var(--s-3) var(--s-5);
  padding-bottom:var(--s-4);
  border-bottom:1px solid var(--ink-40);
  margin-bottom:clamp(28px,3.4vw,48px);
}
.p-realestaterell .rre-hero__masthead .c-crumb{ justify-content:flex-start; margin-bottom:0 }

/* ---- the field: ONE stacking context, z by ROLE ---- */
.p-realestaterell .rre-hero__field{ position:relative; isolation:isolate }

/* ---- the type wall ----
   .rre-hero__title MUST stay position:static / z-index:auto / no opacity /
   no transform / no filter / no will-change. The moment it becomes a stacking
   context, the three lines flatten onto one plane and the outlined line jumps
   in front of him. That failure is INVISIBLE in a screenshot taken after
   .is-in has been force-stamped - the gate must check z-order, not pixels. */
.p-realestaterell .rre-hero__title{
  margin:0; max-width:none; text-align:left;
  font-size:var(--rre-display); line-height:1.02; letter-spacing:-.035em;
}
.p-realestaterell .rre-l{
  position:relative; display:block;
  padding-bottom:.10em; margin-bottom:-.06em;   /* descenders clear .reveal-mask's overflow */
}
.p-realestaterell .rre-l--front{
  z-index:3;
  text-shadow:0 12px 34px rgba(10,10,10,.72);   /* offset AND soft blur, never a hard offset */
}
.p-realestaterell .rre-l--back{ z-index:1 }

/* ---- deck ---- */
.p-realestaterell .rre-hero__deck{
  position:relative; z-index:3;
  max-width:var(--measure); margin-top:var(--s-5);
}

/* ---- ledger: the sharpest fact and the action stand on one rule, and he
        stands on it too ---- */
.p-realestaterell .rre-hero__ledger{
  position:relative; z-index:3;
  display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:space-between;
  gap:var(--s-5) var(--s-6);
  border-top:1px solid var(--ink-50);
  padding-top:var(--s-5);
  margin-top:clamp(28px,3.4vw,48px);
}
.p-realestaterell .rre-hero__price{ display:grid; justify-items:start; gap:8px }
/* TOKEN CARVE-OUT, recorded not inherited: tokens.css reserves --f-mono for
   "numerals / eyebrows / labels ONLY", but the shipped build already sets this
   numeral in --f-display and it is the page's sharpest fact. Kept as shipped;
   the unit line below is the mono half. Do not "fix" one without the other. */
.p-realestaterell .rre-hero__amount{
  font-family:var(--f-display); font-weight:700;
  font-size:var(--t-numeral); line-height:1; letter-spacing:var(--track-display);
  font-variant-numeric:tabular-nums; color:var(--lime);
}
.p-realestaterell .rre-hero__unit{
  font-size:var(--t-label); line-height:1.4;
  text-transform:uppercase; letter-spacing:var(--track-eyebrow);
  color:var(--paper-muted);
}
.p-realestaterell .rre-hero__act{
  justify-content:flex-start;
  max-width:100%;                 /* the act column can never be pushed under a decor layer */
}
.p-realestaterell .rre-hero__note{
  flex:1 0 100%; margin-inline:0; margin-top:var(--s-4);
  max-width:70ch; text-align:left;
}
/* inline SVG replaces the &rarr; glyph-as-icon while KEEPING the .arw class, so
   base.css's `.btn:hover .arw{transform:translateX(var(--arrow-shift))}` still
   drives it. Worth promoting sitewide; scoped here so this page ships clean. */
.p-realestaterell .rre-hero .arw{ display:inline-flex; align-items:center }
.p-realestaterell .rre-hero .arw svg{ display:block; width:16px; height:12px }

/* ---- the plate: frame, datum, credit, cut-out ---- */
.p-realestaterell .rre-hero__plate{
  position:relative; z-index:2;
  margin-top:clamp(24px,6vw,40px);
  margin-inline:calc(var(--gutter) * -1);   /* phone: edge to edge */
}
/* overflow:clip lives HERE, on the cut only, so the datum (a sibling) can still
   bleed left into the type column and right off the trim edge. */
.p-realestaterell .rre-hero__cut{
  position:relative; z-index:1; overflow:clip; pointer-events:none;
}
/* THE CANCELLATION. 137.329% = 1100/801; -22.098% = 177/801 * 100 / 1.37329.
   Together they put the OPAQUE bbox exactly on the plate's box. Change one and
   you must change the other. */
.p-realestaterell .rre-hero__figure{
  width:137.329%; max-width:none; height:auto;
  margin-inline-start:-22.098%;
}

/* THE SEVERED DATUM - authored in the FIGURE's percentage coordinates, never
   the field's, so the occlusion point cannot drift when type sizes change.
   At top:56% the opaque span measures x274..877 of 1100 = 12.1%..87.4% of the
   frame, and those pixels are shirt at luminance 0.75. So: --ink-60 grey enters
   from the type column (3.4:1, a device not a texture - --ink-50 at 1.74:1 was
   too quiet to read), is swallowed for three quarters of his width, and
   re-emerges --lime (11.7:1) running off the trim edge. The gradient stop sits
   at 46% of this element, which is plate-x 43.8% - deep inside the opaque mass,
   so the hand-off is invisible by construction and a few percent of drift
   cannot expose it. The middle is eaten by the REAL matte, not drawn out. */
.p-realestaterell .rre-hero__datum{
  position:absolute; z-index:0; top:56%; left:-16%; right:-14%; height:1px;
  background:linear-gradient(to right,var(--ink-60) 0 46%,var(--lime) 46% 100%);
}

.p-realestaterell .rre-hero__credit{ display:none }

/* ---- 640..1023: still stacked, but he is no longer a full-bleed slab ---- */
@media (min-width:640px){
  .p-realestaterell .rre-hero__plate{
    width:min(100%,480px);
    margin-inline-start:auto; margin-inline-end:calc(var(--gutter) * -1);
  }
  .p-realestaterell .rre-hero__act{ justify-content:flex-end }
}

/* ---- <1024: PHONE + TABLET, owner-directed -------------------------------
   "put the plate under the deck" and "everything in the hero is centered on
   phone and tablets".
   The DOM order is h1 / deck / ledger / plate because the >=1024 grid needs the
   ledger to be row 3 for the figure to land on its rule. Reordering the MARKUP
   would break that, so the column is reordered with flex order instead and the
   DOM - which is the reading and tab order - is left alone. Placed after the
   640px block on purpose: it has to win the plate's margin-inline-start:auto. */
@media (max-width:1023px){
  .p-realestaterell .rre-hero__field{ display:flex; flex-direction:column }
  .p-realestaterell .rre-hero__title{ order:1; text-align:center }
  .p-realestaterell .rre-hero__deck{
    order:2; text-align:center; margin-inline:auto;
  }
  .p-realestaterell .rre-hero__plate{
    order:3;
    margin-inline-start:auto; margin-inline-end:auto;   /* centred, not right-ranged */
  }
  .p-realestaterell .rre-hero__ledger{
    order:4; justify-content:center; text-align:center;
  }
  .p-realestaterell .rre-hero__price{ justify-items:center; width:100% }
  .p-realestaterell .rre-hero__act{ justify-content:center; width:100% }
  .p-realestaterell .rre-hero__note{ text-align:center; margin-inline:auto }
  .p-realestaterell .rre-hero__masthead{
    text-align:center; justify-items:center; justify-content:center;
  }
  .p-realestaterell .rre-hero__masthead .c-crumb,
  .p-realestaterell .rre-hero__masthead .eyebrow{ justify-content:center }
}

/* ---- phone only: the hero eyebrow ----------------------------------------
   Owner: drop the lime dot and put "property data" on its own line.
   .eyebrow is a shared inline-flex whose ::before draws the dot (base.css:49), so
   the dot is removed rather than hidden - display:none on a flex child would still
   leave the 10px gap behind it. Switching to block is what lets the second line
   break at all; inline-flex would keep it on one run no matter the width. */
@media (max-width:639px){
  .p-realestaterell #rre-hero .eyebrow{ display:block; text-align:center }
  .p-realestaterell #rre-hero .eyebrow::before{ content:none }
  .p-realestaterell #rre-hero .rre-hero__eb-l2{ display:block }
}

/* ---- >=1024: the overlap field ---- */
@media (min-width:1024px){
  .p-realestaterell .rre-hero__field{
    display:grid; grid-template-columns:repeat(12,minmax(0,1fr));
    column-gap:var(--s-5); row-gap:0; align-items:start;
  }
  .p-realestaterell .rre-hero__title { grid-column:1/-1; grid-row:1 }
  .p-realestaterell .rre-hero__deck  { grid-column:1/7;  grid-row:2; align-self:start }
  .p-realestaterell .rre-hero__ledger{ grid-column:1/-1; grid-row:3; margin-top:0 }

  /* The outlined line is the only element allowed below the figure. The indent
     is what makes the crossing real rather than optical: measured at 1440,
     "real estate list your" sets 638px wide, +12% (145px) ends at x783, and his
     opaque shoulder edge across that line's y-band is x~737 - so ~46px, about
     the "r" of "your", is eaten by a shirt at luminance 0.5-0.58. The two solid
     lines set 497px and 564px against a 692-809px clear edge and can never
     touch him: that clearance is a construction guarantee, since the front
     lines stop at grid boundary 7 (6c+5g) while his opaque edge is at
     6c+6g+f*(6c+5g), which exceeds it for every f > 0 at every viewport. */
  .p-realestaterell .rre-l--back{ margin-inline-start:12% }

  /* Fails SAFE: default is solid --paper-full; the transparent fill only ever
     lands inside the guard, so an engine without text-stroke shows a solid
     line, never an invisible third of the h1. */
  @supports (-webkit-text-stroke:2px #000){
    .p-realestaterell .rre-l--back .reveal-inner{
      color:transparent; -webkit-text-stroke:.022em var(--paper-full);
    }
    /* base.css:23 themes ::selection globally (--lime on --lime-ink); without
       this, dragging a selection silently re-FILLS the hollow glyphs. */
    .p-realestaterell .rre-l--back .reveal-inner::selection{
      background:var(--lime); color:var(--lime-ink); -webkit-text-stroke-color:var(--lime-ink);
    }
  }

  /* Spanning rows 1-2 with row-gap:0 is what makes the landing exact: the grid
     sizes those two tracks around the plate, so the plate's bottom edge IS the
     ledger's top border. The amputation becomes a plinth, and no arithmetic is
     involved. The negative margin lifts the (invisible) crown into the masthead
     band so the outlined line meets him at the SHOULDER, where the occluder is
     bright, instead of at the head, where it is not. */
  .p-realestaterell .rre-hero__plate{
    grid-column:7/-1; grid-row:1/span 2;
    align-self:start; justify-self:end;
    width:100%; margin-inline:0;
    margin-top:clamp(-88px,-5.6vw,-40px);
  }

  /* REF-A's rotated micro-type is DROPPED, not restyled. Its own note argued that
     plate-x 0..2% is transparent above y 60% so it could never land on him - true,
     and beside the point: the plate's left edge is the middle of the composition,
     so the line landed on the HEADLINE instead. Observed at 1440 running vertically
     through "list yo". Nothing is lost by removing it - it was aria-hidden, and the
     partner section names him in real text a scroll below. */
}
@media (min-width:1440px){
  .p-realestaterell .rre-hero__title{ letter-spacing:-.04em }  /* tracking floor */
}

/* No .reveal transform is overridden anywhere above, so base.css:117's
   `@media (prefers-reduced-motion:reduce){:where(.js) .reveal{transform:none}}`
   and base.css:126's curtain flattening both still govern this section. If any
   future edit here overrides a .reveal or .reveal-inner transform, it MUST ship
   the paired reduce block with it - a page-scoped override outranks base and
   silently reintroduces motion the owner has switched off.

   DELETE from the current sheet:
     .rre-hero__price{ display:flex; flex-direction:column; align-items:center; ... }
     .rre-hero__portrait{ display:block; margin:var(--s-6) auto 0; width:min(300px,62vw) } */

/* ---- PRICING TABLE ---- */
.p-realestaterell .rre-tiers{ max-width:34rem; margin:var(--s-7) auto 0 }
.p-realestaterell .rre-tiers__table{
  width:100%; border-collapse:collapse; color:var(--text-on-blue);
}
.p-realestaterell .rre-tiers__caption{
  font-size:var(--t-label); text-transform:uppercase;
  letter-spacing:var(--track-eyebrow); color:var(--text-on-blue-muted);
  text-align:left; padding-bottom:var(--s-3);
}
.p-realestaterell .rre-tiers__table th{
  text-align:left; font-family:var(--f-mono); font-size:var(--t-label);
  text-transform:uppercase; letter-spacing:var(--track-eyebrow);
  color:var(--text-on-blue-muted); font-weight:400;
  padding:var(--s-3) 0; border-bottom:1px solid rgba(255,255,255,.22);
}
.p-realestaterell .rre-tiers__table td{
  padding:var(--s-3) 0; font-size:var(--t-body);
  border-bottom:1px solid rgba(255,255,255,.12);
}
.p-realestaterell .rre-tiers__table td:last-child{ text-align:right; font-weight:600 }
.p-realestaterell .rre-tiers__note{
  font-size:var(--t-label); color:var(--text-on-blue-muted);
  margin-top:var(--s-5); margin-bottom:var(--s-7);
}

/* ---- PROGRESS METER: one end-to-end unit, not a bar with a floating caption ---- */
.p-realestaterell .rre-meter{
  max-width:64rem; margin:var(--s-7) auto var(--s-5);
  display:flex; align-items:center; gap:var(--s-4);
  padding:var(--s-3) var(--s-5);
  border:1px solid var(--ink-40); border-radius:var(--r-badge); background:var(--ink-10);
}
.p-realestaterell .rre-meter__track{
  flex:1; height:3px; background:var(--ink-40); border-radius:var(--r-badge); overflow:hidden;
}
/* scaleX, not width: animating width relayouts the meter on every frame of every
   keystroke in the form. The bar is 3px tall inside an overflow:hidden track, so
   scaling cannot visibly distort the pill cap. transform-origin pins it left. */
.p-realestaterell .rre-meter__fill{
  height:100%; width:100%; background:var(--lime); border-radius:var(--r-badge);
  transform:scaleX(0); transform-origin:left center;
  transition:transform var(--dur-smooth) var(--ease-smooth);
}
.p-realestaterell .rre-meter__label{
  flex:none; font-size:var(--t-label); color:var(--paper-muted); white-space:nowrap;
}
/* The UA sheet's [hidden]{display:none} is a lower-specificity rule than the
   display:flex above it, so setting .hidden on the meter did nothing and it survived
   the submit morph, floating above the thank you. Measured: meterVisible stayed true. */
.p-realestaterell .rre-meter[hidden]{ display:none }

/* ---- DASHBOARD SHELL ---- */
.p-realestaterell .rre-builder__wrap{ max-width:64rem }
.p-realestaterell .rre-form{ margin-top:var(--s-5); text-align:left }
.p-realestaterell .rre-dash{ display:grid; grid-template-columns:1fr; gap:var(--s-5) }
/* A grid item's default min-width is auto, NOT 0, so a column sizes itself to its
   content's min-content width and refuses to shrink. The rail is a nowrap flex row
   of 14 steps whose min-content is 1910px, so at 390px the single column blew out
   to 1910px and took the panel, its .rre-grid and every input with it - measured
   dash 350px wide containing a 1910px panel, i.e. the form ran off the screen and
   overflow-x:auto on the rail never got the chance to scroll. min-width:0 lets the
   column be the width it is told and hands the overflow back to the rail. */
.p-realestaterell .rre-dash > *{ min-width:0 }
@media (min-width:1024px){
  .p-realestaterell .rre-dash{ grid-template-columns:230px 1fr; gap:var(--s-6) }
}

/* ---- STEP RAIL ---- */
/* phone/tablet: a horizontal strip that scrolls; desktop: a sticky column */
.p-realestaterell .rre-rail__list{
  display:flex; gap:var(--s-2); overflow-x:auto; padding-bottom:var(--s-2);
  scrollbar-width:none;
  /* the scrollbar is hidden, so the only cue that 14 steps continue past the right
     edge is a fade. Without it the strip reads as a truncated list, not a scroller. */
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent);
  scroll-snap-type:x proximity;
}
.p-realestaterell .rre-rail__li{ scroll-snap-align:start }
.p-realestaterell .rre-rail__list::-webkit-scrollbar{ display:none }
.p-realestaterell .rre-rail__li{ flex:none }
@media (min-width:1024px){
  .p-realestaterell .rre-rail{ position:sticky; top:calc(var(--nav-clear) + 16px) }
  /* the rail becomes a vertical column here and no longer overflows, so the
     right-edge scroll fade must come off or it just clips the labels */
  .p-realestaterell .rre-rail__list{
    flex-direction:column; overflow:visible; gap:2px;
    -webkit-mask-image:none; mask-image:none;
  }
  .p-realestaterell .rre-rail__li{ flex:auto }
}
.p-realestaterell .rre-rail__item{
  display:flex; align-items:center; gap:10px; min-height:44px;
  padding:8px 14px; border-radius:var(--r-badge);
  font-size:var(--t-small); color:var(--paper-muted); text-decoration:none;
  white-space:nowrap;
  border:1px solid transparent;
  transition:color var(--dur-fast) var(--ease-standard),
             background var(--dur-fast) var(--ease-standard);
}
@media (min-width:1024px){
  .p-realestaterell .rre-rail__item{ border-radius:var(--r-input); white-space:normal }
}
.p-realestaterell .rre-rail__item:hover{ color:var(--paper-full); background:var(--ink-20) }
.p-realestaterell .rre-rail__item[aria-current="step"]{
  color:var(--paper-full); background:var(--ink-20); border-color:var(--ink-50);
}
/* Step numbers come from a counter, never from the markup: the two commercial steps are
   hidden until a commercial category is ticked, and hardcoded numbers left visible holes
   (01 02 03 05 ... 09 11). counter-increment is not applied to display:none elements, so
   the counter closes the gap by itself and no-JS - where every step is visible - still
   counts 01..13. The digits are decorative, hence aria-hidden on the spans. */
.p-realestaterell .rre-rail__list{ counter-reset:railstep }
.p-realestaterell .rre-rail__li{ counter-increment:railstep }
.p-realestaterell .rre-rail__li--review{ counter-increment:none }
.p-realestaterell .rre-rail__num::before{ content:counter(railstep,decimal-leading-zero) }
.p-realestaterell .rre-rail__li--review .rre-rail__num::before{ content:"\2713" }
.p-realestaterell .rre-rail__num{ flex:none; font-size:var(--t-label); color:var(--ink-60) }
.p-realestaterell .rre-rail__item[aria-current="step"] .rre-rail__num{ color:var(--lime) }
.p-realestaterell .rre-rail__name{ flex:1; min-width:0 }
/* a filled dot marks a step the visitor has actually answered something in */
.p-realestaterell .rre-rail__tick{
  flex:none; width:7px; height:7px; border-radius:var(--r-badge);
  border:1px solid var(--ink-50); background:transparent;
  transition:background var(--dur-fast) var(--ease-standard);
}
.p-realestaterell .rre-rail__li.is-done .rre-rail__tick{
  background:var(--lime); border-color:var(--lime);
}
.p-realestaterell .rre-rail__li--review .rre-rail__item{ font-weight:600; color:var(--paper) }

/* ---- PANELS ---- */
/* hidden only under .js - no-JS gets every panel stacked and reachable */
:where(.js) .p-realestaterell .rre-panel{ display:none }
:where(.js) .p-realestaterell .rre-panel.is-active{ display:block }
.p-realestaterell .rre-panel{
  border:1px solid var(--ink-40); border-radius:var(--r-card);
  background:var(--ink-10); padding:var(--s-5);
}
@media (min-width:640px){ .p-realestaterell .rre-panel{ padding:var(--s-6) } }
.p-realestaterell .rre-panel + .rre-panel{ margin-top:var(--s-4) }
:where(.js) .p-realestaterell .rre-panel + .rre-panel{ margin-top:0 }
.p-realestaterell .rre-panel__head{ margin-bottom:var(--s-5) }
.p-realestaterell .rre-panel__step{ font-size:var(--t-label); color:var(--lime) }
.p-realestaterell .rre-panel__title{
  font-family:var(--f-display); font-size:var(--t-h3); line-height:var(--lh-h3);
  letter-spacing:var(--track-h3); color:var(--paper-full); margin-top:6px;
}
.p-realestaterell .rre-panel__hint{ font-size:var(--t-label); color:var(--ink-60); margin-top:6px }
.p-realestaterell .rre-panel__nav{
  display:none; gap:var(--s-3); margin-top:var(--s-6);
  padding-top:var(--s-5); border-top:1px solid var(--ink-40);
}
:where(.js) .p-realestaterell .rre-panel__nav{ display:flex }
.p-realestaterell .rre-panel__nav .btn{ flex:1; justify-content:center; min-height:48px }
@media (min-width:640px){ .p-realestaterell .rre-panel__nav .btn{ flex:0 0 auto } }

/* ---- FIELDS ---- */
.p-realestaterell .rre-grid{ display:grid; grid-template-columns:1fr; gap:var(--s-4) }
@media (min-width:640px){ .p-realestaterell .rre-grid{ grid-template-columns:1fr 1fr } }
.p-realestaterell .rre-field{ display:flex; flex-direction:column; gap:6px }
.p-realestaterell .rre-field--full{ grid-column:1 / -1; margin-top:var(--s-4) }
.p-realestaterell .rre-field label{
  font-family:var(--f-mono); font-size:var(--t-label); text-transform:uppercase;
  letter-spacing:var(--track-eyebrow); color:var(--ink-60);
}
.p-realestaterell .rre-field__req{ color:var(--lime) }
.p-realestaterell .rre-field input,
.p-realestaterell .rre-field select,
.p-realestaterell .rre-field textarea{
  width:100%; background:var(--ink-20); color:var(--paper-full);
  border:1px solid var(--ink-40); border-radius:var(--r-input);
  padding:11px 14px; font-family:var(--f-body); font-size:var(--t-body);
  min-height:46px;
  transition:border-color var(--dur-fast) var(--ease-standard);
}
.p-realestaterell .rre-field textarea{ resize:vertical; min-height:96px }
.p-realestaterell .rre-field input:hover,
.p-realestaterell .rre-field select:hover,
.p-realestaterell .rre-field textarea:hover{ border-color:var(--ink-50) }
.p-realestaterell .rre-field input:focus,
.p-realestaterell .rre-field select:focus,
.p-realestaterell .rre-field textarea:focus{ border-color:var(--lime) }
/* error = border colour PLUS the text in .rre-err, never colour alone (a11y floor §8) */
.p-realestaterell .rre-field input[aria-invalid="true"],
.p-realestaterell .rre-field select[aria-invalid="true"]{ border-color:var(--error) }

/* ---- CHECKBOX GRIDS ---- */
.p-realestaterell .rre-checks{
  border:0; padding:0; margin:0;
  /* was 2px row-gap, which suited bare text rows; tiles need real separation */
  display:grid; grid-template-columns:1fr; gap:var(--s-3);
}
@media (min-width:640px){ .p-realestaterell .rre-checks{ grid-template-columns:1fr 1fr } }
@media (min-width:1280px){ .p-realestaterell .rre-checks{ grid-template-columns:1fr 1fr 1fr } }
.p-realestaterell .rre-checks--sub{ margin-top:var(--s-5) }
.p-realestaterell .rre-checks__legend{
  grid-column:1 / -1; font-size:var(--t-label); text-transform:uppercase;
  letter-spacing:var(--track-eyebrow); color:var(--ink-60); padding:0 0 var(--s-2);
}
/* Each choice is a SELECTABLE TILE on the same surface every other control in this
   form uses (--ink-20 fill, --ink-40 hairline, --r-input corner). They previously
   sat as naked OS checkboxes with a text label in a 2px-gap grid, next to inputs
   that are all filled bordered boxes - so they read as debug output rather than as
   part of the form. This borrows the system's own control surface instead of
   inventing a third look for it.
   The native input stays visible and focusable: accent-color already paints it
   brand-correct, and replacing it with a drawn box would buy appearance at the
   cost of the free accessibility semantics. 44px min-height is the tap floor. */
.p-realestaterell .rre-check{ position:relative; display:block; cursor:pointer }
/* The native box is visually hidden but still focusable and still the labelled
   control, so keyboard and screen-reader behaviour is the browser's, not ours.
   An 18px OS checkbox was the whole reason these read as bland: it is the one part
   of the form no design system can style, and it sat next to 52px controls. */
.p-realestaterell .rre-check input{
  position:absolute; opacity:0; width:1px; height:1px; margin:0; pointer-events:none;
}
.p-realestaterell .rre-check > span{
  display:flex; align-items:center; gap:12px; min-height:52px; padding:13px 16px;
  background:var(--ink-20); border:1px solid var(--ink-40); border-radius:var(--r-input);
  font-size:var(--t-note); color:var(--paper);
  transition:border-color var(--dur-fast) var(--ease-standard),
             background var(--dur-fast) var(--ease-standard),
             color var(--dur-fast) var(--ease-standard);
}
/* the drawn indicator: a real 20px mark, not an OS widget */
.p-realestaterell .rre-check > span::before{
  content:""; flex:none; width:20px; height:20px;
  border:1.5px solid var(--ink-50); border-radius:6px; background:var(--ink-0);
  transition:background var(--dur-fast) var(--ease-standard),
             border-color var(--dur-fast) var(--ease-standard);
}
.p-realestaterell .rre-check:hover > span{ border-color:var(--ink-50); color:var(--paper-full) }
.p-realestaterell .rre-check:hover > span::before{ border-color:var(--paper-muted) }
/* Selected reuses the site's loudest existing signal - the lime fill of the primary
   button - rather than inventing a new one. The wash is derived from --lime, so no
   new colour enters the system; the flat --ink-10 before it is the fallback for
   browsers without color-mix. */
.p-realestaterell .rre-check input:checked + span{
  border-color:var(--lime); color:var(--paper-full); font-weight:600;
  background:var(--ink-10);
  background:color-mix(in srgb, var(--lime) 9%, var(--ink-10));
}
.p-realestaterell .rre-check input:checked + span::before{
  border-color:var(--lime); background:var(--lime)
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%230A0A0A' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><path d='M4 10.5l4 4 8-9'/></svg>")
    center / 13px no-repeat;
}
.p-realestaterell .rre-check input:focus-visible + span{
  outline:2px solid var(--lime); outline-offset:2px;
}
.p-realestaterell .rre-check:active > span{ transform:translateY(1px) }
@media (prefers-reduced-motion:reduce){
  .p-realestaterell .rre-check:active > span{ transform:none }
}
.p-realestaterell .rre-check--wide{
  grid-column:1 / -1; margin-top:var(--s-4);
}
/* show() moves focus to the panel heading so a screen reader announces the new
   step. The heading is not interactive, so the ring it inherited read as a bug -
   a lime box around a title nobody had tabbed to. Suppressed only for the
   programmatic case; a real keyboard user still gets :focus-visible everywhere. */
.p-realestaterell .rre-panel__title:focus{ outline:none }

/* ---- GEOGRAPHY PICKERS (state / county / city) ----
   These fields used to be free text, so the sheet collected "TX", "Texas" and
   "texas, dallas co." for the same market and could not be grouped or filtered.
   They are now picked from the US Census 2020 vocabulary, and county and city
   cascade from whatever states are chosen.
   The original <input> is NOT removed - it stays in the DOM carrying the same
   comma-joined value under the same name, so the Function allowlist, the sheet
   columns and the review step all keep working unchanged. JS only hides it and
   drives it. If the vocabulary fails to load, the input is shown again and the
   field degrades to exactly what it was before. */
.p-realestaterell .rre-geo{ display:flex; flex-direction:column; gap:var(--s-3) }
.p-realestaterell .rre-geo[hidden]{ display:none }
.p-realestaterell .rre-geo__chips{
  display:flex; flex-wrap:wrap; gap:var(--s-2); list-style:none; margin:0; padding:0;
}
.p-realestaterell .rre-geo__chips:empty{ display:none }
.p-realestaterell .rre-geo__chip{
  display:inline-flex; align-items:center; gap:2px;
  background:var(--ink-10); border:1px solid var(--lime); border-radius:var(--r-badge);
  padding-inline-start:var(--s-3);
  font-size:var(--t-label); color:var(--paper-full);
}
/* the button carries the 44px target; the chip stays visually compact because the
   target is padding around a small glyph, not a big box */
.p-realestaterell .rre-geo__x{
  display:inline-flex; align-items:center; justify-content:center;
  width:44px; height:44px; margin-inline-start:-6px;
  color:var(--paper-muted); background:none; border:0; cursor:pointer;
  transition:color var(--dur-fast) var(--ease-standard);
}
.p-realestaterell .rre-geo__x:hover{ color:var(--paper-full) }
.p-realestaterell .rre-geo__x svg{ width:12px; height:12px; display:block }
.p-realestaterell .rre-geo__empty{
  font-size:var(--t-label); color:var(--warning, var(--paper-muted));
}
/* it is a live region, so it stays in the DOM and collapses instead of unmounting */
.p-realestaterell .rre-geo__empty:empty{ display:none }
.p-realestaterell .rre-note{
  font-size:var(--t-label); color:var(--ink-60); margin-top:var(--s-4); max-width:var(--measure);
}

/* ---- REVIEW STEP ---- */
/* built from live form state on entering the step, so it can never describe
   something different from what actually gets sent */
.p-realestaterell .rre-review{ display:flex; flex-direction:column; margin-bottom:var(--s-6) }
.p-realestaterell .rre-review__row{
  display:grid; grid-template-columns:1fr; gap:2px;
  padding-block:var(--s-3); border-top:1px solid var(--ink-40);
}
@media (min-width:640px){
  .p-realestaterell .rre-review__row{ grid-template-columns:15rem 1fr; gap:var(--s-4) }
}
.p-realestaterell .rre-review__row:last-child{ border-bottom:1px solid var(--ink-40) }
.p-realestaterell .rre-review__k{
  font-family:var(--f-mono); font-size:var(--t-label); text-transform:uppercase;
  letter-spacing:var(--track-eyebrow); color:var(--ink-60);
}
.p-realestaterell .rre-review__v{ font-size:var(--t-note); color:var(--paper); margin:0 }
.p-realestaterell .rre-review__v--empty{ color:var(--ink-60) }
.p-realestaterell .rre-review__edit{
  background:none; border:0; padding:0; margin-top:2px;
  font-family:var(--f-mono); font-size:var(--t-label); color:var(--lime);
  text-decoration:underline; cursor:pointer; text-align:left; justify-self:start;
}
.p-realestaterell .rre-review__empty{
  font-size:var(--t-note); color:var(--ink-60); padding-block:var(--s-4);
}

/* ---- HONEYPOT: off-screen, never display:none (some bots skip hidden inputs) ---- */
.p-realestaterell .rre-hp{
  position:absolute; left:-9999px; width:1px; height:1px; opacity:0; pointer-events:none;
}

/* ---- SUBMIT + STATES ---- */
.p-realestaterell .rre-turnstile{ display:flex; justify-content:center }
.p-realestaterell .rre-turnstile:not(:empty){ margin-top:var(--s-5) }
.p-realestaterell .rre-gate,
.p-realestaterell .rre-err{ text-align:center; margin-inline:auto; max-width:52ch }
.p-realestaterell .rre-err{ color:var(--error); margin-top:var(--s-4) }
.p-realestaterell .rre-gate{ color:var(--ink-60); margin-top:var(--s-4) }
.p-realestaterell .rre-gate a{ color:var(--lime); text-decoration:underline }
.p-realestaterell .rre-submit{
  margin-top:var(--s-6); display:flex; flex-direction:column; align-items:center; gap:var(--s-3);
}
.p-realestaterell .rre-submit__note{
  font-size:var(--t-label); color:var(--ink-60); max-width:var(--measure); text-align:center;
}
/* the submit really is disabled until Turnstile passes; without this it stayed full lime
   with a pointer cursor, so a click that did nothing had no explanation. (base.css has no
   global .btn:disabled - footer.css styles only its own booking button. A shared rule is
   the right fix and is recorded as a follow-up.) */
.p-realestaterell .rre-submit .btn:disabled{ opacity:.55; cursor:not-allowed }

/* ---- NO-JS FALLBACK ----
   Written as html:not(.js) / :where(.js) rather than a bare .js pair on purpose: the submit
   block already carries display:flex, and a zero-specificity :where(.js) override would tie
   with it and be decided by source order. html:not(.js) simply does not match once the head
   stamp lands, so nothing here can shift the JS path. */
html:not(.js) .p-realestaterell .rre-panel--review,
html:not(.js) .p-realestaterell .rre-submit{ display:none }
.p-realestaterell .rre-nojs{
  margin-top:var(--s-6); max-width:var(--measure); margin-inline:auto;
  text-align:center; color:var(--ink-60); font-size:var(--t-label);
}
.p-realestaterell .rre-nojs a{ color:var(--lime); text-decoration:underline }
:where(.js) .p-realestaterell .rre-nojs{ display:none }

/* ---- SHARED COMPONENTS, CONSTRAINED TO THIS PAGE ----
   c-rows and c-foot inherit the full 1320px .wrap while their copy caps at 66ch, so on a
   wide screen the text hugs the left of a very wide band and reads as broken alignment.
   Capping and centring the block fixes the optics without touching the components. */
.p-realestaterell .c-rows{ max-width:56rem; margin-inline:auto; width:100% }
.p-realestaterell .c-foot{ text-align:center }
.p-realestaterell .c-callout{ margin-inline:auto }

/* ---- PARTNER: "inside the name" -----------------------------------------
   The partner's name is set once and split across three depth layers with the
   cut-out wedged between them: "rise real estate" passes BEHIND his head in
   hollow lime and re-emerges on both sides of it, the page's own black floor
   rises IN FRONT of his torso, and "solutions." prints solid on that floor.
   Two real occlusions, opposite sides of one person. No masks, no clip-path -
   the alpha matte does all the cutting.

   MEASURED off /assets/img/rise-partner-portrait.webp (900x1042) by canvas
   alpha/luma scan, not estimated from the bounding box:
     alpha bbox ............ x 0-898, y 10-1041  (the frame IS the figure)
     hair crown ............ 1.0% down; silhouette 10.8% of frame width at 2%
     head, widest .......... 34.1% of frame width at 18% down
     skin (forehead) ....... starts 8.6% down on the centre column
     shoulder ramp ......... 48% wide at 44%, 87.9% at 60%, 98.8% at 80%
     R.I.S.E mark .......... x 61.9-74.4%, y 55.2-65.2% = 12.7% of frame width
   Three consequences drive every number below:
   1. The only dark ground in the frame is the hair (0-8.6%). The hollow line
      therefore crosses THERE, where the head is 24-34% of the frame and the
      line re-emerges on both sides. Below 60% the figure is 88-99% of the
      frame - nothing typographic can pass behind it and still read.
   2. "rise" alone measures 1.86em in Sora. At any legal size (max 64px, under
      the page h1 cap of 72px) it is NARROWER than the head at every figure
      size worth showing, so it cannot overhang him. The name breaks after
      "estate", not after "rise".
   3. The frame's bottom edge cuts the polo hem and both forearms. That crop is
      buried by the floor plane, never trimmed by a hairline. */

/* --fig-w / --fig-h / --rrp-u are declared on the SECTION so the plate, the
   lockup and the credit all do arithmetic against the same figure. */
.p-realestaterell .rre-partner-band{
  /* OWNER OVERRIDE 2026-09-09: "his brand name should be way bigger so it is
     readable behind him". This supersedes the 56px hierarchy ceiling recorded in
     the 640+ block below - the owner wants the wordmark to read as the backdrop.
     The ceilings are NOT taste values: "rise real estate" measures 742px per 100px
     of font-size in Sora at this weight and tracking, so the one-line limit is
     avail/7.42. Measured available widths give 47px at 390, 104px at 834 and 163px
     at 1440; every ceiling below sits under its limit with margin, because a wrap
     to two lines would break the derived --fig-push and grid-template-rows math. */
  --rrp-u:clamp(28px,11vw,45px);           /* type unit AND every offset */
  /* was min(82vw,320px). At 390 that made the figure 320px against a 316px wordmark,
     so the name sat entirely behind his head with nothing emerging either side and
     the whole depth effect was invisible on a phone. 68vw leaves ~25px of the line
     clear on each side, which is what makes it read as behind him rather than hidden. */
  --fig-w:min(58vw,228px);
  --fig-h:calc(var(--fig-w) * 1042 / 900); /* the TRUE alpha ratio, not a guess */
  --lead-size:max(var(--t-note), calc(var(--rrp-u) * .34));
  --back-gap:calc(var(--rrp-u) * 1.10);
  /* the figure is pushed DOWN until its 2% mark meets the top of the hollow
     line content box. Every term is a real metric, not a tuned constant:
     lead box (1.25 line-height) + the gap - the negative half-leading the .9
     line-height creates against Soras 1.25em content area - 2% of the figure.
     Because it is derived, the crossing self-corrects at every viewport. */
  --fig-push:calc(var(--lead-size) * 1.25 + var(--back-gap)
                  - var(--rrp-u) * .175 - var(--fig-h) * .02);
  --cut:.74;      /* floor edge as a fraction of --fig-h. 8.8% clear of the
                     mark, which ends at 65.2% - the floor never touches it. */
  --front:.805;   /* the solid line, 6.5% of the figure below the floor edge */
  /* the floor runs to the section's own bottom edge and meets #rre-legal with no
     seam. NEIGHBOUR-DEPENDENT: #rre-legal is .section--black (verified in
     main.html). If that neighbour is ever repainted this becomes a value step. */
  padding-bottom:0;
}

.p-realestaterell .rre-partner{
  position:relative;
  isolation:isolate;        /* owns the stacking context for the z:-1 line */
  overflow-x:clip;          /* the hard no-horizontal-scroll guarantee;
                               overflow-y stays visible (clip allows that pairing) */
  margin-block-start:var(--s-6);
  padding-block-end:clamp(40px,6vw,72px);
}

/* the floor: full-bleed with no vw math. .section has no inline padding, so an
   absolutely positioned child of a full-width stage IS the viewport width and
   cannot produce the scrollbar overflow that 100vw does. */
.p-realestaterell .rre-partner__plate{
  position:absolute; left:0; right:0; bottom:0;
  top:calc(var(--fig-push) + var(--fig-h) * var(--cut));
  background:var(--ink-0);
  z-index:2; pointer-events:none;
}

.p-realestaterell .rre-partner__lock{
  position:relative;        /* containing block for the abs spans. z-index MUST
                               stay auto, or the hollow line is trapped here. */
  display:grid; grid-template-columns:minmax(0,1fr);
  /* row 1 is sized to the COMPOSITION, not to the figure: the buried tail
     (26% of the image) overflows the row behind the opaque floor instead of
     reserving 100-160px of dead black under it. No negative margins. */
  grid-template-rows:calc(var(--fig-push) + var(--fig-h) * var(--front)
                          + var(--rrp-u) * 1.15) auto;
  row-gap:clamp(28px,4vw,44px);
}

/* ---- the h2: ONE element, three depth layers -----------------------------
   DO NOT give .rre-partner__name or .rre-partner__lock any of:
     z-index (other than auto) - transform / translate / rotate / scale -
     opacity below 1 - filter - backdrop-filter - perspective - clip-path -
     mask / mask-image - mix-blend-mode - isolation - will-change of any of
     those - contain:layout|paint|strict|content - content-visibility:auto -
     container-type - view-transition-name - position:fixed|sticky -
     or an opaque background.
   Each one creates a stacking context (or paints over it) and traps the
   z-index:-1 line behind the figure. The failure is SILENT: half the heading
   simply disappears, with no error anywhere. */
.p-realestaterell .rre-partner__name{
  grid-area:1/1; align-self:start; margin:0; text-align:center;
  font-family:var(--f-display); color:var(--paper-full);
  letter-spacing:var(--track-h2);
}
.p-realestaterell .rre-partner__name span{ display:block }

.p-realestaterell .rre-partner__lead{
  font-size:var(--lead-size);
  line-height:1.25; font-weight:600; letter-spacing:var(--track-h3);
  color:var(--paper);
}

/* layer -1: crosses the hair, re-emerges on both sides of the head */
.p-realestaterell .rre-partner__back{
  position:relative; z-index:-1;
  margin-block-start:var(--back-gap);
  font-size:var(--rrp-u); line-height:.9; font-weight:650;
  color:var(--lime);        /* fallback: SOLID. never invisible. */
}
@supports (-webkit-text-stroke:1px currentColor){
  .p-realestaterell .rre-partner__back{
    color:transparent; -webkit-text-fill-color:transparent;
    -webkit-text-stroke:max(1.25px, .022em) var(--lime);
  }
}
/* theme the surface we did not draw: selected hollow type goes solid, not hollow */
.p-realestaterell .rre-partner__back::selection{
  background:var(--lime); color:var(--lime-ink); -webkit-text-fill-color:var(--lime-ink);
}

/* layer 3: prints on the floor plane, 8.5% of the figure below its edge */
.p-realestaterell .rre-partner__front{
  position:absolute; left:0; right:0; z-index:3;
  top:calc(var(--fig-push) + var(--fig-h) * var(--front));
  font-size:var(--rrp-u); line-height:.9; font-weight:650;
  color:var(--paper-full);
}

/* layer 1: the cut-out. width and height come from the SAME contract the
   landings use, so every overlap is a fixed fraction of the image. */
.p-realestaterell .rre-partner__figure{
  grid-area:1/1; justify-self:center; align-self:start; z-index:1;
  width:var(--fig-w); height:var(--fig-h);
  margin-block-start:var(--fig-push);
}

/* position:relative is what MAKES the z-index below work. It was z-index:3 on a
   STATIC element, which the browser ignores entirely - so under 1280, where this is
   not absolutely positioned, the opaque .rre-partner__plate (absolute, z-index:2,
   --ink-0) simply painted over it and the credit vanished. Measured: static with
   z-index 3 at 390/640/834/1024/1180, and the credit's top inside the plate's band
   at every one of them. Above 1280 it was already absolute, which is why the bug
   only ever showed on the smaller viewports. */
.p-realestaterell .rre-partner__credit{
  position:relative; z-index:3; margin:0; display:grid; gap:2px;
}
.p-realestaterell .rre-partner__credit dd{ margin-inline-start:0 }
/* MEASURED contrast, not assumed. --ink-60 (#6B6B6B) is 3.72:1 on --ink-0 and
   3.36:1 on --ink-20 - it FAILS AA at 12px on both. The page uses --ink-60 for
   dense meta elsewhere; DO NOT make this block "consistent" with it.
   --lime here is 11.69:1 on the floor (below 1280) and 10.58:1 on the panel
   (1280+, where the credit hangs beside the mark). */
.p-realestaterell .rre-partner__role{
  font-size:var(--t-label); text-transform:uppercase;
  letter-spacing:var(--track-eyebrow); color:var(--lime);
}
.p-realestaterell .rre-partner__who{
  font-family:var(--f-display); font-size:var(--t-h4); font-weight:600;
  color:var(--paper-full); letter-spacing:var(--track-h3);
}
.p-realestaterell .rre-partner__org{
  font-size:var(--t-small); color:var(--paper);
}

.p-realestaterell .rre-partner__base{
  position:relative; z-index:3;
  display:grid; row-gap:var(--s-5);
}
/* --measure (66ch), not base.css .deck (60ch): the brief floors prose at 65ch. */
.p-realestaterell .rre-partner__deck{ max-width:var(--measure) }
/* the foot is one long mono line. In a 1fr/auto pair it takes its max-content
   width and starves the deck to one word per line - MEASURED at 834 before it
   was capped. It is capped and allowed to wrap instead.
   text-align:left overrides this page rule .p-realestaterell .c-foot
   {text-align:center} - same specificity, later in the file. Centred meta under
   a left-ranged deck reads as broken alignment. */
.p-realestaterell .rre-partner__foot{ max-width:36ch; text-align:left; margin-top:0 }

/* ---- the one authored moment: he rises out of the floor -------------------
   Same .is-in flip, same tokens, no new --i step: the lockup travels 14px and
   the figure travels 14px + 5% of its own height, so on entry he climbs past
   the hollow line and settles in front of the plane. The plane hides the whole
   run-up, so nothing is ever seen below the crop. */
:where(.js) .p-realestaterell .rre-partner .rre-partner__figure{
  transform:translateY(calc(var(--fig-h) * .05));
  transition:transform var(--dur-slow) var(--ease-out);
  transition-delay:calc(var(--i,0) * 70ms);
}
.p-realestaterell .rre-partner.is-in .rre-partner__figure{ transform:none }
/* MUST match the specificity of the pre-state above and come after it: a
   page-scoped (0,3,0) pre-state silently beats base.css's (0,1,0) reduce-motion
   override, so the committed contract has to be restated here. */
@media (prefers-reduced-motion:reduce){
  :where(.js) .p-realestaterell .rre-partner .rre-partner__figure{ transform:none }
}

/* ---- 640+ : the type and the figure step up together -------------------- */
@media (min-width:640px){
  .p-realestaterell .rre-partner-band{
    /* Was clamp(36px,5.75vw,56px) under a "stay below the 64px h1" rule. The owner
       overrode that: this wordmark is the backdrop of the section, not a competing
       heading, and at 56px it read as a caption behind a 640px figure.
       132px ceiling is set by the one-line limit, not by taste - at 1440 the string
       renders 980px inside a 1212px wrap, so it flanks the 640px figure by ~170px a
       side and stays on one line. */
    --rrp-u:clamp(52px,10.5vw,132px);
    --fig-w:clamp(300px,40vw,470px);
  }
}

/* ---- 900+ : deck and foot share one baseline bar ---- */
@media (min-width:900px){
  .p-realestaterell .rre-partner__base{
    grid-template-columns:minmax(0,1fr) minmax(0,36ch);
    column-gap:var(--s-7); align-items:end;
  }
  .p-realestaterell .rre-partner__foot{ text-align:right; justify-self:end }
}

/* ---- 1280+ : the credit hangs beside the photographed mark -------------- */
/* left: is derived from the figure box, so the credit column can never collide
   with him however wide the viewport gets. */
@media (min-width:1280px){
  .p-realestaterell .rre-partner__credit{
    position:absolute; z-index:3;
    top:calc(var(--fig-push) + var(--fig-h) * .52);
    left:calc(50% + var(--fig-w) / 2 + var(--s-5));
    /* was right:0. Between 1280 and 1320 the .wrap has already hit its 1320px cap
       while the viewport is still that narrow, so the lock's right edge IS the
       viewport edge - measured gutterRight:0 at 1280/1300/1320 - and .rre-partner
       carries overflow-x:clip, so the right-aligned credit was shaved against the
       screen. A real gutter keeps it off the edge at every width. */
    right:var(--gutter);
    text-align:right; justify-items:end;
  }
}

/* ---- CONFIRMATION / THE MORPH ----
   On submit the whole builder - header, meter and dashboard - collapses and the
   confirmation grows into the space it leaves, so the section becomes the thank you
   rather than swapping to a different block further down the page.
   Sequence, driven by succeed() in the page JS:
     1. .is-leaving  fades and lifts the builder out            (transform + opacity)
     2. the wrap's height is animated from its old to its new value  (one shot)
     3. .is-arriving reveals the confirmation                   (transform + opacity)
     4. .is-settled  releases the artifacts from behind the card
   Every step is a compositor property except the single height tween, which runs once
   per submission rather than per frame of anything. */
.p-realestaterell .rre-builder__wrap{ position:relative }
.p-realestaterell .rre-morph{
  transition:height var(--dur-smooth) var(--ease-smooth);
  overflow:hidden;
}
.p-realestaterell .rre-leaving{
  opacity:0; transform:translateY(-10px) scale(.985);
  transition:opacity var(--dur-base) var(--ease-standard),
             transform var(--dur-base) var(--ease-standard);
  pointer-events:none;
}

.p-realestaterell .rre-done{
  position:relative; max-width:44rem; margin:var(--s-7) auto 0; text-align:left;
}
.p-realestaterell .rre-done__title{
  font-family:var(--f-display); font-size:var(--t-h2); line-height:var(--lh-h2);
  letter-spacing:var(--track-h2); color:var(--paper-full); margin-block:var(--s-3);
}
/* succeed() focuses this heading so a screen reader announces the new state. It is not
   a tab stop, so the ring only ever appeared after a programmatic focus and read as a
   lime box drawn around the headline. Same treatment as .rre-panel__title. */
.p-realestaterell .rre-done__title:focus{ outline:none }
.p-realestaterell .rre-done__deck{ max-width:52ch }
.p-realestaterell .rre-done__steps{ margin-block:var(--s-6) }

/* the confirmation's own entrance */
:where(.js) .p-realestaterell .rre-done > *:not(.rre-done__art){
  opacity:0; transform:translateY(12px);
}
:where(.js) .p-realestaterell .rre-done.is-arriving > *:not(.rre-done__art){
  opacity:1; transform:none;
  transition:opacity var(--dur-smooth) var(--ease-out) var(--d,0ms),
             transform var(--dur-smooth) var(--ease-out) var(--d,0ms);
}
.p-realestaterell .rre-done > .eyebrow{ --d:60ms }
.p-realestaterell .rre-done__title{ --d:120ms }
.p-realestaterell .rre-done__deck{ --d:180ms }
.p-realestaterell .rre-done__call{ --d:260ms }
.p-realestaterell .rre-done__steps{ --d:320ms }
.p-realestaterell .rre-done .c-btn-row{ --d:380ms }

/* ---- the phone: the one thing this screen exists to hand over ---- */
.p-realestaterell .rre-done__call{
  position:relative; z-index:1;
  display:flex; flex-direction:column; gap:6px;
  margin-top:var(--s-6); padding:var(--s-5) var(--s-6);
  background:var(--ink-10); border:1px solid var(--lime); border-radius:var(--r-card);
  text-decoration:none; color:var(--paper);
  box-shadow:0 18px 40px -28px rgba(0,0,0,.9);
  transition:background var(--dur-fast) var(--ease-standard),
             transform var(--dur-fast) var(--ease-standard);
}
.p-realestaterell .rre-done__call:hover{ background:var(--ink-20); transform:translateY(-2px) }
.p-realestaterell .rre-done__call:focus-visible{ outline:2px solid var(--lime); outline-offset:3px }
.p-realestaterell .rre-done__call-label{
  font-size:var(--t-label); color:var(--ink-60);
  text-transform:uppercase; letter-spacing:var(--track-eyebrow);
}
.p-realestaterell .rre-done__call-num{
  font-family:var(--f-display); font-size:var(--t-h2); line-height:1.05;
  letter-spacing:var(--track-display); color:var(--lime);
  font-variant-numeric:tabular-nums;
}
.p-realestaterell .rre-done__call-hint{ font-size:var(--t-label); color:var(--paper-muted) }

/* ---- artifacts: they arrive from BEHIND the card, after the morph lands ---- */
.p-realestaterell .rre-done__art{
  position:absolute; inset:50% auto auto 50%;
  width:min(680px,132%); aspect-ratio:1; translate:-50% -50%;
  z-index:0; pointer-events:none; color:var(--lime);
}
.p-realestaterell .rre-done__art svg{ width:100%; height:100%; display:block }
.p-realestaterell .rre-done__ring{
  opacity:0; transform-origin:center; transform:scale(.72);
}
.p-realestaterell .rre-done.is-settled .rre-done__ring{
  animation:rreRing 1100ms var(--ease-out) forwards;
}
.p-realestaterell .rre-done.is-settled .rre-done__ring:nth-of-type(2){ animation-delay:110ms }
.p-realestaterell .rre-done.is-settled .rre-done__ring:nth-of-type(3){ animation-delay:220ms }
@keyframes rreRing{
  0%{ opacity:0; transform:scale(.72) }
  55%{ opacity:.34 }
  100%{ opacity:.14; transform:scale(1) }
}
.p-realestaterell .rre-done__spark{
  position:absolute; left:var(--x); top:var(--y);
  width:6px; height:6px; border-radius:var(--r-badge);
  background:var(--lime); opacity:0; transform:scale(0);
}
.p-realestaterell .rre-done.is-settled .rre-done__spark{
  animation:rreSpark 900ms var(--ease-out) forwards;
}
.p-realestaterell .rre-done.is-settled .rre-done__spark:nth-of-type(2){ animation-delay:140ms }
.p-realestaterell .rre-done.is-settled .rre-done__spark:nth-of-type(3){ animation-delay:260ms }
.p-realestaterell .rre-done.is-settled .rre-done__spark:nth-of-type(4){ animation-delay:380ms }
@keyframes rreSpark{
  0%{ opacity:0; transform:scale(0) }
  60%{ opacity:.9; transform:scale(1.25) }
  100%{ opacity:.5; transform:scale(1) }
}

/* Reduced motion keeps the STATE CHANGE (it carries meaning) and drops the travel:
   no height tween, no slide, no ring/spark growth - things simply are where they land. */
@media (prefers-reduced-motion:reduce){
  .p-realestaterell .rre-morph{ transition:none }
  .p-realestaterell .rre-leaving{ transition:opacity var(--dur-fast) linear; transform:none }
  :where(.js) .p-realestaterell .rre-done > *:not(.rre-done__art){ transform:none }
  :where(.js) .p-realestaterell .rre-done.is-arriving > *:not(.rre-done__art){
    transition:opacity var(--dur-fast) linear;
  }
  .p-realestaterell .rre-done.is-settled .rre-done__ring,
  .p-realestaterell .rre-done.is-settled .rre-done__spark{ animation:none }
  .p-realestaterell .rre-done.is-settled .rre-done__ring{ opacity:.14; transform:scale(1) }
  .p-realestaterell .rre-done.is-settled .rre-done__spark{ opacity:.5; transform:scale(1) }
}

/* ---- MOBILE STICKY CTA ---- */
/* only <=767; .is-hidden is added by the page JS while the builder is on screen so the
   bar never covers the form's own controls */
.p-realestaterell .rre-sticky{ display:none }
@media (max-width:767px){
  /* The bar is position:fixed and body has no bottom padding, so at the very end of
     the page its 56px + inset sat ON TOP of the last block - measured covering the
     partner credit. The page reserves the space it occupies. */
  .p-realestaterell{ padding-bottom:calc(56px + var(--s-4) * 2) }
  .p-realestaterell .rre-sticky{
    position:fixed; left:var(--s-4); right:var(--s-4); bottom:var(--s-4);
    z-index:calc(var(--z-nav) - 1);
    display:flex; align-items:center; justify-content:space-between; gap:var(--s-3);
    padding:10px 10px 10px var(--s-4); min-height:56px;
    background:var(--ink-20); border:1px solid var(--ink-50);
    border-radius:var(--r-badge); text-decoration:none;
    box-shadow:0 10px 30px -12px rgba(0,0,0,.7);
    transition:opacity var(--dur-base) var(--ease-standard),
               transform var(--dur-base) var(--ease-standard);
  }
  .p-realestaterell .rre-sticky.is-hidden{
    opacity:0; transform:translateY(120%); pointer-events:none;
  }
  .p-realestaterell .rre-sticky__text{ font-size:var(--t-label); color:var(--paper-muted) }
  .p-realestaterell .rre-sticky__btn{
    flex:none; background:var(--lime); color:var(--lime-ink);
    font-size:var(--t-small); font-weight:600;
    padding:10px 16px; border-radius:var(--r-btn); min-height:40px;
    display:inline-flex; align-items:center;
  }
}

/* ---- hero entrance: slower than the site default, on purpose ----
   The reveal is replayed by the boot overlay's exit (see playHero in the page JS),
   so this is the first motion a visitor actually sees on the page. At the shared
   --dur-slow it was over before the overlay had finished blurring off. Stretching
   it and widening the per-line stagger is what makes the hero arrive alive rather
   than simply be there. Scoped to #rre-hero so no other section's rhythm moves. */
:where(.js) .p-realestaterell #rre-hero .reveal,
:where(.js) .p-realestaterell #rre-hero .reveal-mask .reveal-inner{
  transition-duration:1150ms;
  transition-timing-function:var(--ease-out);
  transition-delay:calc(var(--i, 0) * 150ms);
}
@media (prefers-reduced-motion:reduce){
  :where(.js) .p-realestaterell #rre-hero .reveal,
  :where(.js) .p-realestaterell #rre-hero .reveal-mask .reveal-inner{
    transition-duration:var(--dur-fast); transition-delay:0ms;
  }
}

/* ---- "who this is for" list ----------------------------------------------
   Scoped to this page; .c-uses is shared and other pages use it at a width that
   suits their copy.
   MEASURED at 1440 before this rule: the list was 1212px wide in two 586px
   columns while the longest item ("commercial real estate professionals") sets
   about 350px. The block's centre already matched the heading's - the problem was
   never the centring, it was that every row carried ~230px of trailing void, so
   the ink sat in two narrow bands with a hole down the middle and off each end.
   Sizing the columns to their content and centring the pair removes the void, and
   the row gap goes up because a list this long needs air more than it needs rows. */
.p-realestaterell .c-uses{
  width:fit-content; max-width:100%; margin-inline:auto;
  justify-content:center;
  gap:var(--s-4) var(--s-8);
}
@media (min-width:768px){
  .p-realestaterell .c-uses{ grid-template-columns:auto auto }
}

/* ---- "why omnikom" dot list ----------------------------------------------
   Same defect as .c-uses above, different cause. MEASURED at 1440: the grid was
   1212px in two 586px columns while .c-dots__item caps itself at 52ch = 492px, so
   each column carried ~94px of dead trailing space and the two text blocks drifted
   apart with a hole down the middle.
   Here the items are sentences, not labels, so the columns are NOT sized to their
   content - that would give ragged, unequal measures. The container is capped to
   what two 52ch columns plus their gap actually occupy, and centred. Row gap goes
   up because every item wraps to two or three lines and 16px was reading as one
   dense block rather than six items. */
.p-realestaterell .c-dots{
  max-width:66rem; margin-inline:auto;
  gap:var(--s-5) var(--s-7);
}

/* ============================================================================
   SINGLE-FORM BUILDER (replaces the 13-panel dashboard)
   One column of filter groups. The brief asked for a property-filtering tool,
   not a wizard, so the structure is carried by grouped fieldsets and a rule
   between them rather than by cards or steps.
   ========================================================================== */
.p-realestaterell .rre-fset{
  border:0; margin:0; padding:var(--s-6) 0 0;
  border-top:1px solid var(--ink-40);
}
.p-realestaterell .rre-fset:first-of-type{ border-top:0; padding-top:0 }
.p-realestaterell .rre-fset + .rre-fset{ margin-top:var(--s-6) }
/* a legend is not a flex/grid item and ignores width in most engines, so it is
   floated out of that role and set as a plain block heading */
.p-realestaterell .rre-fset__h{
  float:none; display:block; width:100%; padding:0; margin-bottom:var(--s-4);
  font-family:var(--f-display); font-size:var(--t-h4); font-weight:600;
  color:var(--paper-full); letter-spacing:var(--track-h3);
}
.p-realestaterell .rre-fset__sub{
  margin:var(--s-5) 0 var(--s-3);
  font-size:var(--t-label); text-transform:uppercase;
  letter-spacing:var(--track-eyebrow); color:var(--ink-60);
}
.p-realestaterell .rre-fset__sub:first-of-type{ margin-top:0 }
.p-realestaterell .rre-grid--pair{ margin-top:var(--s-4) }
.p-realestaterell .rre-checks--one{ margin-top:var(--s-4) }
/* radio groups reuse the checkbox tile; the indicator goes round to say
   "one of these", which is the only signal a tile has for single-select */
.p-realestaterell .rre-check input[type="radio"] + span::before{ border-radius:50% }

.p-realestaterell .rre-how__steps{ max-width:52rem; margin-inline:auto }
.p-realestaterell .rre-how__rate{
  margin-top:var(--s-6); text-align:center; color:var(--lime);
  font-size:var(--t-label); letter-spacing:var(--track-eyebrow); text-transform:uppercase;
}
.p-realestaterell .rre-done__rate{
  margin-top:var(--s-5); color:var(--lime); font-size:var(--t-label);
  letter-spacing:var(--track-eyebrow); text-transform:uppercase;
}

/* ---- the hero portrait, kept in the short hero ----
   The file is 1100x835 with the opaque figure at x177..977 - about 16% dead
   transparent margin left and 11% right, so the image edge is NOT the figure edge.
   137.329% = 1100/801 and -22.098% = 177/801*100/1.37329 cancel that pair and put
   his real silhouette on this element's box. Change one and you must change the
   other. overflow:clip keeps the widened image inside the column. */
.p-realestaterell .rre-hero__cut{
  position:relative; margin:var(--s-7) auto 0;
  width:min(100%, 30rem); overflow:clip; pointer-events:none;
}
.p-realestaterell .rre-hero__figure{
  display:block; width:137.329%; max-width:none; height:auto;
  margin-inline-start:-22.098%;
}
/* the crop is buried, not trimmed: a hairline cut across his forearms reads as an
   amputation, a fade reads as him standing out of the ground the page sits on */
.p-realestaterell .rre-hero__cut::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:26%;
  background:linear-gradient(to bottom, transparent, var(--ink-0));
  pointer-events:none;
}
@media (min-width:900px){
  .p-realestaterell .rre-hero__cut{ width:min(100%, 34rem) }
}


/* ---- PRE SKIP TRACED: the differentiator, stated on the path a buyer walks ----
   Not a badge component and not a card - it borrows the lime the page already uses
   for its one emphatic colour, on the same dark ground, so it reads as a fact the
   page is asserting rather than a sticker applied to it. */
.p-realestaterell .rre-hero__trace{
  margin-top:var(--s-4); max-width:52ch;
  font-size:var(--t-note); line-height:1.5; color:var(--paper);
}
.p-realestaterell .rre-hero__trace b{ color:var(--lime); font-weight:650 }

/* above the submit, where the decision is actually made */
.p-realestaterell .rre-trace-badge{
  display:inline-flex; align-items:center; flex-wrap:wrap;
  justify-content:center; gap:6px;
  margin-bottom:var(--s-4); padding:10px var(--s-5);
  border:1px solid var(--lime); border-radius:var(--r-badge);
  background:var(--ink-10);
  font-size:var(--t-small); color:var(--paper); text-align:center;
}
.p-realestaterell .rre-trace-badge b{ color:var(--lime); font-weight:650 }

/* The rate line sat almost on top of the button row - the buttons read as attached
   to the sentence above them rather than as their own step. The rate is a footnote
   to the phone card, so it stays close to that and the actions get real separation. */
.p-realestaterell .rre-done__rate{ margin-bottom:0 }
.p-realestaterell .rre-done .c-btn-row{ margin-top:var(--s-8) }
/* same crowding above the submit: the reassurance note and the button need daylight */
.p-realestaterell .rre-submit{ gap:var(--s-4) }
