/* The Estate at Sweetwater Creek — one self-contained stylesheet.
   Generated by build.py from the design export. Brand tokens only, no bare hex
   outside tokens/colors.css. */

/* ===== tokens/colors.css ===== */
/* Brand colors — the only place a raw hex may appear */
:root{
  /* THE FIVE PALETTE SLOTS ARE NO LONGER DECLARED HERE — THEY COME FROM THE CM.
     2026-09-09. Craig: "now remap the v2 pages to pull from the CM." Estate Template.html
     runs all-cm-apply-pipeline.html BEFORE it links this file, so any --color1..5 declared
     here would win on source order and the CM could never reach the page. Dropping them is
     what actually completes the remap; nothing else does.
       --color1 Olive #7B6E46 · --color2 Taupe #8A8178 · --color3 Charcoal #242021
       --color4 Sage  #6D775F · --color5 Cream    #EFE7DE        (ID Colors 19427)
     THE SLOT NUMBERS MOVED, AND THAT IS THE WHOLE HAZARD. This file used to hold the same
     five colors in a different order (1 Charcoal, 2 Olive, 3 Sage, 4 Taupe); the CM follows
     Craig's convention instead - 1 primary, 2 secondary, 3 the neutral dark. All 176 use
     sites - estate.css, estate-review-nav.html, photo-edit.css and five /v2 pages - were
     rewritten in the SAME pass (1->3, 2->1, 3->4, 4->2) by
     00_resources/ai-config/scripts/swc-reslot-palette.mjs, so the rendered result is
     unchanged and only the source of the values moved. Never rewrite one slot by hand, and
     never rewrite one half without the other.
     A FALLBACK COPY LIVES IN "Estate Template.html", ahead of the pipeline, so a failed CM
     lookup lands on these measured values instead of blanking the page - var() with a
     declared-but-EMPTY custom property does NOT use its fallback, so an emitter that returns
     nothing is the dangerous case, not a missing one.
     To change a color: edit ID Colors. Not here, and not the fallback. */
  /* 2026-10-14, Craig: "all colors should be SST dynamic via the ID CMs per site!" These four were the last hex
     palette values here. Each now reads the CM token the pipeline already emits with the same value (measured on
     /the-estate): --attention = #C2A15C exactly, --color3 = #242021 exactly, --color5xl = #f4eee8 against the old
     #F5EFE8 (1/255 per channel). Edit ID Colors / ID Styles, never these lines. */
  --colorGoldBase: var(--attention); /* Antique Gold — interaction highlight only, never type */

  /* Surfaces + type color */
  --PageBgColor: var(--color5xl);   /* Warm Ivory — default page background */
  --FontColor:   var(--color3);
  --reverse1:    var(--color5xl);   /* text/icons sitting ON a dark or color block */

  /* Gold derivations — variants read the BASE so an override can't feed back */
  --colorGold:     var(--colorGoldBase);
  --colorGoldSoft: color-mix(in srgb, var(--colorGoldBase) 70%, var(--PageBgColor));
  --colorGoldDeep: color-mix(in srgb, var(--colorGoldBase) 78%, var(--color3));

  /* AA-safe derivations. --color1 and --color2 are too light to carry 12–14px
     text on ivory or cream, so small text derives darker versions. */
  --text-muted:      color-mix(in srgb, var(--color2) 55%, var(--color3));  /* ~6:1 on ivory */
  --text-accent:     color-mix(in srgb, var(--color1) 82%, var(--color3));  /* ~5.4:1 on ivory */
  --text-muted-rev:  color-mix(in srgb, var(--reverse1) 78%, var(--color3)); /* ~9:1 on charcoal */

  /* Buttons */
  --PrimaryButtonColor:        var(--color3);
  /* Derived from the CM palette, Craig 2026-10-14 ("Derive from CM colors, tiny shift"): was #4A3F35, now
     74,66,49 (max 3.7/255 off). */
  --PrimaryButtonHoverColor:   color-mix(in srgb, var(--color1) 44%, var(--color3));   /* charcoal warmed toward olive */
  --SecondaryButtonColor:      transparent;
  --SecondaryButtonHoverColor: var(--color2);
  --DisabledColor:             color-mix(in srgb, var(--color1) 16%, var(--color5));   /* was #DCD2C6; 220,212,198 (max 1.6/255 off) */
}

/* ===== tokens/typography.css ===== */
/* Typography tokens.
   Bryant + Parlare are licensed Adobe Fonts, served by kit qzp4fkc (imported
   from styles.css). Only these weights exist: bryant-web 300/400/700, parlare 400.
   No italics are licensed — emphasise with weight, letterspacing or color. */
:root{
  --font1Family: "bryant-web", system-ui, -apple-system, sans-serif;      /* display + labels */
  --font2Family: "parlare", cursive;                                      /* script accent    */
  --font3Family: "Avenir Next", "Avenir", "Nunito Sans", sans-serif;      /* body             */

  --H1Font:    var(--font1Family);
  --ButtonFont: var(--font1Family);
  --LabelFont:  var(--font1Family);   /* caps labels, nav, eyebrows, stat labels */
  --BodyFont:   var(--font3Family);
}

/* ===== tokens/spacing.css ===== */
/* Spacing scale — 8px base. Section padding must always come from this scale;
   two sections of the same weight get the same padding. */
:root{
  --sp-xxs: 8px;
  --sp-xs:  16px;
  --sp-sm:  24px;
  --sp-md:  40px;
  --sp-lg:  64px;
  --sp-xl:  96px;
  --sp-xxl: 128px;
}

/* ===== tokens/chrome.css ===== */
/* Brand chrome — square corners, one hairline weight, no shadows anywhere. */
:root{
  --RadiusBrand: 0px;
  --BorderBrandColor: color-mix(in srgb, var(--color3) 15%, transparent); /* was rgba(36,32,33,.15) = --color3 at 15% */
  --BorderBrandWidth: 1px;
  --button-grow: 1.075;   /* hover growth factor; border width divides by this */
}

/* ===== styles/base.css ===== */
/* ============================================================
   2. BASE / TYPE
   ============================================================ */
*,*::before,*::after{ box-sizing:border-box; }
/* Global type scale. Every font-size in this sheet is rem-based and the spacing
   scale is px, so one root bump moves all type together and no layout with it. */
html{ -webkit-text-size-adjust:100%; font-size:102%; }
body{
  margin:0;
  background:var(--PageBgColor);
  color:var(--FontColor);
  font-family:var(--BodyFont);
  font-weight:400;
  font-size:clamp(1.0625rem,1rem + .2vw,1.125rem);
  line-height:1.7;
  -webkit-font-smoothing:antialiased;
}
img{ max-width:100%; display:block; }

h1,.h1{
  font-family:var(--H1Font);
  font-weight:300;
  text-transform:uppercase;
  letter-spacing:.12em;
  font-size:clamp(2.25rem,1.5rem + 2.4vw,4rem);
  line-height:1.15;
  margin:0 0 var(--sp-sm);
}
h2,.h2{
  font-family:var(--font1Family);
  font-weight:700;
  letter-spacing:0;
  font-size:clamp(1.75rem,1.35rem + 1.2vw,2.25rem);
  line-height:1.25;
  margin:0 0 var(--sp-xs);
}
h3,.h3{
  font-family:var(--font1Family);
  font-weight:700;
  font-size:clamp(1.125rem,1rem + .45vw,1.375rem);
  line-height:1.35;
  margin:0 0 var(--sp-xxs);
}
h4,.h4{
  font-family:var(--font1Family);
  font-weight:700;
  font-size:1rem;
  line-height:1.4;
  margin:0 0 var(--sp-xxs);
}
p{ margin:0 0 var(--sp-xs); }
p:last-child{ margin-bottom:0; }

/* Parlare's swash capitals overshoot the line box and its descenders run deep, so at
   display size a glyph reaches outside the element and any ancestor clipping for a
   photo — .hero and .band both carry overflow:hidden — slices it. The production site
   fixes this on .font6/.fontStyled in /fonts/_tlc-fonts.css with a blunt
   `margin:2rem; padding:2rem`. Same remedy here, in em so it tracks the type, and on
   the padding rather than the margin so the block keeps its place in the rhythm:
   the clearance travels WITH the glyph at every clamp size. Raised line-height for the
   same reason — 1.05 was set for a font whose ascenders stay inside their box. */
.script{
  font-family:var(--font2Family);
  font-weight:400;
  font-size:clamp(2.75rem,1.9rem + 3.2vw,5rem);
  line-height:1.22;
  letter-spacing:0;
  text-transform:none;
  margin:0 0 var(--sp-xs);
  padding:.32em .18em .26em;
  display:block;
  color:var(--color1);
  /* One knob. The rule and the keyframe both read it, so they cannot drift — and
     `animation-fill-mode:both` means the keyframe's final value is what actually
     paints, which is why setting `opacity` alone here would have done nothing. */
  --script-op:.21;
  opacity:var(--script-op);
  /* HANGING INDENT on the wrapped lines. Craig, 2026-08-17: "it would be more appealing
     if anything that wraps in them [indented] a little ways ... a touch of personal
     touch." A continuation indent is how handwriting actually behaves on a page, and it
     stops a two-line script reading as two separate stacked phrases.
     padding-left carries the indent, text-indent pulls the FIRST line back out of it —
     so line 1 keeps its original left edge and every line after it steps in. The .18em
     is the swash clearance from the padding shorthand above, which this replaces on the
     left side only. Centred scripts opt out below: a hanging indent on centred text
     just looks like a mistake. */
  --script-indent:1em;
  padding-left:calc(.18em + var(--script-indent));
  text-indent:calc(-1 * var(--script-indent));
  animation:script-in 1.4s cubic-bezier(.22,.61,.36,1) both;
}
.rev .script,.hero-inner .script,.band-inner .script{ color:var(--reverse1); --script-op:.41; }
.band-inner .script{ --script-indent:0em; }
@keyframes script-in{
  from{ opacity:0; transform:translateY(10px); }
  to{ opacity:var(--script-op); transform:none; }
}
@keyframes script-in-rev{
  from{ opacity:0; transform:translateY(10px); }
  to{ opacity:var(--script-op); transform:none; }
}
.rev .script,.hero-inner .script,.band-inner .script{ animation-name:script-in-rev; }
@media (prefers-reduced-motion:reduce){
  .script{ animation:none; }
  .nav-list a,.nav-overlay a,.footer-nav a,.button-ghost{ transition-duration:.01ms; }
}
.script-sm{ font-size:clamp(1.75rem,1.4rem + 1.4vw,2.5rem); padding:.26em .16em .22em; }

/* PAGE-HEADER SCRIPT. Craig, 2026-08-01: "this font looks so much better nowrap.
   Give it a little more space to avoid wrapping... larger font like this but would
   need to be right aligned (actually go beyond the right side of the container by
   50px is preferred) ... until responsive mobile must then adjust to left aligned."
   The bleed is gated at 1420px because the container caps at 1320 + 24px of gutter —
   any narrower and a 50px overhang puts a horizontal scrollbar on the page. */
.page-intro .script{
  white-space:nowrap;
  text-align:right;
  font-size:clamp(3rem,1.8rem + 4.6vw,6rem);
}
/* RIGHT-ANCHORED, and it has to be absolute to actually be right-anchored.
   `width:max-content; margin-left:auto` was the obvious answer and it is WRONG here:
   when a block's width exceeds its containing block the box is over-constrained, and
   CSS resolves auto margins to ZERO — so the script snapped back to the left edge of
   its column and ran off the right of the screen, which is exactly what Craig kept
   seeing. Taking it out of flow and pinning `right` anchors the edge that matters at
   any text length; the overflow then runs LEFT under the heading, which he asked for
   ("it's ok if they slide under the info a little on the left when it's long").
   `right` offsets the .18em of side padding the same way the old margin did, so -50px
   is 50px of visible ink. `bottom:0` keeps the baseline where `align-items-end` had it. */
/* The bleed is deliberate, so the page must not answer it with a horizontal scrollbar.
   `clip` rather than `hidden`: hidden would make the section a scroll container and
   break `position:sticky` anywhere inside it. This line was dropped when the anchoring
   was rewritten and the page scrolled sideways at 1024-1440 until it came back. */
