/* 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{
  --color1: #242021;        /* Charcoal    — primary: buttons, headlines, dark sections */
  --color2: #7B6E46;        /* Olive Earth — accent: eyebrows, active nav, ornaments */
  --color3: #6D775F;        /* Sage Green  — secondary accent, quiet UI */
  --color4: #8A8178;        /* Warm Taupe  — borders and hover tones ONLY, never small text */
  --color5: #EFE7DE;        /* Soft Cream  — cards, alternating section fills */
  --colorGoldBase: #C2A15C; /* Antique Gold — interaction highlight only, never type */

  /* Surfaces + type color */
  --PageBgColor: #F5EFE8;   /* Warm Ivory — default page background */
  --FontColor:   #242021;
  --reverse1:    #F5EFE8;   /* 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(--color1));

  /* AA-safe derivations. --color2 and --color4 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(--color4) 55%, var(--color1));  /* ~6:1 on ivory */
  --text-accent:     color-mix(in srgb, var(--color2) 82%, var(--color1));  /* ~5.4:1 on ivory */
  --text-muted-rev:  color-mix(in srgb, var(--reverse1) 78%, var(--color1)); /* ~9:1 on charcoal */

  /* Buttons */
  --PrimaryButtonColor:        var(--color1);
  --PrimaryButtonHoverColor:   #4A3F35;   /* charcoal warmed toward taupe */
  --SecondaryButtonColor:      transparent;
  --SecondaryButtonHoverColor: var(--color4);
  --DisabledColor:             #DCD2C6;
}

/* ===== 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: rgba(36,32,33,.15);
  --BorderBrandWidth: 1px;
  --btn-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(--color2);
  /* 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,.btn-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(--color2) 82%,var(--color1));
  margin:0 0 var(--sp-xs);
  display:block;
}
.eyebrow-rev{ color:var(--color4); }

code,kbd,samp,pre{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.9em;
  color:color-mix(in srgb,var(--color2) 82%,var(--color1));
  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(--color1));
  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(--color4) 55%,var(--color1)); }
.caps{ font-family:var(--LabelFont); text-transform:uppercase; letter-spacing:.14em; }
.muted{ color:color-mix(in srgb,var(--color4) 55%,var(--color1)); }
.accent{ color:var(--color2); }

a{ color:color-mix(in srgb,var(--color2) 82%,var(--color1)); text-decoration-thickness:1px; text-underline-offset:.22em; text-decoration-color:var(--colorGold); }
a:hover{ color:var(--color1); text-decoration-color:var(--colorGold); }
.rev a{ color:var(--reverse1); }
.rev a:hover{ color:var(--color4); }

: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 */
.btn: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(--color1); 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; }
.btn{
  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;
  --btn-fill:transparent;
  --btn-border:transparent;
  transition:color .3s ease;
}
/* Bootstrap 5 loads ahead of this sheet and paints the button ELEMENT on
   :hover / :focus-visible / :active. `.btn:hover` is (0,2,0) and beats our
   `.btn{ background:none }`, so .btn-secondary dropped a #5c636a slab over the
   ::before layer and swallowed its own label. The element carries the label and
   nothing else; only ::before ever draws fill or edge. background-COLOR only —
   .btn-ghost's gold background-image has to survive this. */
/* Selector-for-selector mirror of every Bootstrap rule that paints a button, at the
   SAME specificity or higher, sitting later in the cascade. The first pass listed the
   plain forms (.btn:hover, .btn:active) and lost the ACTIVE state, because Bootstrap
   writes that one as `:not(.btn-check) + .btn:active` — (0,3,0) against our (0,2,0),
   so #5C636A came back the moment a button was pressed. Do not "simplify" this list;
   each line exists because Bootstrap has a matching one.
   background-COLOR only — .btn-ghost's gold background-image and the hover shine both
   ride background-image and must survive. */