.page-intro{ overflow-x:clip; }
@media (min-width:992px){
  .page-intro .container{ position:relative; }
  .page-intro .script{
    position:absolute;
    right:calc(-50px - .18em);
    bottom:0;
    margin:0;
  }
}
/* Under 992 it returns to the flow, which puts it after the heading and the lead and
   above the first photograph — Craig: "probably left align below the header and
   subheader, pushing the photo down a little ways". */
/* WIDE SCREENS — flush to the WINDOW, not the container. Craig likes the 50px bleed at
   laptop width but wants the script to reach the browser edge once there is real gutter
   to cross. The container is centred and capped at 1320, so the gutter is
   (100vw - 1320) / 2 — i.e. 50vw - 660px. Pinning `right` to the negative of that lands
   the painted glyph exactly on the viewport edge at any width, with the usual .18em
   padding offset so it is INK on the edge, not the box. Gated at 1600 so 1440-class
   laptops keep the slide-in look he already approved. */
/* WIDE SCREENS — deliberately NOT special-cased, and this is the second attempt.
   Tried flush to the window edge: Craig, on "Look closer", "a little weird with a short
   word... way over to the right side ... looks a little too disconnected."
   Tried centring it in the gap between the heading column and the window, with both
   `left` and `right` set and `margin-inline:auto`: it does not centre. An absolutely
   positioned box only gets centred by auto margins when left, right AND width are all
   resolvable and the box FITS — with `width:max-content` and a phrase wider than the
   gap it goes over-constrained, the auto margins compute to zero, and it pins left.
   Measured 415px off centre at 1920. Same auto-margin rule that broke the first fix.
   So the script keeps ONE behaviour at every desktop width: 50px of ink past the
   container, which is the version he approved. If this is revisited, the honest way is
   a measured left offset per breakpoint, not auto margins. */
@media (max-width:991.98px){
  .page-intro .script{
    text-align:left; white-space:normal;
    /* Craig, 2026-08-17: "way too much spacing above and below the handwritten —
       decrease the padding above it by half and decrease the spacing below by 3/4."
       Measured at 430px: 67px above, 62px below. The bulk of the gap above is the
       row's own g-5 gutter (48px) landing as padding-top on the column, so halving
       that is where the space actually comes from; the script's own margin gives
       the rest. Below is the section's padding-bottom, cut from --sp-lg to --sp-xs. */
    margin:0;
  }
  /* The gap above is the row's g-5 gutter landing as padding-top on this column, not
     anything the script owns — so that is where the space has to come off. */
  .page-intro .row > *:last-child{ padding-top:var(--sp-sm); }
}
}

.eyebrow{
  font-family:var(--font1Family);
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:.18em;
  font-size:.8125rem;
  line-height:1.4;
  color:color-mix(in srgb,var(--color1) 82%,var(--color3));
  margin:0 0 var(--sp-xs);
  display:block;
}
.eyebrow-rev{ color:var(--color2); }

code,kbd,samp,pre{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.9em;
  color:color-mix(in srgb,var(--color1) 82%,var(--color3));
  background:var(--color5);
  border-radius:var(--RadiusBrand);
  padding:0 4px;
}
.sec-cream code,.sec-cream kbd,.sec-cream samp{ background:var(--PageBgColor); }
.rev code,.sec-dark code,.rev kbd,.sec-dark kbd{
  color:color-mix(in srgb,var(--reverse1) 78%,var(--color3));
  background:color-mix(in srgb,var(--reverse1) 10%,transparent);
}
mark{ background:var(--color5); color:var(--FontColor); }

.measure{ max-width:68ch; }
.measure-tight{ max-width:52ch; }
.lead{ font-family:var(--BodyFont); font-size:clamp(1.125rem,1.02rem + .35vw,1.3125rem); line-height:1.6; }
.caption{ font-family:var(--BodyFont); font-size:.875rem; line-height:1.6; color:color-mix(in srgb,var(--color2) 55%,var(--color3)); }
.caps{ font-family:var(--LabelFont); text-transform:uppercase; letter-spacing:.14em; }
.muted{ color:color-mix(in srgb,var(--color2) 55%,var(--color3)); }
.accent{ color:var(--color1); }

/* NO UNDERLINE ON ANY LINK. Craig, 2026-10-14: "give everything the Estate look - no blue buttons, no underlines
   on links" (standing rule: hover is a color change, never an underline). Bootstrap's reboot underlines every a;
   this used to style that underline gold. */
a{ color:color-mix(in srgb,var(--color1) 82%,var(--color3)); text-decoration:none; }
a:hover{ color:var(--color3); text-decoration:none; }
.rev a{ color:var(--reverse1); }
.rev a:hover{ color:var(--color2); }

/* FONT AWESOME'S SVG SIZING, PORTED VERBATIM. Craig, 2026-10-14: the /plan date icon "is not from Style Guide SST".
   The Releventful form hard-codes the guide's fa-calendar-days <svg class="svg-inline--fa">, but this template loads
   no Font Awesome, so nothing sized it: Chromium drew it 22x26, WebKit stretched it to fill the 45px panel (45x51).
   On /ops/style-guide the FA kit injects exactly these two rules (read off the page 2026-10-14). */
svg:not(:host).svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible;box-sizing:content-box}
.svg-inline--fa{display:var(--fa-display,inline-block);height:1em;overflow:visible;vertical-align:-.125em}

:focus-visible{
  outline:var(--BorderBrandWidth) solid var(--colorGold);
  outline-offset:2px;
}
.rev :focus-visible{ outline-color:var(--colorGold); }
/* elements whose own hairline carries the focus state — never a second line */
.button:focus-visible,
.nav-list a:focus-visible,
.nav-overlay a:focus-visible,
.footer-nav a:focus-visible,
.footer-legal a:focus-visible,
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible,
.filter:focus-visible{ outline:none; }

.visually-hidden{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); white-space:nowrap;
}
.skip-link{
  font-family:var(--LabelFont);
  position:absolute; left:var(--sp-xs); top:-4rem; z-index:200;
  background:var(--color3); color:var(--reverse1);
  padding:var(--sp-xxs) var(--sp-xs); text-transform:uppercase;
  letter-spacing:.1em; font-size:.8125rem; text-decoration:none;
  transition:top .2s ease;
}
.skip-link:focus{ top:var(--sp-xs); color:var(--reverse1); }

/* ===== styles/components.css ===== */
/* ============================================================
   3. COMPONENTS
   ============================================================ */
/* --- Buttons ---
   The element holds ONLY the label. A single ::before layer behind it carries
   the fill and the 1px border, and that layer is what grows on hover: the label
   never scales, never moves, never resamples. The layer's border width is
   counter-scaled so the hairline still renders as a true 1px at full size, and
   because the growth is a transform the button's footprint never changes —
   nothing else on the page can shift. No shadows. No second lines. */
a,button,input,select,textarea{ -webkit-tap-highlight-color:transparent; }
.button{
  display:inline-flex; align-items:center; justify-content:center;
  gap:var(--sp-xxs);
  font-family:var(--ButtonFont);
  font-weight:400;
  font-size:.8125rem;
  text-transform:uppercase;
  letter-spacing:.1em;
  line-height:1;
  padding:20px 44px;
  border:0;
  background:none;
  text-decoration:none;
  cursor:pointer;
  text-align:center;
  white-space:nowrap;
  flex:0 0 auto;
  position:relative;
  isolation:isolate;
  /* THESE TWO CAME FREE FROM BOOTSTRAP'S `.btn` AND STOP COMING FREE AT THE RENAME.
     vertical-align decides where an inline-flex button sits on the text baseline beside
     it, and user-select is why dragging across a CTA does not highlight its label. Both
     measured on the /v2 specimens before the rename (middle / none); declared here so the
     rename moves nothing. Everything else Bootstrap's .btn set was already overridden
     above — border, background, padding, type, transition. */
  vertical-align:middle;
  -webkit-user-select:none;
          user-select:none;
  --button-fill:transparent;
  --button-border:transparent;
  transition:color .3s ease;
}
/* THE 20-SELECTOR BOOTSTRAP MIRROR THAT USED TO SIT HERE IS GONE, AND IT IS GONE
   BECAUSE OF THE RENAME. It existed only to out-rank Bootstrap's own `.btn:hover`,
   `.btn:active` and `:not(.btn-check) + .btn:active` rules, which painted a #5C636A slab
   over our ::before layer and swallowed the label. Bootstrap owns `.btn`; this system
   now owns `.button`, so there is nothing left to out-rank and no cascade war to keep
   in sync. If a Bootstrap button rule ever reappears on one of these, the cause is a
   stray `btn` class left in the markup, not a missing mirror — fix the markup.
   Removed 2026-09-10 with the .btn -> .button rename. */
.button::before{
  content:"";
  position:absolute; inset:0; z-index:-1;
  border-radius:var(--RadiusBrand);
  background-color:var(--button-fill);
  border:var(--BorderBrandWidth) solid var(--button-border);
  transform:scale(1);
  transition:
    transform .34s cubic-bezier(.13,.9,.28,1),
    border-width .34s cubic-bezier(.13,.9,.28,1),
    background-color .3s ease,
    border-color .3s ease;
}
.button:hover::before,.button:focus-visible::before{
  transform:scale(var(--button-grow,1.04));
  border-width:calc(var(--BorderBrandWidth) / var(--button-grow,1.04));
  border-color:var(--colorGold);
}
.button:active::before{
  transform:scale(1.01);
  border-width:calc(var(--BorderBrandWidth) / 1.01);
  transition-duration:.1s;
}
@media (prefers-reduced-motion:reduce){
  .button::before{ transition-duration:.01ms; }
  .button:hover::before,.button:focus-visible::before{ transform:none; border-width:var(--BorderBrandWidth); }
}

.button-primary{
  color:var(--reverse1);
  --button-fill:var(--PrimaryButtonColor);
  --button-border:var(--PrimaryButtonColor);
}
.button-primary:hover,.button-primary:focus-visible{ color:var(--reverse1); }
.button-primary:hover::before,.button-primary:focus-visible::before{ background-color:var(--PrimaryButtonHoverColor); }

/* Quiet — card-level "Learn more" CTAs: primary weight, soft cream fill */
.button-quiet{
  color:var(--color3);
  --button-fill:var(--color5);
  --button-border:var(--BorderBrandColor);
}
.button-quiet:hover,.button-quiet:focus-visible{ color:var(--color3); }
.button-quiet:hover::before,.button-quiet:focus-visible::before{ background-color:color-mix(in srgb,var(--color5) 60%,var(--PageBgColor)); }
.sec-cream .button-quiet{ --button-fill:var(--PageBgColor); }
.sec-cream .button-quiet:hover::before,.sec-cream .button-quiet:focus-visible::before{ background-color:color-mix(in srgb,var(--PageBgColor) 60%,var(--color5)); }
/* Compact size for cards */
.button-sm{ padding:16px 30px; font-size:.75rem; min-height:44px; }

.button-secondary{
  color:var(--color3);
  /* THE SECONDARY BUTTON IS AN OUTLINE BUTTON. THAT IS ITS IDENTITY, NOT A BRAND VALUE.
     This read `var(--SecondaryButtonColor)` until 2026-09-10, and on /v2 that token is
     `transparent` — so the two are the same pixel here and the change is invisible on the
     website. It is NOT the same anywhere the TLC brand chain is also running: the CM's ink
     contexts (.onLt, .onDrk, .onMix …) re-declare the *ButtonColor tokens on elements
     INSIDE the component's ancestor, and a descendant's own declaration beats any
     specificity from further up — so on /ops/style-guide?brand=Default the secondary
     button filled #7B6E46 olive under #6D775F sage text and the label vanished.
     `transparent` is V2 saying "this button has no fill", the same way --BorderBrandWidth
     says "1px". A brand can repaint an outline; it cannot make it solid without making it
     a different component. Stated literally so it survives any chain the page is on. */
  --button-fill:transparent;
  --button-border:var(--color3);
}
.button-secondary:hover,.button-secondary:focus-visible{ color:var(--color3); }

.rev .button-primary,.button-primary.on-dark,
.site-header.over .header-cta .button-primary{
  color:var(--color3);
  --button-fill:var(--reverse1);
  --button-border:var(--reverse1);
}
.rev .button-primary:hover,.button-primary.on-dark:hover,
.rev .button-primary:focus-visible,.button-primary.on-dark:focus-visible,
.site-header.over .header-cta .button-primary:hover{ color:var(--color3); }
.rev .button-primary:hover::before,.button-primary.on-dark:hover::before,
.site-header.over .header-cta .button-primary:hover::before{ background-color:var(--reverse1); }

.rev .button-primary.button-quiet,.button-primary.button-quiet.on-dark{
  color:var(--reverse1);
  --button-fill:color-mix(in srgb,var(--reverse1) 14%,var(--color3));
  --button-border:color-mix(in srgb,var(--reverse1) 30%,var(--color3));
}

.rev .button-secondary,.button-secondary.on-dark{
  color:var(--reverse1);
  --button-border:color-mix(in srgb,var(--reverse1) 55%,var(--color3));
}
.rev .button-secondary:hover,.button-secondary.on-dark:hover,
.rev .button-secondary:focus-visible,.button-secondary.on-dark:focus-visible{ color:var(--reverse1); }

.button.disabled,.button:disabled{
  color:var(--color2);
  --button-fill:var(--DisabledColor);
  --button-border:var(--DisabledColor);
  pointer-events:none;
  /* Bootstrap's `.btn:disabled{opacity:var(--bs-btn-disabled-opacity)}` used to supply
     this — measured 0.65 on the /v2/components specimen before the rename. Nothing here
     ever declared it, so the moment the base class stopped being `.btn` the disabled
     button would have snapped to full opacity. Stated explicitly so the rename is
     render-neutral and so this state no longer depends on a framework we do not own. */
  opacity:.65;
}
.button.disabled::before,.button:disabled::before{ transform:none; }

/* Ghost — no box at all; the gold rule runs in and the arrow slides */
.button-ghost{
  padding:var(--sp-xxs) 0;
  border:0;
  background-color:transparent;
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat;
  background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  color:var(--color3);
  align-self:flex-start;
  isolation:auto;
  transition:color .3s ease, background-size .42s cubic-bezier(.35,0,.65,1);
}
.button-ghost::before{ display:none; }
.button-ghost .arw{ display:inline-block; transition:transform .45s cubic-bezier(.22,.61,.36,1); }
.button-ghost:hover,.button-ghost:focus-visible{
  color:color-mix(in srgb,var(--color1) 82%,var(--color3));
  background-size:100% var(--BorderBrandWidth);
}
.button-ghost:hover .arw,.button-ghost:focus-visible .arw{ transform:translateX(8px); }
.rev .button-ghost{ color:var(--reverse1); }
.rev .button-ghost:hover,.rev .button-ghost:focus-visible{ color:var(--reverse1); background-size:100% var(--BorderBrandWidth); }
/* --- Gold shine ---
   A gold reflection travelling across the LABEL on hover, paired with the ::before growth.
   Clipping a gradient to glyphs means painting it as a BACKGROUND, and a background can
   only ever be painted in step 1 of its own stacking context. `.button{ isolation:isolate }`
   makes the button a stacking context, and inside one the negative-z children paint in
   step 2 — so `.button::before` (z-index:-1, the fill) lands ON TOP of anything the button's
   own background drew, and erased the label on every filled variant. Measured: secondary
   (fill transparent) shone, primary went blank. The isolation is load-bearing — drop it
   and the fill falls behind section backgrounds — and sweeping the FILL instead was worse
   (Craig: "the gradient shows over entire button instead of just the text").
   So the shine needs a layer that is INLINE CONTENT, which paints in step 7, above the
   fill. estate.js wraps every button's bare text in `.button-t` for exactly that; if the
   script never runs there is simply no shine and nothing else changes. */
.button-t{ display:inline-block; }
/* Shine stops derived from the CM gold (--colorGold = --attention), Craig 2026-10-14 "all colors should be SST
   dynamic via the ID CMs": were #FFF6E2 / #FFF3D6. Each gradient is declared twice: a color-mix() version first
   (every browser that does background-clip:text; up to 12/255 off), then the gold-relative oklch() version (within
   1.7/255), which wins where relative color syntax exists. Without the first, a browser lacking it would drop the
   whole gradient and clip-text could paint nothing. */
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .button:not(.button-ghost):hover .button-t,
  .button:not(.button-ghost):focus-visible .button-t{
    background-image:linear-gradient(100deg,
      currentColor 0 40%,
      color-mix(in srgb,var(--colorGold) 88%,color-mix(in srgb, var(--colorGold) 13%, white)) 47%,
      color-mix(in srgb, var(--colorGold) 19%, white) 50%,
      color-mix(in srgb,var(--colorGold) 88%,color-mix(in srgb, var(--colorGold) 13%, white)) 53%,
      currentColor 60% 100%);
    background-size:250% 100%;
    background-repeat:no-repeat;
    background-position:0% 0;
    -webkit-background-clip:text;
            background-clip:text;
    -webkit-text-fill-color:transparent;
    animation:button-shine .9s cubic-bezier(.33,0,.24,1) 1;
  }
@supports ((-webkit-background-clip:text) or (background-clip:text)) and (color: oklch(from red l c h)){
  .button:not(.button-ghost):hover .button-t,
  .button:not(.button-ghost):focus-visible .button-t{
    background-image:linear-gradient(100deg,
      currentColor 0 40%,
      color-mix(in srgb,var(--colorGold) 88%,oklch(from var(--colorGold) .975 calc(c * .29) h)) 47%,
      oklch(from var(--colorGold) .966 calc(c * .42) h) 50%,
      color-mix(in srgb,var(--colorGold) 88%,oklch(from var(--colorGold) .975 calc(c * .29) h)) 53%,
      currentColor 60% 100%);
  }
}
}
@keyframes button-shine{ from{ background-position:100% 0; } }
@media (prefers-reduced-motion:reduce){
  .button:not(.button-ghost):hover .button-t,
  .button:not(.button-ghost):focus-visible .button-t{
    background-image:none; -webkit-text-fill-color:currentColor; animation:none;
  }
}
.button-row{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-xs); }

/* --- Dividers + ornaments --- */
.divider{ height:1px; background:var(--BorderBrandColor); border:0; margin:0; }
.rev .divider{ background:color-mix(in srgb,var(--reverse1) 22%,transparent); }
.ornament{ width:60px; height:1px; background:var(--color1); border:0; margin:0; }
.ornament-center{ margin-inline:auto; }

/* --- Photo placeholders --- */
.ph{
  position:relative;
  background:
    repeating-linear-gradient(135deg,
      color-mix(in srgb,var(--color2) 16%,var(--color5)) 0 10px,
      var(--color5) 10px 20px);
  border:var(--BorderBrandWidth) solid var(--BorderBrandColor);
  display:flex; align-items:flex-end;
  overflow:hidden;
  width:100%;
}
.ph-detail{
  background:
    repeating-linear-gradient(135deg,
      color-mix(in srgb,var(--color4) 14%,var(--color5)) 0 10px,
      var(--color5) 10px 20px);
}
.ph-label{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.6875rem;
  line-height:1.5;
  letter-spacing:.04em;
  text-transform:uppercase;
  color:var(--color3);
  background:color-mix(in srgb,var(--PageBgColor) 88%,transparent);
  border-top:var(--BorderBrandWidth) solid var(--BorderBrandColor);
  padding:var(--sp-xxs) var(--sp-xs);
  width:100%;
  margin:0;
}
.ph-req .ph-label::before{ content:"◆ client photo · "; color:var(--color1); }
.ph-detail .ph-label::before{ content:"◇ detail shot · "; color:var(--color4); }
.r-45{ aspect-ratio:4/5; }
.r-32{ aspect-ratio:3/2; }
.r-11{ aspect-ratio:1/1; }
.r-169{ aspect-ratio:16/9; }
.r-219{ aspect-ratio:21/9; }
.ph-fill{ height:100%; aspect-ratio:auto; }

/* --- Editorial card --- */
.card-ed{
  display:flex; flex-direction:column;
  background:transparent;
  border-radius:var(--RadiusBrand);
  height:100%;
}
.card-ed.filled{ background:var(--color5); }
.card-ed.bordered{ border:var(--BorderBrandWidth) solid var(--BorderBrandColor); }
/* a placeholder sitting inside a bordered or filled card drops its own edge */
.card-ed.bordered .ph,.card-ed.filled .ph{ border:0; }
.card-ed.bordered .ph-label,.card-ed.filled .ph-label{ border-top-color:var(--BorderBrandColor); }
.card-ed .card-body{ padding:var(--sp-sm) 0 0; display:flex; flex-direction:column; gap:var(--sp-xxs); flex:1 1 auto; align-items:flex-start; }
.card-ed.filled .card-body,.card-ed.bordered .card-body{ padding:var(--sp-sm); }
.card-ed .card-body p{ margin:0; }
.card-ed .button-ghost,.card-ed .button{ margin-top:auto; }

/* --- The whole card is the hit area ---
   Craig, 2026-08-01: "the entire card needs to be clickable, not just the LEARN MORE
   button... i need this style of large hover area in any card across entire site...
   still want the LEARN MORE button hover state to fire when hovering ANY part of the
   entire card. Also, need animation in the image on hover, i love a slight grow but
   staying in bounds."
   estate.js drops a real <a class="card-hit"> over each card, cloned from that card's
   own CTA — a real anchor, so middle-click, open-in-new-tab and the status bar all
   behave; aria-hidden and tabindex=-1 so the visible button stays the only thing a
   screen reader or the tab order sees. The overlay covers the button too, so the
   button never receives :hover itself — every state below is re-fired from the card,
   mirroring the .button rules above. Keep the two in sync.
   The image grows inside .ph-img, which is already overflow:hidden — hence "in bounds"
   with nothing new to clip. */
.card-ed{ position:relative; }
.card-hit{ position:absolute; inset:0; z-index:3; cursor:pointer; }
/* The card image's own motion lives in EXTRA_CSS, after the LQIP block — see the
   note there. It cannot be declared here: `.lqip .ph-img.lq img` is (0,3,1), beats
   this file's (0,2,1), and its `transition:opacity` shorthand wipes transform. */

.card-ed:hover .button::before,
.card-ed:focus-within .button::before{
  transform:scale(var(--button-grow,1.04));
  border-width:calc(var(--BorderBrandWidth) / var(--button-grow,1.04));
  border-color:var(--colorGold);
}
.card-ed:hover .button-primary::before{ background-color:var(--PrimaryButtonHoverColor); }
.card-ed:hover .button-quiet::before{ background-color:color-mix(in srgb,var(--color5) 60%,var(--PageBgColor)); }
.sec-cream .card-ed:hover .button-quiet::before{ background-color:color-mix(in srgb,var(--PageBgColor) 60%,var(--color5)); }
.card-ed:hover .button-ghost,
.card-ed:focus-within .button-ghost{
  color:color-mix(in srgb,var(--color1) 82%,var(--color3));
  background-size:100% var(--BorderBrandWidth);
}
.rev .card-ed:hover .button-ghost,.rev .card-ed:focus-within .button-ghost{ color:var(--reverse1); }
.card-ed:hover .button-ghost .arw,.card-ed:focus-within .button-ghost .arw{ transform:translateX(8px); }
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .card-ed:hover .button:not(.button-ghost) .button-t{
    background-image:linear-gradient(100deg,
      currentColor 0 40%,
      color-mix(in srgb,var(--colorGold) 88%,color-mix(in srgb, var(--colorGold) 13%, white)) 47%,
      color-mix(in srgb, var(--colorGold) 19%, white) 50%,
      color-mix(in srgb,var(--colorGold) 88%,color-mix(in srgb, var(--colorGold) 13%, white)) 53%,
      currentColor 60% 100%);
    background-size:250% 100%;
    background-repeat:no-repeat;
    background-position:0% 0;
    -webkit-background-clip:text;
            background-clip:text;
    -webkit-text-fill-color:transparent;
    animation:button-shine .9s cubic-bezier(.33,0,.24,1) 1;
  }
@supports ((-webkit-background-clip:text) or (background-clip:text)) and (color: oklch(from red l c h)){
  .card-ed:hover .button:not(.button-ghost) .button-t{
    background-image:linear-gradient(100deg,
      currentColor 0 40%,
      color-mix(in srgb,var(--colorGold) 88%,oklch(from var(--colorGold) .975 calc(c * .29) h)) 47%,
      oklch(from var(--colorGold) .966 calc(c * .42) h) 50%,
      color-mix(in srgb,var(--colorGold) 88%,oklch(from var(--colorGold) .975 calc(c * .29) h)) 53%,
      currentColor 60% 100%);
  }
}
}
@media (prefers-reduced-motion:reduce){
  .card-ed:hover .button::before,.card-ed:focus-within .button::before{
    transform:none; border-width:var(--BorderBrandWidth);
  }
  .card-ed:hover .button:not(.button-ghost) .button-t{
    background-image:none; -webkit-text-fill-color:currentColor; animation:none;
  }
}