.btn,
.btn:hover,
.btn:focus,
.btn:focus-visible,
.btn:active,
.btn.active,
.btn.show,
.btn:disabled,
.btn.disabled,
.btn-check + .btn:hover,
.btn-check:checked + .btn,
.btn-check:focus-visible + .btn,
:not(.btn-check) + .btn:active,
.btn:first-child:active,
.btn-check:checked + .btn:focus-visible,
:not(.btn-check) + .btn:active:focus-visible,
.btn:first-child:active:focus-visible,
.btn.active:focus-visible,
.btn.show:focus-visible,
fieldset:disabled .btn{
  background-color:transparent;
  border-color:transparent;
  box-shadow:none;
}
.btn::before{
  content:"";
  position:absolute; inset:0; z-index:-1;
  border-radius:var(--RadiusBrand);
  background-color:var(--btn-fill);
  border:var(--BorderBrandWidth) solid var(--btn-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;
}
.btn:hover::before,.btn:focus-visible::before{
  transform:scale(var(--btn-grow,1.04));
  border-width:calc(var(--BorderBrandWidth) / var(--btn-grow,1.04));
  border-color:var(--colorGold);
}
.btn:active::before{
  transform:scale(1.01);
  border-width:calc(var(--BorderBrandWidth) / 1.01);
  transition-duration:.1s;
}
@media (prefers-reduced-motion:reduce){
  .btn::before{ transition-duration:.01ms; }
  .btn:hover::before,.btn:focus-visible::before{ transform:none; border-width:var(--BorderBrandWidth); }
}

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

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

.btn-secondary{
  color:var(--color1);
  --btn-fill:var(--SecondaryButtonColor);
  --btn-border:var(--color1);
}
.btn-secondary:hover,.btn-secondary:focus-visible{ color:var(--color1); }

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

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

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

.btn.disabled,.btn:disabled{
  color:var(--color4);
  --btn-fill:var(--DisabledColor);
  --btn-border:var(--DisabledColor);
  pointer-events:none;
}
.btn.disabled::before,.btn:disabled::before{ transform:none; }

/* Ghost — no box at all; the gold rule runs in and the arrow slides */
.btn-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(--color1);
  align-self:flex-start;
  isolation:auto;
  transition:color .3s ease, background-size .42s cubic-bezier(.35,0,.65,1);
}
.btn-ghost::before{ display:none; }
.btn-ghost .arw{ display:inline-block; transition:transform .45s cubic-bezier(.22,.61,.36,1); }
.btn-ghost:hover,.btn-ghost:focus-visible{
  color:color-mix(in srgb,var(--color2) 82%,var(--color1));
  background-size:100% var(--BorderBrandWidth);
}
.btn-ghost:hover .arw,.btn-ghost:focus-visible .arw{ transform:translateX(8px); }
.rev .btn-ghost{ color:var(--reverse1); }
.rev .btn-ghost:hover,.rev .btn-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. `.btn{ isolation:isolate }`
   makes the button a stacking context, and inside one the negative-z children paint in
   step 2 — so `.btn::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 `.btn-t` for exactly that; if the
   script never runs there is simply no shine and nothing else changes. */
.btn-t{ display:inline-block; }
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .btn:not(.btn-ghost):hover .btn-t,
  .btn:not(.btn-ghost):focus-visible .btn-t{
    background-image:linear-gradient(100deg,
      currentColor 0 40%,
      color-mix(in srgb,var(--colorGold) 88%,#FFF6E2) 47%,
      #FFF3D6 50%,
      color-mix(in srgb,var(--colorGold) 88%,#FFF6E2) 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:btn-shine .9s cubic-bezier(.33,0,.24,1) 1;
  }
}
@keyframes btn-shine{ from{ background-position:100% 0; } }
@media (prefers-reduced-motion:reduce){
  .btn:not(.btn-ghost):hover .btn-t,
  .btn:not(.btn-ghost):focus-visible .btn-t{
    background-image:none; -webkit-text-fill-color:currentColor; animation:none;
  }
}
.btn-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(--color2); border:0; margin:0; }
.ornament-center{ margin-inline:auto; }

/* --- Photo placeholders --- */
.ph{
  position:relative;
  background:
    repeating-linear-gradient(135deg,
      color-mix(in srgb,var(--color4) 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(--color3) 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(--color1);
  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(--color2); }
.ph-detail .ph-label::before{ content:"◇ detail shot · "; color:var(--color3); }
.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 .btn-ghost,.card-ed .btn{ 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 .btn 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 .btn::before,
.card-ed:focus-within .btn::before{
  transform:scale(var(--btn-grow,1.04));
  border-width:calc(var(--BorderBrandWidth) / var(--btn-grow,1.04));
  border-color:var(--colorGold);
}
.card-ed:hover .btn-primary::before{ background-color:var(--PrimaryButtonHoverColor); }
.card-ed:hover .btn-quiet::before{ background-color:color-mix(in srgb,var(--color5) 60%,var(--PageBgColor)); }
.sec-cream .card-ed:hover .btn-quiet::before{ background-color:color-mix(in srgb,var(--PageBgColor) 60%,var(--color5)); }
.card-ed:hover .btn-ghost,
.card-ed:focus-within .btn-ghost{
  color:color-mix(in srgb,var(--color2) 82%,var(--color1));
  background-size:100% var(--BorderBrandWidth);
}
.rev .card-ed:hover .btn-ghost,.rev .card-ed:focus-within .btn-ghost{ color:var(--reverse1); }
.card-ed:hover .btn-ghost .arw,.card-ed:focus-within .btn-ghost .arw{ transform:translateX(8px); }
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .card-ed:hover .btn:not(.btn-ghost) .btn-t{
    background-image:linear-gradient(100deg,
      currentColor 0 40%,
      color-mix(in srgb,var(--colorGold) 88%,#FFF6E2) 47%,
      #FFF3D6 50%,
      color-mix(in srgb,var(--colorGold) 88%,#FFF6E2) 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:btn-shine .9s cubic-bezier(.33,0,.24,1) 1;
  }
}
@media (prefers-reduced-motion:reduce){
  .card-ed:hover .btn::before,.card-ed:focus-within .btn::before{
    transform:none; border-width:var(--BorderBrandWidth);
  }
  .card-ed:hover .btn:not(.btn-ghost) .btn-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(--color4) 55%,var(--color1));
}

/* --- Icons --- */
.ico{ width:30px; height:30px; display:block; stroke:var(--color2); 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(--color4); }
.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(--color4) 55%,var(--color1));
}
.stars{ letter-spacing:.3em; color:var(--color2); 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(--color1);
}
.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(--color4);
  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(--color1);
}
.field-hint{ font-size:.75rem; color:color-mix(in srgb,var(--color4) 55%,var(--color1)); }

/* ===== 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(--color1); color:var(--reverse1); }
.sec-dark .caption,.sec-dark .muted{ color:color-mix(in srgb,var(--color4) 55%,var(--color1)); }
.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(--color1); 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(--color1);
  background-size:100% var(--BorderBrandWidth);
}
.nav-list a[aria-current="page"]{
  color:var(--color2);
  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 .btn{ 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(--color1);
  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(--color1); 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 .btn{ 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(--color1) 70%,transparent); color:var(--reverse1); border-top-color:color-mix(in srgb,var(--reverse1) 20%,transparent); }
.hero .ph-req .ph-label::before{ color:var(--color4); }
.scrim{ position:absolute; inset:0; background:color-mix(in srgb,var(--color1) 45%,transparent); }
.scrim-soft{ background:color-mix(in srgb,var(--color1) 35%,transparent); }
.scrim-strong{ background:color-mix(in srgb,var(--color1) 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(--color1) 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(--color1); 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(--color4); 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(--color4); 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:20px; height:20px; }
.social-row a:hover .ico{ stroke:var(--color4); }

/* --- 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(--color2); }

/* --- Journal --- */
.article-body{ max-width:68ch; }
.article-body h2{ margin-top:var(--sp-md); }
.article-body blockquote{
  margin:var(--sp-md) 0; padding-left:var(--sp-sm);
  border-left:2px solid var(--color2);
  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(--color4) 55%,var(--color1));
  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(--color1));
}
.rev .btn-ghost:hover,.sec-dark .btn-ghost:hover,
.site-footer .footer-nav a:hover,.site-footer .footer-legal a:hover,
.nav-overlay a:hover{
  color:var(--reverse1);
}
.rev .btn-ghost:hover,.sec-dark .btn-ghost:hover{ border-bottom-color:var(--reverse1); }

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

/* ===== 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 .btn{ 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; }
  .btn{ width:100%; }
  .btn-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(--color1);
  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(--color4);
  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(--color1); outline:none; box-shadow:none;
}
.estate-form .form-check-input{ width:auto; }
.estate-form input[type=submit],.estate-form button[type=submit],.estate-form .btn{
  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]:hover,.estate-form button[type=submit]:hover,.estate-form .btn: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(--color1) 66%,transparent) 0%,
    color-mix(in srgb,var(--color1) 46%,transparent) 45%,
    color-mix(in srgb,var(--color1) 22%,transparent) 100%);
}
@media (max-width:767.98px){
  .hero .scrim{ background:color-mix(in srgb,var(--color1) 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: Bootstrap floating labels, Estate skin ---------
   The site's forms are authored with .form-floating plus TLC 3.0 spacing
   utilities that lived in t_tlc-styles.css. We deliberately do not load that
   stylesheet, so the handful of utilities the form actually uses are restated
   here, scoped to .estate-form and nowhere else. */
/* Craig, 2026-08-01, pointing at .QUOTE / .FIELD on the component sheet: "we have
   established that hairline animation on the components right here, why is it diff?"
   It was different because the Treepl form component ships Bootstrap floating labels
   and this block was skinning that pattern instead of replacing it. The floating label
   brings three things the style guide does not have: an overlay label that collides
   with scrolled textarea copy, a `label::after` block painted in --bs-body-bg (the
   white slab that appeared behind a filled label on /v2/plan), and a blue focus ring.
   So the pattern is now CONVERTED, not skinned: column-reverse puts the label — which
   comes after the control in .form-floating markup — above it, exactly like .field.
   Same label, same bottom rule, same gold hairline running in from the left on focus,
   no outline and no second line. If .field changes, change this with it.
   Scoped to both form hosts: .estate-form is the page forms, #review-feedback is the
   Request-a-Change modal in the review bar. */
:is(.estate-form,#review-feedback) .form-floating{
  position:static;
  display:flex; flex-direction:column-reverse;
  gap:var(--sp-xxs);
  margin-bottom:var(--sp-sm);
}
:is(.estate-form,#review-feedback) .form-floating > .form-control,
:is(.estate-form,#review-feedback) .form-floating > .form-select{
  font-family:var(--BodyFont); font-size:1rem; line-height:1.6;
  color:var(--FontColor);
  height:auto; min-height:0;
  padding:var(--sp-xxs) 0;
  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(--color4);
  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{
  background-size:100% var(--BorderBrandWidth);
  border-bottom-color:var(--color1);
  box-shadow:none; outline:none;
}
:is(.estate-form,#review-feedback) .form-floating > label{
  position:static;
  padding:0; margin:0; border:0; height:auto;
  transform:none; opacity:1; pointer-events:auto;
  font-family:var(--LabelFont); font-size:.75rem; font-weight:700;
  text-transform:uppercase; letter-spacing:.18em;
  color:var(--color1);
}
/* Bootstrap still writes the shrink/lift transform and the white backing slab on the
   filled and focused states. Both are cancelled here or the label jumps on first keypress. */
:is(.estate-form,#review-feedback) .form-floating > .form-control:focus ~ label,
:is(.estate-form,#review-feedback) .form-floating > .form-control:not(:placeholder-shown) ~ label,
:is(.estate-form,#review-feedback) .form-floating > .form-control-plaintext ~ label,
:is(.estate-form,#review-feedback) .form-floating > .form-select ~ label{
  transform:none; opacity:1; color:var(--color1);
}
:is(.estate-form,#review-feedback) .form-floating > label::after{
  display:none !important; content:none !important; background:transparent !important;
}
/* Treepl sometimes nests .form-floating inside a .form-group, and both carry the
   gap — that reads as a double space between two fields and a single one elsewhere.
   The outer wrapper keeps it; the inner one gives it up. */
:is(.estate-form,#review-feedback) .form-group > .form-floating{ margin-bottom:0; }
:is(.estate-form,#review-feedback) .form-floating > textarea.form-control{
  height:auto; min-height:150px; padding-top:var(--sp-xxs); resize:vertical;
}
/* 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(--color4); border-radius:var(--RadiusBrand);
  padding:0; margin-top:.35em;
}
.estate-form .form-check-input:checked{ background-color:var(--color1); border-color:var(--color1); }
.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(--color2); }
.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: --color4 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(--color1));
}

/* --- 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(--color1));
  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; }