/* --- Stat block --- */
.stat{ display:flex; flex-direction:column; gap:var(--sp-xs); }
.stat-num{
  font-family:var(--font1Family); font-weight:300;
  font-size:clamp(2.5rem,1.8rem + 2.2vw,3.75rem);
  line-height:1; letter-spacing:.02em;
}
.stat-rule{ width:100%; height:1px; background:var(--BorderBrandColor); }
.rev .stat-rule{ background:color-mix(in srgb,var(--reverse1) 22%,transparent); }
.stat-label{
  font-family:var(--LabelFont);
  font-size:.8125rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.18em; color:color-mix(in srgb,var(--color2) 55%,var(--color3));
}

/* --- Icons --- */
.ico{ width:30px; height:30px; display:block; stroke:var(--color1); fill:none; stroke-width:1; }
.ico-circle{
  width:68px; height:68px; border-radius:50%;
  background:var(--color5);
  display:flex; align-items:center; justify-content:center;
  flex:0 0 auto;
}
.rev .ico{ stroke:var(--color2); }
.rev .ico-circle{ background:color-mix(in srgb,var(--reverse1) 8%,transparent); }

/* --- Checklist --- */
.check-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--sp-xs); }
.check-list li{ display:flex; gap:var(--sp-xs); align-items:flex-start; }
.check-list .ico{ margin-top:4px; }
.check-list span{ font-size:1rem; line-height:1.6; }

/* --- Quote --- */
.quote{ display:flex; flex-direction:column; gap:var(--sp-xs); }
.quote blockquote{
  margin:0; font-family:var(--font1Family); font-weight:300;
  font-size:clamp(1.125rem,1.02rem + .4vw,1.375rem);
  line-height:1.55;
}
.quote cite{
  font-family:var(--LabelFont); font-style:normal; font-size:.8125rem; font-weight:700;
  text-transform:uppercase; letter-spacing:.18em; color:color-mix(in srgb,var(--color2) 55%,var(--color3));
}
.stars{ letter-spacing:.3em; color:var(--color1); font-size:.9375rem; }

/* --- Field --- */
.field{ display:flex; flex-direction:column; gap:var(--sp-xxs); }
.field label{
  font-family:var(--LabelFont);
  font-size:.75rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.18em; color:var(--color3);
}
.field input,.field select,.field textarea{
  font-family:var(--BodyFont); font-size:1rem; color:var(--FontColor);
  background-color:var(--PageBgColor);
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat;
  background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  border:0; border-bottom:var(--BorderBrandWidth) solid var(--color2);
  border-radius:var(--RadiusBrand);
  padding:var(--sp-xxs) 0;
  width:100%;
  transition:background-size .42s cubic-bezier(.35,0,.65,1), border-bottom-color .3s ease;
}
.field textarea{ min-height:120px; resize:vertical; }
.field input:focus,.field select:focus,.field textarea:focus,
.field input:hover,.field select:hover,.field textarea:hover{
  background-size:100% var(--BorderBrandWidth);
  border-bottom-color:var(--color3);
}
.field-hint{ font-size:.75rem; color:color-mix(in srgb,var(--color2) 55%,var(--color3)); }

/* ===== styles/layout.css ===== */
/* ============================================================
   4. LAYOUT
   ============================================================ */
.sec{ padding-top:var(--sp-lg); padding-bottom:var(--sp-lg); position:relative; }
.sec-sm{ padding-top:var(--sp-md); padding-bottom:var(--sp-md); }
.sec-md{ padding-top:var(--sp-lg); padding-bottom:var(--sp-lg); }
.sec-lg{ padding-top:var(--sp-xl); padding-bottom:var(--sp-xl); }
.sec-xl{ padding-top:var(--sp-xxl); padding-bottom:var(--sp-xxl); }
.sec-flush-top{ padding-top:0; }
.sec-cream{ background:var(--color5); }
.sec-dark{ background:var(--color3); color:var(--reverse1); }
.sec-dark .caption,.sec-dark .muted{ color:color-mix(in srgb,var(--color2) 55%,var(--color3)); }
.sec-rule{ border-top:var(--BorderBrandWidth) solid var(--BorderBrandColor); }
.container{ max-width:1320px; padding-inline:var(--sp-sm); }
.stack-xs > * + *{ margin-top:var(--sp-xs); }
.stack-sm > * + *{ margin-top:var(--sp-sm); }
.stack-md > * + *{ margin-top:var(--sp-md); }
.offset-up{ margin-top:calc(-1 * var(--sp-lg)); }
.pull-right{ margin-right:calc(-1 * var(--sp-md)); }
.bleed{ width:100%; }

/* In-page anchors land under the fixed header without this — the article TOC jumps
   to a heading that is then hidden behind the nav bar. Applied to anything that is
   an anchor target rather than to every heading. */
html{ scroll-behavior:smooth; }
@media (prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }
[id]{ scroll-margin-top:110px; }


/* ===== styles/sections.css ===== */
/* ============================================================
   5. SECTIONS
   ============================================================ */
/* --- Header --- */
.site-header{
  position:fixed; inset:0 0 auto; z-index:100;
  padding:var(--sp-sm) 0;
  transition:background-color .35s ease, padding .35s ease, border-color .35s ease;
  border-bottom:var(--BorderBrandWidth) solid transparent;
}
.site-header.over{ background:transparent; }
.site-header.solid{
  background:var(--PageBgColor);
  border-bottom-color:var(--BorderBrandColor);
  padding:var(--sp-xs) 0;
}
.header-grid{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-md); }
.logo{ text-decoration:none; display:block; line-height:1; }
.logo img{ display:block; width:200px; height:auto; }
/* The header ships the onLt (dark) wordmark and flips it when it sits over a
   hero. The FOOTER ships the real onDrk (white) asset, so it must never be
   inverted — .rev was turning white artwork black on the charcoal footer. */
.site-header.over .logo img{ filter:invert(1); }
.site-footer .logo img{ width:260px; filter:none; }
.nav-list{ display:flex; gap:var(--sp-sm); list-style:none; margin:0; padding:0; align-items:center; }
.nav-list a{
  font-family:var(--LabelFont);
  display:inline-block; white-space:nowrap; line-height:1.2;
  font-size:.75rem; text-transform:uppercase; letter-spacing:.16em;
  color:var(--color3); text-decoration:none; padding:var(--sp-xxs) 0;
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat;
  background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  transition:color .3s ease, background-size .42s cubic-bezier(.35,0,.65,1);
}
.nav-list a:hover,.nav-list a:focus-visible{
  color:var(--color3);
  background-size:100% var(--BorderBrandWidth);
}
.nav-list a[aria-current="page"]{
  color:var(--color1);
  background-size:100% var(--BorderBrandWidth);
}
.site-header.over .nav-list a{ color:var(--reverse1); }
.site-header.over .nav-list a:hover,.site-header.over .nav-list a:focus-visible,.site-header.over .nav-list a[aria-current="page"]{ color:var(--reverse1); }
.header-cta .button{ padding:14px 26px; font-size:.75rem; }

.nav-toggle{
  font-family:var(--LabelFont);
  display:none; background:none; border:0; padding:var(--sp-xxs);
  cursor:pointer; color:var(--color3);
  font-size:.75rem; text-transform:uppercase; letter-spacing:.16em;
}
.site-header.over .nav-toggle{ color:var(--reverse1); }
.nav-overlay{
  position:fixed; inset:0; z-index:150; background:var(--color3); color:var(--reverse1);
  display:flex; flex-direction:column; padding:var(--sp-sm);
  opacity:0; visibility:hidden; transition:opacity .35s ease, visibility .35s ease;
}
.nav-overlay.open{ opacity:1; visibility:visible; }
.nav-overlay-inner{ margin:auto; display:flex; flex-direction:column; gap:var(--sp-sm); text-align:center; }
.nav-overlay a{
  font-family:var(--LabelFont);
  color:var(--reverse1); text-decoration:none; text-transform:uppercase;
  letter-spacing:.16em; font-size:1rem;
  display:inline-block; padding-bottom:var(--sp-xxs);
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat;
  background-position:center bottom;
  background-size:0 var(--BorderBrandWidth);
  transition:background-size .42s cubic-bezier(.35,0,.65,1);
}
.nav-overlay a:hover,.nav-overlay a:focus-visible{ background-size:100% var(--BorderBrandWidth); }
.nav-overlay .button{ background-image:none; padding:20px 44px; }
.nav-close{
  font-family:var(--LabelFont);
  align-self:flex-end; background:none; border:0; color:var(--reverse1);
  font-size:.75rem; letter-spacing:.16em; text-transform:uppercase; cursor:pointer;
  padding:var(--sp-xxs);
}

/* --- Hero --- */
.hero{ position:relative; min-height:88vh; display:flex; align-items:flex-end; overflow:hidden; }
.hero-short{ min-height:62vh; }
.hero .ph{ position:absolute; inset:0; border:0; aspect-ratio:auto; align-items:flex-end; }
.hero .ph-label{ background:color-mix(in srgb,var(--color3) 70%,transparent); color:var(--reverse1); border-top-color:color-mix(in srgb,var(--reverse1) 20%,transparent); }
.hero .ph-req .ph-label::before{ color:var(--color2); }
.scrim{ position:absolute; inset:0; background:color-mix(in srgb,var(--color3) 45%,transparent); }
.scrim-soft{ background:color-mix(in srgb,var(--color3) 35%,transparent); }
.scrim-strong{ background:color-mix(in srgb,var(--color3) 55%,transparent); }
.hero-inner{ position:relative; z-index:2; padding-top:var(--sp-xxl); padding-bottom:var(--sp-xl); color:var(--reverse1); }
.hero-inner h1{ margin-bottom:var(--sp-sm); }

/* --- Image band --- */
.band{ position:relative; min-height:520px; display:flex; align-items:center; justify-content:center; overflow:hidden; }
.band .ph{ position:absolute; inset:0; border:0; aspect-ratio:auto; }
.band .ph-label{ background:color-mix(in srgb,var(--color3) 70%,transparent); color:var(--reverse1); border-top-color:color-mix(in srgb,var(--reverse1) 20%,transparent); }
.band-inner{ position:relative; z-index:2; text-align:center; color:var(--reverse1); padding:var(--sp-xl) var(--sp-sm); }

/* --- Footer --- */
.site-footer{ background:var(--color3); color:var(--reverse1); padding:var(--sp-xl) 0 var(--sp-md); }
.footer-nav{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--sp-xxs); }
.footer-nav a{
  font-family:var(--LabelFont);
  color:var(--reverse1); text-decoration:none; font-size:.8125rem;
  text-transform:uppercase; letter-spacing:.12em;
  display:inline-block; padding-bottom:3px;
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat;
  background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  transition:background-size .42s cubic-bezier(.35,0,.65,1);
}
.footer-nav a:hover,.footer-nav a:focus-visible{ background-size:100% var(--BorderBrandWidth); }
.footer-head{
  font-family:var(--LabelFont);
  font-size:.75rem; font-weight:700; text-transform:uppercase;
  letter-spacing:.18em; color:var(--color2); margin:0 0 var(--sp-xs);
}
.footer-legal{ display:flex; flex-wrap:wrap; gap:var(--sp-sm); list-style:none; margin:0; padding:0; }
.footer-legal a{ font-family:var(--LabelFont); color:var(--color2); font-size:.75rem; text-transform:uppercase; letter-spacing:.12em; text-decoration:none; }
.footer-legal a:hover{ color:var(--reverse1); }
.social-row{ display:flex; gap:var(--sp-xs); }
.social-row a{ display:flex; }
.social-row .ico{ stroke:var(--reverse1); width:40px; height:40px; }
.social-row a:hover .ico{ stroke:var(--color2); }

/* --- hvr-pop on brand logos and linked icons ------------------------------------
   Craig, 2026-08-01: every brand logo and every linking icon should carry hvr-pop, and
   then: "install those so we have a plethora of good ones." So the template now loads
   /css/hover-min.css (the same Hover.css the live site uses) and the effect is opted
   into BY CLASS in the markup — `class="logo hvr-pop"`, `class="hvr-pop"` on the social
   anchors — instead of being restated here. A second local @keyframes hvr-pop would
   shadow the library's and quietly drift from it.
   These two declarations stay local on purpose: they are box model, and layout must
   never depend on an external stylesheet arriving. Hover.css sets the same values, so
   there is no shift either way. */
.logo,.social-row a{ display:inline-block; vertical-align:middle; }
}

/* --- Page intro --- */
.page-intro .script{ font-size:clamp(1.75rem,1.2rem + 2vw,3.25rem); }
.page-intro{ padding-top:calc(var(--sp-xxl) + var(--sp-md)); padding-bottom:var(--sp-lg); }

/* --- Gallery grid --- */
.gal{ display:grid; grid-template-columns:repeat(12,1fr); gap:var(--sp-xs); }
.g-4{ grid-column:span 4; }
.g-6{ grid-column:span 6; }
.g-8{ grid-column:span 8; }
.g-12{ grid-column:span 12; }

/* --- Tier row --- */
.tier{ display:grid; grid-template-columns:1fr; gap:var(--sp-md); align-items:center; }
.tier-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--sp-xxs); }
.tier-list li{ font-size:1rem; padding-left:var(--sp-xs); position:relative; }
.tier-list li::before{ content:""; position:absolute; left:0; top:.7em; width:6px; height:1px; background:var(--color1); }

/* --- Journal --- */
.article-body{ max-width:68ch; }
.article-body h2{ margin-top:var(--sp-md); }
/* STORIES BROWSE ROW (/journal, custom-stories-posts.html) — the post sidebar's Topics + Archive, laid out across
   the top. Label above its list as in the sidebar; links in a wrapping row, all one size, so every line centers. */
.stories-browse{ margin-bottom:var(--sp-md); }
.stories-browse-group + .stories-browse-group{ margin-top:var(--sp-sm); }
.stories-browse .eyebrow{ margin-bottom:var(--sp-xxs); }
.stories-browse .footer-nav{ flex-direction:row; flex-wrap:wrap; align-items:center; gap:var(--sp-xxs) var(--sp-sm); }
.stories-browse .footer-nav a[aria-current]{ font-weight:700; }
.stories-browse .divider{ margin-top:var(--sp-sm); }
/* Phone: each list is ONE swipeable line instead of 13 wrapped lines (~550px measured at 390) ahead of the first story.
   The next link is cut at the edge, which is what says "there is more". */
@media (max-width:767.98px){
  .stories-browse .footer-nav{ flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none; padding-bottom:var(--sp-xxs); }
  .stories-browse .footer-nav::-webkit-scrollbar{ display:none; }
  .stories-browse .footer-nav li{ flex:0 0 auto; }
  .stories-browse .footer-nav a{ white-space:nowrap; }
}
/* STORY + LEGAL BODIES — text written in the admin editor, not in this design. Craig, 2026-10-14, on
   /blog/smokymountainvenue: "pink headers (way too small, not enough spacing following the paragraph, and
   pink)" and "all headers do not jam up into the paragraph above them ever".
   1. SPACING. Every subhead in an .article-body (43 Blog Posts + the legal pages) gets the designed article's
      top space, whatever comes before it. The editor often leaves a paragraph as a BARE TEXT RUN after a </p>,
      which has no margin of its own, so the heading sat 0-3px under it. A margin on the heading is the only
      thing that holds for every predecessor (p, bare text, ul, li, another heading).
   2. COLOR. The old editor wrapped subheads in <span style="color: rgb(243,166,182)"> - eight pink shades
      across 10 posts. Every color here comes from the ID CMs through the brand pipeline, so an inline color
      is never right: it inherits the token its parent already has. !important because an inline style beats
      every selector otherwise.
   3. SIZE, stories only (.article-story is on the Blog Post detail layout). The posts use h4 as their
      subhead (h3 in 2 posts, h5 under h4 in 2). They take the designed /journal-article subhead - the
      h2 rule above, copied - and h5/h6 take the h3 rule, so a post that nests keeps its two levels. */
.article-body :is(h3,h4,h5,h6){ margin-top:var(--sp-md); }
.article-body > :is(h2,h3,h4,h5,h6):first-child{ margin-top:0; }
.article-body [style*="color"]{ color:inherit !important; }
/* Same class, the other property: a Word paste on /privacy left background:#FEFEFE behind every run -
   white bars on the ivory page. Editor content never owns a background; the page token shows through. */
.article-body [style*="background"]{ background:none !important; }
/* CORE30 /experience BODIES — same defect, Craig 2026-10-14: "all headers do not jam up into the paragraph above
   them ever". The 32 Core30 pages put h2/h3 straight after a <p> or a list with margin-top 0, so the only space
   above a heading was the paragraph's 16px — the same gap as under it, which reads as jammed (measured 16.0px on
   23 pages, tlc-audit-pink-headgap.mjs). section[aria-label="Detail"] is the Core30 body and appears on no other
   page. A primary heading takes the designed article's top space; a sub-heading takes one step less. */
section[aria-label="Detail"] :is(p,ul,ol,blockquote,table) + h2{ margin-top:var(--sp-md); }
section[aria-label="Detail"] :is(p,ul,ol,blockquote,table) + :is(h3,h4,h5,h6){ margin-top:var(--sp-sm); }
.article-story :is(h2,h3,h4){
  font-family:var(--font1Family); font-weight:700; letter-spacing:0;
  font-size:clamp(1.75rem,1.35rem + 1.2vw,2.25rem); line-height:1.25;
  margin-bottom:var(--sp-xs);
}
.article-story :is(h5,h6){
  font-family:var(--font1Family); font-weight:700;
  font-size:clamp(1.125rem,1rem + .45vw,1.375rem); line-height:1.35;
  margin-top:var(--sp-sm); margin-bottom:var(--sp-xxs);
}
.article-body blockquote{
  margin:var(--sp-md) 0; padding-left:var(--sp-sm);
  border-left:2px solid var(--color1);
  font-family:var(--font1Family); font-weight:300; font-size:1.25rem; line-height:1.55;
}

/* --- Component sheet --- */
.spec{ border-top:var(--BorderBrandWidth) solid var(--BorderBrandColor); padding-top:var(--sp-sm); }
.spec-label{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.6875rem; letter-spacing:.06em; color:color-mix(in srgb,var(--color2) 55%,var(--color3));
  text-transform:uppercase; margin:0 0 var(--sp-xs);
}
.swatch{ height:120px; border:var(--BorderBrandWidth) solid var(--BorderBrandColor); }

/* --- Muted text on dark surfaces: AA-safe tint of --reverse1 --- */
.rev .caption,.rev .muted,.rev .caps,.rev .stat-label,.rev .eyebrow-rev,
.sec-dark .caption,.sec-dark .muted,.sec-dark .caps,.sec-dark .stat-label,.sec-dark .eyebrow-rev,
.site-footer .caption,.site-footer .caps,.site-footer .footer-head,.site-footer .footer-legal a,
.nav-overlay .caption{
  color:color-mix(in srgb,var(--reverse1) 78%,var(--color3));
}
.rev .button-ghost:hover,.sec-dark .button-ghost:hover,
.site-footer .footer-nav a:hover,.site-footer .footer-legal a:hover,
.nav-overlay a:hover{
  color:var(--reverse1);
}
.rev .button-ghost:hover,.sec-dark .button-ghost:hover{ border-bottom-color:var(--reverse1); }

.social-row a:hover .ico{ stroke:color-mix(in srgb,var(--reverse1) 78%,var(--color3)); }

/* ===== styles/responsive.css ===== */
/* ============================================================
   6. RESPONSIVE  (576 / 768 / 992 / 1200 / 1400)
   ============================================================ */
@media (min-width:992px){
  .tier{ grid-template-columns:1fr 1fr; gap:var(--sp-lg); }
  .tier-reverse .tier-media{ order:2; }
}
@media (max-width:1399.98px){
  .nav-list{ gap:var(--sp-xs); }
  .nav-list a{ letter-spacing:.12em; }
}
@media (max-width:1199.98px){
  .header-grid{ gap:var(--sp-sm); }
  .nav-list{ gap:var(--sp-xs); }
  .nav-list a{ font-size:.6875rem; letter-spacing:.1em; }
  .header-cta .button{ padding:14px 20px; font-size:.6875rem; }
  .logo img{ width:170px; }
}
@media (max-width:991.98px){
  .nav-list,.header-cta{ display:none; }
  .nav-toggle{ display:block; }
  .sec-lg{ padding-top:var(--sp-lg); padding-bottom:var(--sp-lg); }
  .sec-xl{ padding-top:var(--sp-xl); padding-bottom:var(--sp-xl); }
  .g-4,.g-6,.g-8{ grid-column:span 6; }
  .offset-up{ margin-top:0; }
  .pull-right{ margin-right:0; }
}
@media (max-width:767.98px){
  .hero{ min-height:78vh; }
  .band{ min-height:400px; }
  .g-4,.g-6,.g-8{ grid-column:span 12; }
  .button{ width:100%; }
  .button-ghost{ width:auto; }
  .site-footer{ padding-top:var(--sp-lg); }
  /* Craig, 2026-08-17, mobile: "way too much spacing above and below the handwritten."
     The space BELOW it is this section's own padding-bottom. It has to be set here in
     responsive.css, not in base.css — sections.css writes the desktop value LATER in the
     concatenated sheet, so a media query up there loses on order, not specificity. */
  .page-intro{ padding-bottom:var(--sp-xs); }
}
@media (max-width:575.98px){
  .page-intro{ padding-top:calc(var(--sp-xl) + var(--sp-md)); }
}

/* ============================================================
   7. BUILD LAYER — real photography, Treepl form adoption, nav JS states
   ============================================================ */
.ph-img{ position:relative; overflow:hidden; width:100%; background:var(--color5); }
.ph-img img{ width:100%; height:100%; object-fit:cover; display:block; }

/* A CLIENT'S ZOOM IS A VARIABLE, NEVER AN INLINE `transform`.
   The editor lets a client zoom into a photograph, and that crop has to survive
   into the page file. Writing it as `style="transform:scale(2)"` looked obvious
   and broke two things at once on 2026-08-18: an inline transform outranks
   `.card-ed:hover .ph-img img`, so the card lost its hover grow for good, and
   the edit pencil measured itself against a box twice the size and hid.
   As a custom property the card rules can COMPOSE the two - the client's crop
   times the hover's 1.045 - instead of one silently replacing the other.
   Scoped by attribute so an image with no zoom keeps `transform:none` and does
   not gain a stacking context it never asked for. Declared BEFORE the card
   rules on purpose: equal specificity, so those win for cards and this one
   only ever governs a hero or a band, which have no hover state. */
.ph-img img[style*="--ph-zoom"]{ transform:scale(var(--ph-zoom,1)); }
.card-ed.bordered .ph-img,.card-ed.filled .ph-img{ border:0; }
.hero .ph-img,.band .ph-img{ position:absolute; inset:0; aspect-ratio:auto; }
.hero .ph-img img,.band .ph-img img{ height:100%; }

/* --- blur-up ---------------------------------------------------------------
   Every .ph-img.lq carries a ~20px WebP of its own photograph in --lq (build.py
   inlines it; see the LQIP section there for why it is not a resizer URL). The
   ::before paints that blurred under the real image, which fades in on load.

   .lqip is put on <html> by an inline script in the template head, NOT by
   estate.js — estate.js is deferred, so a class added there would land after
   first paint and photos would visibly blink out and fade back in. Gating on it
   also means that with JS off the img simply renders opaque over the blur and
   nothing is ever hidden.

   isolation:isolate is load-bearing, not tidiness. .ph-img is position:relative
   with z-index:auto, so it is NOT a stacking context — an unscoped
   `.ph-img img{z-index:1}` escapes into the hero's context and paints OVER
   .scrim (positioned, z-index:auto, step 8), dropping the dark overlay out
   from under the white hero type on every page with a hero or a band. Sealing
   the tile keeps the ::before/img ordering a private matter. Both rules are
   also scoped to .lq so tiles without a placeholder are untouched. */
.ph-img.lq{ isolation:isolate; }
.ph-img.lq::before{
  content:""; position:absolute; inset:0; z-index:0;
  background-image:var(--lq); background-size:cover; background-position:center;
  filter:blur(12px); transform:scale(1.12);
}
.ph-img.lq img{ position:relative; z-index:1; }
.lqip .ph-img.lq img{ opacity:0; transition:opacity .55s ease; }
.lqip .ph-img.lq.is-loaded img{ opacity:1; }
/* Discard the blurred layer only on .lq-done, which estate.js adds 900ms AFTER
   is-loaded — i.e. once the fade has finished and the photo is fully opaque.
   Hanging this off .is-loaded instead removes the blur as the fade STARTS, and
   any tile whose photo is not actually decoded yet flashes bare --color5. */
.ph-img.lq.lq-done::before{ display:none; }
@media (prefers-reduced-motion: reduce){
  .lqip .ph-img.lq img{ transition:none; }
}

/* --- Scroll reveal ---------------------------------------------------------------
   Craig, 2026-08-01: "subtle animations of the images and important content as the user
   scrolls down the page for all pages... subtle and quiet is much preferred for this
   HIGH-END site." One gesture, used everywhere: a short rise and a fade, 900ms, the same
   ease-out as the rest of the site. No slide-in from the side, no scale on text, no
   bounce - those read as a template. Images fade ONLY; moving a photograph while its own
   LQIP blur is still crossfading looks like a fault rather than a flourish.
   The hidden state is gated on html.rv, which estate.js adds only once it has elements
   to observe. No JS, or no IntersectionObserver, means nothing is ever hidden. Content
   is never hidden by CSS alone. */
html.rv [data-rv]{ opacity:0; transform:translateY(14px); }
html.rv [data-rv="img"]{ transform:none; }
html.rv [data-rv].rv-in{
  opacity:1;
  transform:none;
  transition:opacity .9s cubic-bezier(.22,.61,.36,1),
             transform .9s cubic-bezier(.22,.61,.36,1);
  transition-delay:calc(var(--rv-i,0) * 70ms);
}
html.rv [data-rv="img"].rv-in{ transition:opacity 1.15s cubic-bezier(.22,.61,.36,1); }
@media (prefers-reduced-motion: reduce){
  html.rv [data-rv],html.rv [data-rv].rv-in{ opacity:1; transform:none; transition:none; }
}

/* --- Card image grow -------------------------------------------------------------
   Craig: "cards image needs to grow smooth and elegant not jumpy." It was not the
   easing - it had no transition at all. Declared in styles/components.css as
   `.card-ed .ph-img img` (0,2,1), it was overwritten by `.lqip .ph-img.lq img` (0,3,1,
   and later in the sheet) whose `transition:opacity` SHORTHAND resets transition-property
   to opacity alone. Every card photograph goes through LQIP, so the scale had nothing to
   interpolate and snapped in one frame. Restated here, after that rule, at a specificity
   it cannot lose to. The layer is promoted UP FRONT (translateZ + backface-visibility +
   will-change) so the browser rasterises once instead of re-rasterising mid-scale -
   promoting on :hover is itself a one-frame jump. Keep translateZ in BOTH states so the
   interpolation stays on one matrix type. */
.card-ed .ph-img img,
.lqip .card-ed .ph-img.lq img{
  transform:scale(var(--ph-zoom,1)) translateZ(0);
  transform-origin:50% 50%;
  backface-visibility:hidden;
  will-change:transform;
  transition:opacity .55s ease, transform 1.1s cubic-bezier(.22,.61,.36,1);
}
.card-ed:hover .ph-img img,
.card-ed:focus-within .ph-img img,
.lqip .card-ed:hover .ph-img.lq img,
.lqip .card-ed:focus-within .ph-img.lq img{ transform:scale(calc(var(--ph-zoom,1) * 1.045)) translateZ(0); }
@media (prefers-reduced-motion: reduce){
  .card-ed .ph-img img,.lqip .card-ed .ph-img.lq img{ transition:none; will-change:auto; }
  .card-ed:hover .ph-img img,.card-ed:focus-within .ph-img img,
  .lqip .card-ed:hover .ph-img.lq img,
  .lqip .card-ed:focus-within .ph-img.lq img{ transform:scale(var(--ph-zoom,1)) translateZ(0); }
}

/* gallery filtering */
.gal-item[hidden]{ display:none; }

/* Treepl form component, wearing the Estate field styling.
   Treepl writes its own markup; these rules adopt it rather than fight it. */
.estate-form form{ margin:0; }
.estate-form h3,.estate-form h4{
  font-family:var(--font1Family); font-weight:700; letter-spacing:0;
}
.estate-form h3{ font-size:1.25rem; margin:0 0 var(--sp-xs); }
.estate-form h4{ font-size:1rem; margin:0 0 var(--sp-xxs); }
.estate-form label{
  font-family:var(--LabelFont); font-size:.75rem; font-weight:700;
  text-transform:uppercase; letter-spacing:.18em; color:var(--color3);
  display:block; margin-bottom:var(--sp-xxs);
}
.estate-form input[type=text],.estate-form input[type=email],.estate-form input[type=tel],
.estate-form input[type=number],.estate-form input[type=date],.estate-form input[type=url],
.estate-form select,.estate-form textarea,.estate-form .form-control{
  font-family:var(--BodyFont); font-size:1rem; color:var(--FontColor);
  background-color:var(--PageBgColor);
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat; background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  border:0; border-bottom:var(--BorderBrandWidth) solid var(--color2);
  border-radius:var(--RadiusBrand); box-shadow:none;
  padding:var(--sp-xxs) 0; width:100%;
  transition:background-size .42s cubic-bezier(.35,0,.65,1), border-bottom-color .3s ease;
}
.estate-form textarea,.estate-form textarea.form-control{ min-height:120px; resize:vertical; }
.estate-form input:focus,.estate-form select:focus,.estate-form textarea:focus,
.estate-form input:hover,.estate-form select:hover,.estate-form textarea:hover{
  background-size:100% var(--BorderBrandWidth);
  border-bottom-color:var(--color3); outline:none; box-shadow:none;
}
.estate-form .form-check-input{ width:auto; }
/* A SECOND BUTTON IMPLEMENTATION, AND IT WAS BEATING THE REAL ONE. 2026-09-22.
   This block styles a bare submit control inside a form — fine — but its selector also listed
   `.estate-form .button`, so it repainted the actual component defined at .button / .button-primary
   above: measured on /v2/plan's SEND against §7 on ?brand=Default, 9 of 33 properties differed and
   the verifier named THIS rule for every one of them. The component carries only its label and
   paints its fill and 1px border on a ::before layer (§7's own rules say so); this rule put a
   solid background and a real border back on the element, which is why SEND read as a flat dark
   slab instead of the guide's button.
   `.button` is dropped from the selector and the two bare cases take :not(.button), so a submit
   that opts into the component is left to it. Craig, 2026-09-22: "fix the SEND button to match
   the style guide." */
.estate-form input[type=submit]:not(.button),.estate-form button[type=submit]:not(.button){
  display:inline-flex; align-items:center; justify-content:center;
  font-family:var(--ButtonFont); font-weight:400; font-size:.8125rem;
  text-transform:uppercase; letter-spacing:.1em; line-height:1;
  padding:20px 44px; width:auto;
  color:var(--reverse1); background:var(--PrimaryButtonColor);
  border:var(--BorderBrandWidth) solid var(--PrimaryButtonColor);
  border-radius:var(--RadiusBrand); background-image:none; cursor:pointer;
  transition:background-color .3s ease, border-color .3s ease;
}
.estate-form input[type=submit]:not(.button):hover,.estate-form button[type=submit]:not(.button):hover{
  background:var(--PrimaryButtonHoverColor); border-color:var(--colorGold); color:var(--reverse1);
}

/* Hero legibility: the flat 45% scrim leaves the lead paragraph sitting on bright
   grass. Weight it toward the text column instead of darkening the whole photo. */
.hero .scrim{
  background:linear-gradient(100deg,
    color-mix(in srgb,var(--color3) 66%,transparent) 0%,
    color-mix(in srgb,var(--color3) 46%,transparent) 45%,
    color-mix(in srgb,var(--color3) 22%,transparent) 100%);
}
@media (max-width:767.98px){
  .hero .scrim{ background:color-mix(in srgb,var(--color3) 55%,transparent); }
}
/* Parlare carries long descenders — at hero scale they collide with the H1. */
.hero-inner .script{ line-height:1.26; margin-bottom:var(--sp-sm); }

/* --- Treepl form component: THE V2 SKIN, PAINTED ONTO THE SST'S OWN FLOATING LABEL -------
   Craig, 2026-09-10, rejecting the previous version of this block: "re-creating the floating
   label on the existing inputs doesn't do it, that looks terrible. Instead, you need to
   utilize the original style guide inputs EXACTLY as they were, then just layer the css for
   the bg color, border color (bottom only) and border animation (bottom border animation on
   hover). The font size, the label size and placement needs to remain the same as the SST."

   SO THIS BLOCK IS PAINT, NOT GEOMETRY, AND THAT IS THE WHOLE RULE.
   The version before it re-implemented .form-floating from scratch - its own label
   positioning, its own scale(.75), its own padding, its own derived height - and measured
   2026-09-10 it MOVED 45 computed properties on the guide's own §8 input: font-family,
   font-size 27.6 -> 16.32, line-height, height 82.8 -> 63.0, padding, transform-origin.
   Recreating a floating label cannot land close enough to the real one, and it does not have
   to: Bootstrap already ships it and the SST already tunes it. This block now declares
   NOTHING that can move the label or the type. If you are about to add font-size,
   line-height, padding, height, transform, top/left or anything on > label here, stop -
   that is the mistake this comment exists to prevent.

   WHAT IT IS ALLOWED TO TOUCH, and nothing else:
     · background-color        the field reads as ivory paper, not a white box
     · border                  bottom hairline ONLY - top/right/left and the radius go
     · background-size         the gold hairline that runs in from the left on hover/focus
     · box-shadow / outline    Bootstrap's blue focus ring, removed - it is a border effect
     · label::after            painted --bs-body-bg (white) to notch the TOP border; with no
                               top border it has no job and would sit as a white slab on the
                               ivory field. Made TRANSPARENT rather than display:none, so it
                               keeps its box and cannot shift the label a pixel.
   Verifier: 00_resources/ai-config/scripts/swc-verify-input-skin.mjs — it reads the guide
   twice, once with sg-v2-layer.css disabled, and FAILS on any property outside that list.

   Scoped to both form hosts: .estate-form is the page forms, #review-feedback is the
   Request-a-Change modal in the review bar. The same rules reach the style guide through
   css/swc/sg-v2-layer.css, which re-hosts this family onto #tl-style-guide-mount.
   If .field changes, change this with it - estate.css:727-753 is the same skin on the
   non-Bootstrap input and the two must stay in step. */
:is(.estate-form,#review-feedback) .form-floating{
  margin-bottom:var(--sp-sm);
  /* THE TEXTAREA VEIL, RECOLORED — AND IT LIVES HERE, BESIDE THE BACKGROUND IT MUST MATCH.
     Craig, 2026-09-10: "the text area has a fade over the top to prevent the text from
     running overlap on the repositioned label. Always make sure to update the color for
     that fade."
     A textarea's copy scrolls UP THROUGH its own padding and would paint under the floated
     label, so the SST fades the top 34px of the field out from underneath it -
     `.form-floating:has(> textarea.form-control)::before` in
     shared/style-guide/v1/style-guide.css:2348. That veil is A GRADIENT OF THE FIELD'S OWN
     COLOR, so the moment this block repaints the field it must repaint the veil too, or a
     white band sits on an ivory field. Which is exactly what happened.
     NOTHING IS RECREATED HERE. The SST's own comment says "On a tinted field, set --fl-veil
     on the wrapper", so this is its documented hook, pointed at the same token the field
     uses three rules below. The SST keeps owning the geometry, the gradient stops, the
     :has() gate and the gutter; this says only WHICH COLOR to fade from. --fl-veil-tint is
     the second layer it composites on top and defaults to var(--InputBgColor) - the SST's
     white field - so leaving it would repaint the white this skin just removed.
     ANY future change to the field's background-color changes this line in the same edit.
     One decision, two declarations, deliberately adjacent so it is hard to miss. */
  --fl-veil:var(--PageBgColor);
  --fl-veil-tint:transparent;
  /* NO RIGHT GUTTER. The SST defaults --fl-veil-gutter to 15px so the veil does not cover a
     classic scrollbar. Measured 2026-09-10 on both surfaces with 16 lines typed and the field
     scrolled: `offsetWidth - clientWidth - borders` = 0.0px, i.e. overlay scrollbars, nothing
     to leave room for - so that 15px was simply an uncovered column of live field, and a
     scrolled line's last glyph paints in it at the top-right corner. It is the SST's own
     token, set to 0 here rather than the rule being edited. If this site ever renders classic
     scrollbars, put 15px back. */
  --fl-veil-gutter:0px;
}
/* ONE VEIL COLOR HERE, BECAUSE ON /v2 THE FIELD ONLY EVER HAS ONE.
   Measured 2026-09-10 across rest / hover / focus / typing / clicked-away: on /v2/plan the
   field is #F5EFE8 in ALL FIVE states, so the veil is too and there is nothing to switch.
   The guide is the surface with two backgrounds - t_tlc-styles.css repaints its field
   #FFFFFF on hover and focus with !important - and the two state rules that follow the field
   there are emitted by swc-build-sg-v2-layer.mjs, scoped to #tl-style-guide-mount, NOT from
   here. That split is deliberate and it is the whole lesson of this round: the first attempt
   put the state rules in this file keyed on var(--InputBgColorHover, var(--PageBgColor)),
   assuming the token would be unset on /v2 and fall back. It is NOT unset - the CM pipeline
   emits #FFFFFF for it on both surfaces - so the fallback never fired and /v2 got a WHITE
   veil on an ivory field, the same defect inverted. A token being DEFINED says nothing about
   whether any rule uses it to paint. Match the surface, not the token. */

/* THE VEIL ITSELF, PORTED VERBATIM SO /v2 HAS ONE AT ALL.
   Measured 2026-09-10: /v2/plan had NO veil in any state. The rule that draws it lives in
   shared/style-guide/v1/style-guide.css (md5 8b01bf0fdd0c33875a345d483e207dfc, lines
   2346-2362) and that sheet is loaded ONLY on /ops/style-guide. /v2 is on Estate Template,
   which links bootstrap + hover-min + this file and no shared TLC sheet at all, so there was
   nothing to inherit - a textarea's copy scrolled straight under its floated label on a live
   client form.
   COPIED, NOT REWRITTEN. Craig, 2026-09-10: "they should be using the exact same CSS and HTML
   so if we make any more changes they are updated here on the SC custom css." Every
   declaration below is byte-identical to the SST's - the 1px insets, the 15px gutter default,
   the 34px height, z-index 2 under the label's 3, the 0/76%/100% stops, even the
   `border-radius: 4px 0 0 0` that this site's square fields do not need (it is the field's own
   color, so it cannot show). The ONLY change is the scope prefix. If the SST's veil changes,
   re-copy it from that file rather than editing these numbers.
   THE TWO STATE RULES ABOVE FEED IT. They set --fl-veil; this draws it. */
:is(.estate-form,#review-feedback) .form-floating:has(> textarea.form-control) { position: relative; }
:is(.estate-form,#review-feedback) .form-floating:has(> textarea.form-control) > label { z-index: 3; }
/* THE ONE DECLARED DIVERGENCE FROM THE COPY ABOVE: top and left are 0, not 1px.
   Craig, 2026-09-10: "there is a small artifact sneaking out the top of the input textarea
   when filled out with text ... avoid the OB (out-of-bounds)."
   The SST insets the veil by 1px because ITS field carries a 1px border for the veil to tuck
   inside. This skin removes that border - bottom hairline only - so the same 1px became a
   bare strip of LIVE FIELD above the veil, and a textarea scrolls its copy straight through
   it. Measured 2026-09-10, 14 lines typed, scrollTop 853: exactly "1.0px of UNCOVERED field"
   on BOTH surfaces, rendering as a sliver of the previous line above the label.
   Zero is right HERE and 1px stays right in the SST - the difference is the border, not a
   disagreement, so this is NOT pushed back upstream. Every other declaration in this rule is
   still byte-identical to style-guide.css:2348.
   Verifier: swc-verify-textarea-veil.mjs asserts the uncovered strip is 0px. */
:is(.estate-form,#review-feedback) .form-floating:has(> textarea.form-control)::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: var(--fl-veil-gutter, 15px);
  height: 34px;
  z-index: 2;
  pointer-events: none;
  border-radius: 4px 0 0 0;
  background: linear-gradient(to bottom,
    var(--fl-veil, #fff) 0,
    var(--fl-veil, #fff) 76%,
    transparent 100%);
}
/* Treepl sometimes nests .form-floating inside a .form-group and both carry the bottom
   margin - a double space between two fields and a single one elsewhere. Outer keeps it. */
:is(.estate-form,#review-feedback) .form-group > .form-floating{ margin-bottom:0; }
/* .estate-form .hide is (0,2,0) and the :is() here carries an id, so anything declared on
   .form-floating in this block outranks it. An earlier version declared display:flex and
   un-hid the two `form-floating hide` wrappers (FirstName / LastName) on the Experience
   Guide Request form - they rendered on /v2/plan for a month. Never declare display on
   .form-floating; this restates the hide at a weight that cannot lose. */
:is(.estate-form,#review-feedback) .form-floating.hide,
:is(.estate-form,#review-feedback) .form-floating[hidden]{ display:none; }

/* THE DATE FIELD IS NOT IN A .form-floating, WHICH IS WHY THE SKIN MISSED IT.
   Craig, 2026-09-10: "we did forget the date-time input, they need to be modified to fit color
   bg and animations."
   Measured in the form source — Content/Forms/Experience Guide Request.html:123-126 — the date
   field is `<div class="datepicker-input"><input type="date" class="form-control hasDatepicker">`
   with its <label> deliberately commented out (`<!-- HIDE ... -->`) and a placeholder instead.
   So it has no floating label to skin, and it never matched `.form-floating > .form-control`.
   It joins the SAME selector list below rather than getting a block of its own, so the two can
   never drift — one change, both fields. PAINT ONLY, exactly like the rest of this skin: no
   geometry, no padding, and NO floating label added, because that label is hidden on purpose
   and adding one would be a design change nobody asked for. */
:is(.estate-form,#review-feedback) .form-floating > .form-control,
:is(.estate-form,#review-feedback) .form-floating > .form-select,
:is(.estate-form,#review-feedback) .datepicker-input > .form-control,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker,
:is(.estate-form,#review-feedback) input[type="date"].form-control,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control{
  background-color:var(--PageBgColor);
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat;
  background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  border:0;
  border-bottom:var(--BorderBrandWidth) solid var(--color2);
  border-radius:var(--RadiusBrand);
  box-shadow:none;
  transition:background-size .42s cubic-bezier(.35,0,.65,1), border-bottom-color .3s ease;
}
:is(.estate-form,#review-feedback) .form-floating > .form-control:focus,
:is(.estate-form,#review-feedback) .form-floating > .form-control:hover,
:is(.estate-form,#review-feedback) .form-floating > .form-select:focus,
:is(.estate-form,#review-feedback) .form-floating > .form-select:hover,
:is(.estate-form,#review-feedback) .datepicker-input > .form-control:focus,
:is(.estate-form,#review-feedback) .datepicker-input > .form-control:hover,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker:focus,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker:hover,
:is(.estate-form,#review-feedback) input[type="date"].form-control:focus,
:is(.estate-form,#review-feedback) input[type="date"].form-control:hover,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control:focus,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control:hover{
  background-size:100% var(--BorderBrandWidth);
  box-shadow:none;
  outline:none;
  /* THE BOX THAT APPEARS ON CLICK IS CREAM, SO IT BARELY SHOWS. Craig, 2026-09-10:
     "on click inside the input, the border appears on top and sides... is it possible to use
      the cream color for this border only on click inside so it will barely show up."
     The base rule above says `border:0`, and it LOSES: t_tlc-styles.css sets
     `border: var(--InputBorderWidth) … !important` on `textarea:focus` and `.form-control:focus`,
     and --InputBorderWidth is the four-value `1px 1px 1px 1px`, so a full box comes back on
     every focus. An !important declaration cannot be beaten by a non-important one at ANY
     specificity, so matching the !important here is the fix, not a shortcut (contract §3).
     Only the three sides he named are recolored — the bottom keeps the stroke that is the
     whole component, and it is restated !important for the same reason: the shorthand above
     would otherwise take the bottom colour with it. --color5 #EFE7DE against the field's own
     --PageBgColor #F5EFE8 is the "barely show up" he asked for. */
  border-top-color:var(--color5) !important;
  border-right-color:var(--color5) !important;
  border-left-color:var(--color5) !important;
  border-bottom-color:var(--color3) !important;
}

/* A SELECT MUST STILL LOOK LIKE A SELECT. Craig, 2026-09-10: "Select menus must have a caret
   or down triangle applied to all so User knows it's a select menu."
   It was OUR skin that removed it. `background-image` is ONE property, and the rule above
   sets it to the gold underline gradient — which silently discarded Bootstrap's caret, because
   that caret IS a background-image on .form-select. Nothing errored; the control just stopped
   announcing itself. Measured on the guide: background-image came back
   `linear-gradient(rgb(194,161,92), rgb(194,161,92))` and nothing else.
   Both layers now, caret first so it paints over the underline. The SVG is copied byte-for-byte
   out of bootstrap.min.css's own .form-select rule, including its `%23343a40` stroke — a data
   URI cannot read a custom property, so the one hex in this file is that stroke, and it is
   Bootstrap's, not a colour invented here. Position/size are Bootstrap's too, so the caret
   lands exactly where a stock select puts it and the 2.25rem right padding still fits it. */
:is(.estate-form,#review-feedback) .form-floating > .form-select{
  background-image:
    linear-gradient(45deg, transparent 50%, var(--color3) 50%),
    linear-gradient(135deg, var(--color3) 50%, transparent 50%),
    linear-gradient(var(--colorGold),var(--colorGold));
  background-position:right 19px center, right 14px center, left bottom;
  background-size:5px 5px, 5px 5px, 0 var(--BorderBrandWidth);
  background-repeat:no-repeat, no-repeat, no-repeat;
}
:is(.estate-form,#review-feedback) .form-floating > .form-select:focus,
:is(.estate-form,#review-feedback) .form-floating > .form-select:hover{
  background-size:5px 5px, 5px 5px, 100% var(--BorderBrandWidth);
}

/* THE PLACEHOLDER IS THE RESTING FLOATING LABEL, AND IT IS A BRAND TOKEN NOW.
   Craig, 2026-09-10: "The placeholders are too light gray with the addition of the background
   color. These need to be darker charcoal solid color, color3."
   The cream field is what exposed it — the text did not change, its ground did. Measured on the
   guide: `t_tlc-styles.css .form-floating label{ color:var(--InputPlaceholderColor) }` at
   (0,1,1) was winning with `rgba(0,0,0,.35)`, 35% black, and the real `::placeholder` is
   `rgba(0,0,0,0)` because the floating pattern hides it and lets the label do the work. So both
   are set here: the label for a .form-floating, and ::placeholder for the fields that have no
   floating label (the date pair). Solid, no alpha, as asked.
   ONLY THE RESTING STATE. The floated small-caps label — the one that sits above a filled value
   — measures rgba(0,0,0,.65) from a different rule and is not touched; he named the
   placeholders. */
:is(.estate-form,#review-feedback) .form-floating > label{
  color:var(--color3);
}
/* NOT INSIDE A .form-floating. 2026-09-22 09:30 MDT. The note above already says this rule is
   for "the fields that have no floating label (the date pair)" — the SELECTOR did not say it, so
   it matched every field. Bootstrap makes the placeholder transparent inside .form-floating
   (`.form-floating > .form-control::placeholder{color:transparent}`, (0,2,1)); this rule was
   (0,2,1) as well and estate.css loads LATER, so it won and every floating field painted its
   placeholder UNDER its own small-caps label. Craig screenshotted the result: "Full Name" sitting
   across "FULL NAME*" on six fields. `:not(.form-floating)` takes it to (0,3,1) and confines it
   to the fields it was always meant for. */
/* BARE HOST FORM, for the same reason as the padding rule below it: `:not(.form-floating)`
   contains the literal string `.form-floating`, so the generator's substring test re-hosted
   this rule and it leaked into §8 of the style guide, where it had never been before. The
   bare form keeps it on /v2 only. */
.estate-form :not(.form-floating) > .form-control::placeholder,
.estate-form :not(.form-floating) > .form-select::placeholder,
#review-feedback :not(.form-floating) > .form-control::placeholder,
#review-feedback :not(.form-floating) > .form-select::placeholder{
  color:var(--color3);
  opacity:1;
}

/* ROOM FOR THE FLOATED LABEL. The .estate-form `padding` SHORTHAND on .form-control beat
   Bootstrap's `.form-floating > .form-control{padding:1rem .75rem}`, so a text input had
   `8px 0` and a typed value landed on top of the label. The SELECT beside it never had the
   problem because estate.css does not restate padding for .form-select, so it kept Bootstrap's
   floating values — measured on /v2/plan at root 16.32px: 26.52px / 10.2px, i.e. 1.625rem and
   .625rem. Those exact values are copied here rather than chosen. Horizontal stays 0: these
   fields are a bottom hairline, not a box. Textarea is excluded — its top strip is covered by
   the measured 34px veil in .form-floating:has(> textarea.form-control)::before and changing
   its padding moves the text out from under that veil. */
/* THE FLOATING PADDING NOW COMES FROM THE SST, NOT FROM HERE. css/swc/estate-sst-inputs.css
   carries sst-styles.css's own `.form-floating > .form-control:focus, :not(:placeholder-shown)
   { padding-top:1.625rem; padding-bottom:.925rem }`, which is the rule §8 renders. The hand
   block that stood here set 1.625rem/0/.625rem and would now be a second, slightly different
   source for the same thing. Removed 2026-09-22. */

/* AND THE DATE PICKERS. Craig, 2026-09-10, for the second time in one session:
   "including the DatePickers... always include Date Pickers in the input changes."
   Standing instruction, not a one-off — every change to an input in this file gets the date
   family in the SAME pass, or it ships half done. The date pair is easy to miss because it is
   not a .form-floating and has no label, so neither the label rule nor ::placeholder reaches it.

   A NATIVE DATE FIELD DOES NOT PAINT ITS TEXT FROM `color` ALONE. Chrome renders the value out
   of a shadow tree — ::-webkit-datetime-edit and one field per segment — and the segments keep
   their own ink, which is why the field measured rgb(33,37,41) (Bootstrap's body colour, via
   .form-control) while the mm/dd/yyyy on screen read lighter still. Setting the element's
   `color` fixes the separators and nothing else. Every segment is listed, plus the wrapper, so
   a filled date and an empty one are the same charcoal.
   `-webkit-` prefixed pseudo-elements: an unknown one in a GROUPED selector invalidates the
   whole rule, so these are their own block and not appended to the list above. */
:is(.estate-form,#review-feedback) .datepicker-input > .form-control,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker,
:is(.estate-form,#review-feedback) input[type="date"].form-control,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control{
  color:var(--color3) !important;
}
:is(.estate-form,#review-feedback) input[type="date"].form-control::-webkit-datetime-edit,
:is(.estate-form,#review-feedback) input[type="date"].form-control::-webkit-datetime-edit-text,
:is(.estate-form,#review-feedback) input[type="date"].form-control::-webkit-datetime-edit-month-field,
:is(.estate-form,#review-feedback) input[type="date"].form-control::-webkit-datetime-edit-day-field,
:is(.estate-form,#review-feedback) input[type="date"].form-control::-webkit-datetime-edit-year-field,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-text,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-month-field,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-day-field,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-year-field,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-hour-field,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-minute-field,
:is(.estate-form,#review-feedback) input[type="datetime-local"].form-control::-webkit-datetime-edit-ampm-field{
  color:var(--color3);
}

/* THE DATE NEEDS ROOM FOR ITS OWN ICON ON /v2, AND ONLY THE GUIDE WAS GIVING IT ANY.
   2026-09-22. sst-styles/t_tlc-styles sets `.datepicker-input input{padding-right:45px}` and then
   ZEROES it again two rules later (the 45px is commented out and padding-right:0 replaces it —
   the literal is not repeated here because a nested comment-close would end THIS comment and
   eat the rule under it, which is exactly what happened on the first attempt), so the SST's own
   date has no gutter. §8 looks right only because the style guide's sheet adds one —
   turnerlee.com/shared/style-guide/v1/style-guide.css `.sg-page .datepicker-input .form-control
   {padding-right:55px!important}`, quoted in the note below. /v2 does not load that sheet, so its
   date painted the value straight under the 45px icon: measured padding-right 0px against §8's
   55px, and the icon sat on top of "mm/dd/". The gutter is a property of the component, not of
   the guide, so it is stated here for the two surfaces that need it. Bare host form on purpose —
   the guide already has its own copy and swc-build-sg-v2-layer.mjs must not lift a second one.
   !important because the rule being beaten has it. */
.estate-form .datepicker-input input,
#review-feedback .datepicker-input input{
  padding-right:55px !important;
}

/* THE DATE FIELDS, AND THE ONE REASON THEY NEED !important. Craig, 2026-09-10:
   "date pickers must also have the same color, bottom stroke and animations applied to them."
   They are already in the selector list above and it was not enough. The SST style guide's own
   sheet pins them, measured at
   turnerlee.com/shared/style-guide/v1/style-guide.css:1364-1376 —
     .sg-page .datepicker-input .form-control{
       background:#fff!important; border:1px solid rgba(0,0,0,.25)!important;
       border-radius:.25rem!important; height:4.5rem!important; padding-right:55px!important; }
   An !important declaration cannot be beaten by a non-important one at ANY specificity, so our
   (1,3,0) rule lost silently — the field stayed white with a 1px box at 4.6px radius. Proven,
   not assumed: an INLINE `background-color:#F5EFE8` on the element also computed to white.
   Matching the !important is therefore the fix, not a shortcut (contract §3).

   PAINT ONLY. `height`, `padding`, `padding-right:55px`, `font-size` and `line-height` are that
   component's GEOMETRY — the 55px is clearing the guide's own 45px calendar panel — and none of
   it is touched here. Three properties, the three Craig named: the cream field, the bottom
   stroke, and the gold fill that animates across it.
   `background` is a SHORTHAND in the rule being beaten, so every background longhand has to be
   restated here or `#fff` takes the gradient with it.
   The !important also lands on /v2, where nothing competes for these properties and the values
   are identical — inert there, and it keeps estate.css the single source the generator lifts. */
:is(.estate-form,#review-feedback) .datepicker-input > .form-control,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker{
  background-color:var(--PageBgColor) !important;
  background-image:linear-gradient(var(--colorGold),var(--colorGold)) !important;
  background-repeat:no-repeat !important;
  background-position:left bottom !important;
  background-size:0 var(--BorderBrandWidth) !important;
  border:0 !important;
  border-bottom:var(--BorderBrandWidth) solid var(--color2) !important;
  border-radius:var(--RadiusBrand) !important;
}
:is(.estate-form,#review-feedback) .datepicker-input > .form-control:focus,
:is(.estate-form,#review-feedback) .datepicker-input > .form-control:hover,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker:focus,
:is(.estate-form,#review-feedback) .form-control.hasDatepicker:hover{
  background-size:100% var(--BorderBrandWidth) !important;
  border-top-color:var(--color5) !important;
  border-right-color:var(--color5) !important;
  border-left-color:var(--color5) !important;
  border-bottom-color:var(--color3) !important;
}
/* The white notch, killed. Transparent, not display:none - see the note above. */
:is(.estate-form,#review-feedback) .form-floating > label::after{
  background-color:transparent !important;
}

/* A RADIO IS ROUND. The shared box rule below takes border-radius from --RadiusBrand, which
   is 0 on /v2 — so every radio on the inquiry form rendered as a square and read as a
   checkbox. Radios only; the checkboxes are meant to be square. 2026-09-22 09:45 MDT. */
.estate-form input[type=radio],
.estate-form .form-check-input[type=radio]{ border-radius:50%; }

/* .form-select.xs — PORTED FROM t_tlc-styles.css, VERBATIM. The Estate Template does not link
   that sheet, so the STATE select lost the only rule that gave it width: its wrapper is
   `min-width30 flex-shrink-1` (min-width:30px) with no basis, so with no padding to widen its
   min-content box it shrank to exactly 30px and became unusable — measured on /v2/plan.
   Same class of bug as the review bar's missing `.stickyButtons` geometry: this form was built
   for the Inner Template and quietly depends on that sheet's utilities. `min-width30`, `top50`,
   `bottom30` and `right10pad` were already ported; this one was missed. Scoped to .estate-form
   so it cannot become a site-wide utility by accident, and the !important is carried over
   because the original has it — Bootstrap's own .form-select padding would otherwise win. */
.estate-form .form-floating > .form-select.xs{
  padding-right:2rem !important;
  margin-right:2.5rem !important;
}

/* checkboxes and radios keep their own box */
.estate-form input[type=checkbox],.estate-form input[type=radio],
.estate-form .form-check-input{
  width:1em; height:1em; background-image:none;
  border:var(--BorderBrandWidth) solid var(--color2); border-radius:var(--RadiusBrand);
  padding:0; margin-top:.35em;
}
.estate-form .form-check-input:checked{ background-color:var(--color3); border-color:var(--color3); }
.estate-form .form-check{ display:flex; align-items:flex-start; gap:var(--sp-xxs); }
.estate-form .form-check-label,.estate-form .form-Radio-label{
  font-family:var(--BodyFont); font-size:.9375rem; font-weight:400;
  text-transform:none; letter-spacing:0; color:var(--FontColor); margin:0;
}
.estate-form .form-group{ margin-bottom:var(--sp-sm); }
.estate-form .datepicker-input__icon,.estate-form .fa-calendar{ color:var(--color1); }
.estate-form .color2{ color:var(--text-accent); }
.estate-form .font140{ font-size:1.4em; }
.estate-form .font90{ font-size:.9em; }
.estate-form .hide{ display:none; }
.estate-form .min-width30{ min-width:30px; }
.estate-form .bottom-10{ margin-bottom:-10px; }
.estate-form .bottom15pad{ padding-bottom:15px; }
.estate-form .bottom20{ margin-bottom:20px; }
.estate-form .bottom30{ margin-bottom:30px; }
.estate-form .bottom60{ margin-bottom:60px; }
.estate-form .bottom30pad{ padding-bottom:30px; }
.estate-form .bottom100pad{ padding-bottom:100px; }
.estate-form .top20pad{ padding-top:20px; }
.estate-form .top50{ margin-top:50px; }
.estate-form .right10pad{ padding-right:10px; }

/* Eyebrow on any dark or photographic surface: --color2 measured 4.21:1 on
   charcoal, under the 4.5:1 floor for 13px caps. Use the AA-safe reverse tint. */
.eyebrow-rev,.hero-inner .eyebrow,.rev .eyebrow,.sec-dark .eyebrow,.band-inner .eyebrow{
  color:color-mix(in srgb,var(--reverse1) 82%,var(--color3));
}

/* --- Sign in / member chip in the footer legal row --- */
.estate-signin{ display:inline-flex; align-items:center; gap:var(--sp-xs); }
.estate-signin a{
  font-family:var(--LabelFont); font-size:.75rem; text-transform:uppercase;
  letter-spacing:.12em; text-decoration:none;
  color:color-mix(in srgb,var(--reverse1) 78%,var(--color3));
  display:inline-block; padding-bottom:3px;
  background-image:linear-gradient(var(--colorGold),var(--colorGold));
  background-repeat:no-repeat; background-position:left bottom;
  background-size:0 var(--BorderBrandWidth);
  transition:color .3s ease, background-size .42s cubic-bezier(.35,0,.65,1);
}
.estate-signin a:hover,.estate-signin a:focus-visible{
  color:var(--reverse1); background-size:100% var(--BorderBrandWidth);
}
.estate-signin-name{ letter-spacing:.08em; text-transform:none; }

/* the header only goes transparent once JS confirms a hero is present */
.site-header{ background:var(--PageBgColor); border-bottom-color:var(--BorderBrandColor); }
.site-header.over{ background:transparent; border-bottom-color:transparent; }
html.has-hero .site-header:not(.solid){ background:transparent; border-bottom-color:transparent; }
