/* Top Producer Investment Capital. Structural CSS.
   Every colour and font comes from tokens.css. No literals here. */

*, *::before, *::after { box-sizing: border-box; }

/* The canvas is the footer's ground, not paper. Ryan 2026-09-21: "below the
   footer there is white on the page. Let's just make the color be black to
   match the footer so that we don't ever have accidental white on the page."

   With no background on html, the BODY's background propagates to the canvas,
   so --paper painted everything outside the body box: the strip below the
   footer whenever the window is taller than the page, and the rubber band at
   both ends of an overscroll on a trackpad. Giving html its own background
   stops that propagation; body's paper then paints only the body box, which is
   what it was ever meant to do, and every page ends in the footer's own ground
   instead of a white shelf.

   #0E0D09 and not --ink, because the thing it has to match is the footer scene,
   which is #0E0D09. --ink is #16150F and would show as a seam of its own. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  background: #0E0D09;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--body);
  font-size: var(--t-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.022em;
  margin: 0;
  text-wrap: balance;
}

/* Every section heading on the site, one size. Until 2026-09-18 nothing set
   this: --t-h2 was declared in tokens.css and then only ever read by
   .section--plate h2, so a plain h2 fell through to the browser default of
   1.5em. Against a 17px body that is 26px, which is exactly what .sysrow__h
   is, so "Before We Buy" rendered the same size as the h2 it sits under and
   the hierarchy read backwards.

   h3 is deliberately left alone. Its default happens to land within a pixel
   or two of --t-h3, and the h3s that matter (.deal__h, .sysrow__h, .why h3,
   .vitem h3) all set their own size already. Applying the token there would
   change four components to fix nothing. */
h2 { font-size: var(--t-h2); }

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

/* ---------- layout ---------- */

.wrap { width: 100%; max-width: var(--wide); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: var(--narrow); }

.section { padding-block: var(--s-section); }
.section--tight { padding-block: clamp(2.5rem, 4.5vw, 4rem); }

.section--paper { background: var(--paper); }
.section--lift  { background: var(--paper-lift); }
.section--ink   { background: var(--ink); color: var(--on-dark); }
.section--steel { background: var(--steel); color: var(--on-dark); }

.section--ink h1, .section--ink h2, .section--ink h3,
.section--plate h1, .section--plate h2, .section--plate h3,
.section--steel h1, .section--steel h2, .section--steel h3 { color: var(--paper-lift); }

.prose { max-width: var(--measure); }
.prose p + p { margin-top: 0; }

/* ---------- eyebrow + heading ---------- */

/* No .eyebrow class. Kickers above headings are banned on every Tanel build
   (CORE-PLAYBOOK standing rule 9). A heading opens a section; nothing labels it. */

/* .rule-gold removed 2026-09-16: the No Decorative Bar Rule. A short coloured
   bar under a heading is ornament, and it is the fastest generated-page tell. */

.lead { font-size: var(--t-lead); line-height: 1.55; color: var(--text-soft); }
.section--ink .lead, .section--steel .lead { color: var(--on-dark-soft); }

/* ---------- buttons ---------- */

.btn {
  display: inline-block;
  font-family: var(--body);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .02em;
  padding: .95rem 1.85rem;
  border-radius: var(--radius-pill);
  text-decoration: none;
  border: 2px solid transparent;
  /* No translateY on hover. DESIGN.md bans hover-lift as a depth cue. */
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}

.btn--gold   { background: var(--gold); color: var(--ink); border-color: var(--gold); }
.btn--gold:hover { background: var(--gold-bright); border-color: var(--gold-bright); }

.btn--ghost  { background: transparent; color: var(--gold-bright); border-color: var(--gold); }
.btn--ghost:hover { background: var(--gold); color: var(--ink); }

.btn--ink    { background: var(--ink); color: var(--paper-lift); border-color: var(--ink); }
.btn--ink:hover { background: var(--ink-soft); border-color: var(--ink-soft); }

/* ---------- header ---------- */

.masthead {
  position: sticky; top: 0; z-index: 60;
  background: var(--ink);
  border-bottom: 1px solid var(--rule-dark);
}
.masthead__in {
  display: flex; align-items: center; gap: 1.5rem;
  min-height: var(--masthead-h);
}
.brand { display: flex; align-items: center; gap: .7rem; text-decoration: none; margin-right: auto; }
.brand img { height: 42px; width: auto; }
.brand__txt { display: none; }
@media (min-width: 560px) {
  .brand__txt {
    display: block;
    font-family: var(--display); font-weight: 700; font-size: .92rem;
    letter-spacing: .06em; text-transform: uppercase; color: var(--gold-bright);
    line-height: 1.2;
  }
  .brand__txt span { display: block; color: var(--on-dark-soft); font-weight: 500; letter-spacing: .12em; font-size: .68rem; }
}

.nav { display: none; align-items: center; gap: 1.75rem; }
@media (min-width: 900px) { .nav { display: flex; } }
.nav a {
  color: var(--on-dark); text-decoration: none;
  font-size: .93rem; font-weight: 500; letter-spacing: .01em;
  padding-block: .4rem; border-bottom: 2px solid transparent;
}
.nav a:hover { color: var(--gold-bright); }
.nav a[aria-current="page"] { color: var(--gold-bright); border-bottom-color: var(--gold); }
.nav .btn { padding: .65rem 1.2rem; }
.nav .btn:hover { color: var(--ink); }

.navtoggle {
  display: inline-flex; align-items: center; gap: .5rem;
  margin-left: auto; background: none; border: 1px solid var(--rule-dark);
  color: var(--on-dark); font-family: var(--body); font-size: .82rem; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase;
  padding: .6rem .9rem; border-radius: var(--radius); cursor: pointer;
}
@media (min-width: 900px) { .navtoggle { display: none; } }

.navdrawer { display: none; background: var(--ink-soft); border-bottom: 1px solid var(--rule-dark); }
.navdrawer[data-open="true"] { display: block; }
@media (min-width: 900px) { .navdrawer { display: none !important; } }
.navdrawer a {
  display: block; padding: .95rem var(--gutter);
  color: var(--on-dark); text-decoration: none; font-weight: 500;
  border-bottom: 1px solid var(--rule-dark);
}
.navdrawer a:last-child { border-bottom: 0; color: var(--gold-bright); font-weight: 600; }

/* ---------- hero: full viewport, black and gold ---------- */

.hero {
  position: relative;
  /* the masthead is sticky and 74px tall; a plain 100svh hero would push its
     own scroll cue below the fold. */
  min-height: calc(100svh - var(--masthead-h));
  display: flex;
  align-items: center;
  color: var(--on-dark);
  padding-block: clamp(2.2rem, 5vw, 4rem) clamp(7rem, 11vw, 9rem);
  background: var(--ink);
  overflow: hidden;
  isolation: isolate;
}

/* Layer 1: dot lattice, faded out toward the edges so it reads as depth
   rather than as wallpaper. */
.hero__dots {
  position: absolute; inset: 0; z-index: -3;
  background-image: radial-gradient(circle at center, rgba(233,226,208,.10) 1px, transparent 1.2px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(115% 85% at 50% 38%, #000 0%, rgba(0,0,0,.65) 48%, transparent 82%);
          mask-image: radial-gradient(115% 85% at 50% 38%, #000 0%, rgba(0,0,0,.65) 48%, transparent 82%);
}

/* Layer 2: the warm field. Two offset gold pools plus a cool counter-pool, so
   the ground is lit rather than merely black. */
.hero__glow {
  position: absolute; inset: -12% -6%; z-index: -2;
  background:
    radial-gradient(52% 58% at 76% 26%, rgba(200,153,26,.30) 0%, rgba(200,153,26,.10) 42%, transparent 72%),
    radial-gradient(44% 46% at 20% 74%, rgba(49,91,123,.30) 0%, transparent 70%),
    radial-gradient(90% 60% at 50% 108%, rgba(224,174,40,.16) 0%, transparent 62%);
  filter: blur(6px);
}

/* Layer 3: a single slow horizon sheen. The one piece of motion in the
   background, long enough that it reads as light rather than as animation. */
.hero__sheen {
  position: absolute; left: -30%; right: -30%; top: 0; bottom: 0; z-index: -1;
  background: linear-gradient(104deg, transparent 38%, rgba(240,226,190,.055) 50%, transparent 62%);
  animation: sheen 14s ease-in-out infinite;
}
@keyframes sheen {
  0%, 100% { transform: translateX(-9%); }
  50%      { transform: translateX(9%); }
}
@media (prefers-reduced-motion: reduce) { .hero__sheen { animation: none; } }

.hero .wrap {
  position: relative; z-index: 1; width: 100%;
  max-width: var(--wide-hero);
  padding-inline: clamp(1.25rem, 4.4vw, 4.4rem);
}

/* THE HEADLINE PAIR, sized off one variable.

   Ryan's rule, 2026-09-21: "I do want this to stick to a max of two lines. We
   could have two lines for 'Invest passively in Texas apartment complexes and
   hotels' and then the third line underneath is 'I operate...'". So: headline
   two lines, gold claim one line, three lines total, at every width.

   THE CLAIM IS THE BINDING LINE, not the headline, which is the opposite of
   what you would guess. The headline is 55 characters over two lines, so each
   line carries 27. The claim is 38 characters that must not break, so it needs
   more width than either headline line does. Measured in WebKit: the claim
   So the claim is defined as a FRACTION of the headline rather than
   independently, and the pair can never drift out of step when one of them is
   retuned. That indirection earned itself immediately: the claim was "I
   Operate Them With Elevated Standards." at .72, and when Ryan cut it to
   "Operated With Elevated Standards." the shorter line could take .99 of the
   headline before breaking. One number moved and the hierarchy held.

   .88 rather than the .99 it would allow. At .99 the two lines are the same
   size, which is what the old single-h1-with-a-br looked like, but near-parity
   reads as a mistake rather than a decision: either match exactly or step
   clearly. .88 is a visible step that still lets the gold line carry weight,
   and it clears the one-line ceiling at 320, the worst case, with room.

   TWO REGIMES, because the column does two different things. Below 950 the
   hero is one column and the text gets about 90% of the viewport. At 950 the
   film moves alongside and the text drops to about 42%. One vw value cannot
   serve both, which is why 950 appears here as well as in the grid. */
/* These two numbers are measured, not reasoned. The first attempt derived them
   from the headline's total width over two lines and was 12% too large at
   every width, because text does not break mid-word: the best split is
   "Invest Passively In Texas" over "Apartment Complexes And Hotels", so the
   binding line is 30 characters and not the 27.5 an even split implies. These
   come from binary-searching the largest size that still renders two lines, in
   WebKit, at 13 widths. The ceiling is 5.78vw at 320 rising to 6.04vw by 600
   below the breakpoint, and a flat 2.77vw above it; 5.6 and 2.65 sit under
   the worst case in each band.
   The px caps are not cosmetic. The text column stops growing when the wrap
   hits its max width, so past about 1750 a vw value keeps growing while the
   space does not. */
.hero__grid { --hero-fs: min(5.6vw, 40px); }
@media (min-width: 950px) { .hero__grid { --hero-fs: min(2.65vw, 46px); } }

.hero__title {
  margin: 0;
  font-family: var(--display); font-weight: 700;
  font-size: var(--hero-fs);
  color: var(--paper-lift);
  letter-spacing: -0.032em;
  line-height: 1.14;
  max-width: 100%;
  text-wrap: pretty;
}

/* The gold line. It was the second half of the old h1 and is its own paragraph
   now, so the h1 carries exactly one sentence and a crawler reads "Invest
   Passively In Texas Apartment Complexes And Hotels" rather than two sentences
   run together. */
.hero__claim {
  margin: .3rem 0 0;
  font-family: var(--display); font-weight: 700;
  font-size: calc(var(--hero-fs) * .88);
  color: var(--gold-bright);
  letter-spacing: -0.028em; line-height: 1.16;
  max-width: 100%;
}

.hero__sub {
  /* Fills the column, but the type steps up with it so the line stays a
     readable measure rather than an 85-character run. */
  font-size: 1.12rem; color: #BFB9AC;
  max-width: 710px;
  margin-top: 1.45rem; line-height: 1.62;
}
/* The lede. Was the hero deck until 2026-09-17; it now opens the first section
   below the fold, where it states the reader's own outcome in concrete terms
   before the benefit list generalises it. */
.lede {
  font-size: clamp(1.12rem, 1.4vw, 1.38rem);
  line-height: 1.45; font-weight: 600; letter-spacing: -.005em;
  color: var(--text);
  max-width: 62ch; margin: 1.15rem 0 1.15rem;
}
.section--ink .lede, .section--steel .lede { color: var(--paper-lift); }
.hero__sub strong { color: var(--paper-lift); font-weight: 600; }

.hero__cta {
  margin-top: 2.1rem;
  display: flex; flex-wrap: wrap; gap: 1rem 1.2rem;
  align-items: center;
  /* Centred under the text block, not under the grid column: matched to the
     paragraph's own measure so the button sits on the copy's centre line. */
  justify-content: center;
  max-width: 710px;
}
.hero__cta .btn--ghost { border-width: 1px; }

.hero__grid { display: grid; gap: clamp(2rem, 3.4vw, 3.75rem); align-items: center; }
/* Text column is sized to its own measure; the film takes what is left. */
@media (min-width: 950px) {
  /* Proportional, not fixed: a hard 740px text column starves the film at
     laptop widths and only looks right on a large monitor. */
  .hero__grid { grid-template-columns: minmax(0, clamp(380px, 46%, 740px)) minmax(0, 1fr); }
}

/* The headline is two authored lines with an explicit <br>, and it is meant to
   sit on exactly two, inside the left text column, with the film beside it.

   It was moved to its own full-width row on 2026-09-18 and moved straight back
   the same day. That version did hold two lines at every width, but it pushed
   the copy and the film down the page, and Ryan looked at both and kept this
   one: "I liked the size space and everything about the hero above the fold
   from before." The cost is that the headline wraps to three lines below about
   1286px. That is known and accepted, not a bug to fix.

   There is deliberately NO text-wrap: nowrap here. It was added 2026-09-17 to
   force the two lines and it was the wrong tool twice over. nowrap does nothing
   when the line already fits, and when the line does NOT fit it makes the text
   overflow its column and paint straight over the film instead of wrapping. It
   shipped scoped to 950px while the line needed 1152px, so it did exactly that
   on every laptop in between.

   A line that fits its column stays on one line without being told to. So the
   whole question is column width against line width, measured at the 31.2px
   minimum hero size in Archivo:

       "We Invest Together In Real Estate."      503px
       "I Operate It With Elevated Standards."   542px   <- the binding line

   Text column is clamp(380px, 46%, 740px) of the hero wrap, which reaches 542px
   at about 1286px of viewport, 540px at 1280 and 611px at 1440. So the headline
   holds on two lines from roughly 1286 up, and below that it wraps to three,
   which is a graceful failure rather than text over video. Raising the column
   to 48% would pull that to 1235 and cost the film 23px at 1440.

   If the headline copy changes again, re-measure both lines. Do not reach for
   nowrap. */

/* ---------- photographic plate ---------- */
/* A section whose ground is a photograph held still while the page scrolls over
   it. Three background layers, painted front to back in source order:

     1. --gold-corner, the shared gold corner wash
     1b. a flat black layer at 45%, which is exactly brightness(.55) on the
        photograph. It is done this way rather than with a CSS filter because
        filter makes an element a containing block and would break the held
        background below it
     2. a black wash, heaviest on the left where the copy sits and lightest
        through the middle right, so the photograph stays legible as a
        photograph instead of going flat grey
     3. the photograph

   Only the photograph is attachment: fixed. The two gradients scroll with the
   section, so the wash hugs the section's own box rather than being sized to
   the viewport and cropped. A fixed layer with background-size: cover is sized
   to the viewport, which is exactly what makes it hold still.

   min-height is 80svh rather than 80vh: on a phone vh is the tallest the
   viewport ever gets, so 80vh reserves space for a URL bar that is not there
   and the section opens with a band of dead ground. It stays min-height, not
   height, because four stacked pills on a narrow screen are taller than the
   floor.

   The photograph is passed in as --plate-img on the element rather than named
   here. build.py's version_assets() stamps every local asset URL with a content
   hash, because _headers serves /assets/* as immutable for a year and an image
   replaced at the same path otherwise never reaches a browser that already has
   it. That stamper only runs over the HTML it generates, so a url() written
   here would be the one asset on the site outside the cache-busting fix. Keep
   image paths in the generator. */
.section--plate {
  position: relative;
  min-height: 80svh;
  display: flex;
  align-items: center;
  color: var(--on-dark);
  background-color: var(--ink);
  background-image:
    var(--gold-corner),
    linear-gradient(101deg, rgba(9, 9, 6, .88) 0%, rgba(12, 11, 8, .84) 38%, rgba(16, 15, 10, .75) 70%, rgba(20, 19, 13, .80) 100%),
    linear-gradient(rgba(0, 0, 0, .45), rgba(0, 0, 0, .45)),
    var(--plate-img);
  background-size: cover, cover, cover, cover;
  background-position: center, center, center, center 38%;
  background-repeat: no-repeat;
  background-attachment: scroll, scroll, scroll, fixed;
}
/* The plate holds one card, centred in the column, left-aligned inside it. */
.section--plate > .wrap { width: 100%; }
/* Scaled up 20% on 2026-09-17 at Ryan's instruction, with the pills. Scoped to
   the plate rather than raised in --t-h2, which every other section's heading
   reads from. */
/* Was calc(var(--t-h2) * 1.2). That multiplier was this section quietly
   compensating for an h2 rule that did not exist; the 1.2 is now folded
   into the token itself, so this heading keeps the exact size it had and
   every other section heading joins it. */
.section--plate h2 { font-size: var(--t-h2); }
.section--plate .lead { color: var(--on-dark-soft); }

/* background-attachment: fixed does not work on iOS Safari: the layer is sized
   to the document rather than the viewport and the effect collapses into a
   badly scaled still. Touch pointers get the scrolling version, which is the
   same picture without the hold. Reduced motion gets it too, because holding a
   layer still while the page moves IS the relative motion. */
@media (hover: none), (max-width: 950px), (prefers-reduced-motion: reduce) {
  .section--plate { background-attachment: scroll, scroll, scroll, scroll; }
}

/* On a narrow screen the 101deg wash is the wrong shape. Its dark end is
   compressed into a few dozen pixels, so most of the section is left at the
   pale end of the ramp and the white heading lands on a sunlit window in the
   photograph. Re-aim it down the page instead of across it, and hold it darker
   throughout: there is no room here for the picture to be a picture, so it
   becomes ground. */
@media (max-width: 950px) {
  .section--plate {
    background-image:
      var(--gold-corner),
      linear-gradient(177deg, rgba(9, 9, 6, .84) 0%, rgba(12, 11, 8, .80) 46%, rgba(16, 15, 10, .77) 100%),
      linear-gradient(rgba(0, 0, 0, .45), rgba(0, 0, 0, .45)),
      var(--plate-img);
    background-position: center, center, center, center 42%;
  }
}

/* ---------- the process ledger, on its glass card ---------- */
/* Four pill-shaped answers until 2026-09-17, when Ryan called the pill
   childish and the section became the whole eleven-step process. A 999px
   radius is the most consumer shape there is; what reads as capital is a
   ledger: no container around each row, a fixed numeral column, hairlines
   between, and the accent spent on a numeral rather than washed across a
   surface. The hairline is structure, not the ornament standing rule 10 bans:
   remove it and eleven separate steps merge into a block. */

.plate-card {
  width: 100%;
  max-width: 972px;
  box-sizing: border-box;
  margin-inline: auto;
  padding: clamp(1.6rem, 3vw, 2.75rem) clamp(1.35rem, 3.4vw, 3.5rem);
  text-align: left;
  background: rgba(9, 9, 6, .55);
  border: 1px solid rgba(242, 239, 232, .13);
  border-radius: 4px;
  /* The inset top highlight is what makes glass read as glass rather than as
     a flat tint. The outer shadow lifts it off the photograph. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .055), 0 24px 60px rgba(0, 0, 0, .28);
  -webkit-backdrop-filter: blur(11px) saturate(1.08);
          backdrop-filter: blur(11px) saturate(1.08);
}
/* Where backdrop-filter is unsupported the card is simply a flat translucent
   panel. It still carries its contrast, because the fill alone is doing that
   work; only the blur is lost. */

.plate-lede {
  margin: .8rem 0 1.4rem;
  max-width: 58ch;
  font-family: var(--body);
  font-size: var(--t-body);
  line-height: 1.55;
  color: rgba(242, 239, 232, .66);
}

.ledger { list-style: none; margin: 0; padding: 0; border-top: 1px solid rgba(242, 239, 232, .18); }

.ledger__row {
  display: grid;
  grid-template-columns: clamp(58px, 7.2vw, 86px) minmax(0, 1fr);
  align-items: start;
  padding: clamp(.75rem, 1.1vw, 1.06rem) 0;
  border-bottom: 1px solid rgba(242, 239, 232, .18);
}

/* The step marker: a numeral and an icon, in that reading order. Both are
   drawn because they answer different questions. The icon says what the step
   IS; the numeral says where you ARE in eleven of them, which is the whole
   argument of a list titled start to finish. The icons replaced the numerals
   on 2026-09-17 and the numerals came back the same day.

   The row aligns on start rather than baseline: a 34px ring has no baseline to
   share with the text beside it and hung low against it. */
.ledger__n {
  display: flex;
  align-items: center;
  gap: clamp(.4rem, .8vw, .55rem);
}
.ledger__num {
  font-family: var(--body);
  font-weight: 700;
  font-size: clamp(.72rem, .95vw, .82rem);
  letter-spacing: .1em;
  color: var(--gold-bright);
  font-variant-numeric: tabular-nums;
}
.ledger__ico {
  display: grid;
  place-items: center;
  flex: none;
  width: clamp(28px, 3.2vw, 34px);
  height: clamp(28px, 3.2vw, 34px);
  border-radius: 50%;
  background: rgba(200, 153, 26, .1);
  border: 1px solid rgba(224, 174, 40, .28);
}
.ledger__ico svg {
  width: clamp(14px, 1.7vw, 17px); height: clamp(14px, 1.7vw, 17px); display: block;
  fill: none; stroke: var(--gold-bright);
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}

.ledger__s {
  display: block;
  font-size: clamp(1.06rem, 1.45vw, 1.31rem);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--on-dark);
}

.ledger__d {
  display: block;
  margin-top: .3rem;
  font-family: var(--body);
  font-size: clamp(.875rem, 1.1vw, 1rem);
  line-height: 1.5;
  /* .62 is not a guess. Composited against the brightest part of the
     photograph showing through the card, it measures 6.05:1. */
  color: rgba(242, 239, 232, .62);
}

/* ---------- credibility marquee ---------- */

/* Solid --ink, not a fade to 75%.
   The band was feathering into the hero: transparent at its top edge and only
   three quarters opaque below that, which let the hero glow's steel pool at
   20%/74% wash blue up through the logos. z-index: 2 already put the band
   above the glow; what it could not do was stop a translucent background
   showing what was behind it. The hairline on top is the transition now, and
   the band is its own surface. Any --ink here has to stay opaque: the blue
   pool sits directly behind it by design and will come back through the moment
   this takes an alpha. */
.cred {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  border-top: 1px solid rgba(233,226,208,.10);
  padding: 1rem 0 1.15rem;
  background: var(--ink);
}
.cred__label {
  text-align: center; font-size: .75rem; color: var(--text-faint);
  margin: 0 0 .85rem; letter-spacing: .13em; text-transform: uppercase;
  font-weight: 600;
}
.cred__label b { color: #CBC6BA; font-weight: 600; }
.cred__track {
  display: flex; width: max-content;
  /* --loop and the duration are set in JS from the measured half-width; this
     is only the pre-script fallback. */
  --loop: 50%;
  animation: marquee 68s linear infinite;
}
.cred__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.cred__item {
  display: flex; align-items: center; justify-content: center;
  padding: 0 2.6rem; flex: none;
}
.cred__item img {
  height: 40px; width: auto; display: block;
  opacity: .82; transition: opacity .2s ease;
}
.cred__item img[alt="20 Tate Village"]   { height: 48px; }
/* Starlight's horizontal lockup is roughly 12:1. Matched on height it runs
   four times wider than any other mark in the row, so this one is constrained
   on width instead and the others stay matched on height. */
.cred__item img[alt="Starlight Horizon"] { height: auto; width: 190px; }
@keyframes marquee { to { transform: translateX(calc(var(--loop) * -1)); } }
/* No pause-on-hover. A sticky hover on iOS freezes a CSS marquee permanently. */
@media (prefers-reduced-motion: reduce) { .cred__track { animation: none; } }

/* scroll cue */
.scrollcue {
  position: absolute; left: 50%; bottom: calc(100% + .9rem);
  transform: translateX(-50%); z-index: 3;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer; padding: .35rem 1.1rem;
  color: #A9A192;
}
.scrollcue:hover { color: var(--gold-bright); }
.scrollcue svg { width: 30px; height: 17px; stroke: currentColor; stroke-width: 2.4; fill: none; }
.scrollcue__chev { animation: bob 1.9s ease-in-out infinite; }
@keyframes bob {
  0%, 100% { transform: translateY(0);   opacity: .7; }
  50%      { transform: translateY(5px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .scrollcue__chev { animation: none; } }

/* On a phone the hero copy is taller than the viewport, and forcing it to fit
   would mean shrinking the one paragraph that has to be read. Let it size to
   its content instead, and drop the scroll cue: when the fold visibly cuts
   through content, nothing needs to say "scroll". */
@media (max-width: 900px) {
  .hero { min-height: 0; padding-block: clamp(2rem, 6vw, 3rem) 8.5rem; }
  .scrollcue { display: none; }
}
@media (max-width: 520px) {
  .cred__item { padding: 0 1.5rem; }
  .cred__item img { height: 30px; }
  .cred__item img[alt="20 Tate Village"] { height: 36px; }
  .cred__item img[alt="Starlight Horizon"] { height: auto; width: 140px; }
  .cred__label { font-size: .72rem; }
}

/* ---------- hero video: muted loop that opens a lightbox ---------- */

.vsl {
  position: relative; width: 100%; border: 0; padding: 0; cursor: pointer;
  background: var(--ink-soft); border-radius: var(--radius); overflow: hidden;
  box-shadow: 0 30px 80px rgba(0,0,0,.55), 0 0 0 1px rgba(233,226,208,.09);
  display: block;
}
.vsl video, .vsl img { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; }
.vsl::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(180deg, rgba(22,21,15,0) 52%, rgba(22,21,15,.55) 100%);
  pointer-events: none;
}
.vsl__play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 104px; height: 76px; border-radius: var(--radius);
  background: linear-gradient(180deg, #F0C042 0%, var(--gold) 58%, #B48814 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,244,210,.75),
    inset 0 -1px 0 rgba(90,66,8,.5),
    0 0 0 9px rgba(224,174,40,.13),
    0 12px 30px rgba(0,0,0,.45);
  display: grid; place-items: center; z-index: 2;
  transition: transform .22s ease, box-shadow .22s ease;
}
.vsl:hover .vsl__play {
  transform: translate(-50%,-50%) scale(1.05);
  box-shadow:
    inset 0 1px 0 rgba(255,244,210,.85),
    inset 0 -1px 0 rgba(90,66,8,.5),
    0 0 0 13px rgba(224,174,40,.18),
    0 14px 36px rgba(0,0,0,.5);
}
/* The glyph is cut rather than drawn: a light edge under it and a dark edge
   above read as a bevel pressed into the gold plate. */
.vsl__play svg { width: 29px; height: 33px; margin-left: 3px; display: block;
  filter: drop-shadow(0 1.5px 0 rgba(255,246,218,.55)) drop-shadow(0 -1px 0 rgba(58,42,4,.55)); }
.vsl__label {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: .85rem 1.1rem; text-align: left;
  font-family: var(--body); font-size: .86rem; font-weight: 600; letter-spacing: .01em;
  color: #EDE8DC;
}

/* ---------- lightbox ---------- */

.lb[hidden] { display: none; }
.lb {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(10,9,6,.94);
  display: grid; place-items: center; padding: clamp(.75rem, 3vw, 2.5rem);
}
.lb__box { width: min(1180px, 100%); position: relative; }
.lb video { width: 100%; aspect-ratio: 16/9; background: #000; border-radius: var(--radius); display: block; }
/* The YouTube films mount here instead of in the <video>, at the same
   size and shape, so the dialog does not change when the source does.
   The [hidden] rule is needed because .lb video sets display:block,
   which a bare hidden attribute cannot beat. */
.lb video[hidden] { display: none; }
.lb__frame { width: 100%; aspect-ratio: 16/9; background: #000;
  border-radius: var(--radius); display: block; border: 0; }
.lb__close {
  position: absolute; top: -2.9rem; right: 0;
  background: none; border: 1px solid rgba(255,255,255,.28); color: #fff;
  font-family: var(--body); font-size: .76rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  padding: .5rem 1rem; border-radius: var(--radius-pill); cursor: pointer;
}
.lb__close:hover { border-color: var(--gold); color: var(--gold-bright); }
@media (max-width: 620px) { .lb__close { top: auto; bottom: -3rem; right: 50%; transform: translateX(50%); } }

/* ---------- value grid ---------- */

.vgrid { display: grid; gap: 1.6rem 2.2rem; margin-top: 2.25rem; }
@media (min-width: 620px) { .vgrid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 950px) { .vgrid--3 { grid-template-columns: repeat(3, 1fr); } }

.vitem { display: flex; gap: .85rem; align-items: flex-start; }
.vitem__mark {
  flex: none; width: 10px; height: 10px; margin-top: .55rem;
  background: var(--gold); transform: rotate(45deg);
}
.vitem h3 { font-size: 1.06rem; letter-spacing: -0.01em; }
.vitem p { font-size: var(--t-small); color: var(--text-soft); margin-top: .35rem; }
.section--ink .vitem p, .section--steel .vitem p { color: var(--on-dark-soft); }

/* ---------- split (image + text) ---------- */

.split { display: grid; gap: clamp(1.8rem, 4vw, 3.5rem); align-items: center; }
@media (min-width: 880px) { .split { grid-template-columns: 5fr 6fr; } }
.split__media img { width: 100%; aspect-ratio: 4/3; object-fit: cover; border-radius: var(--radius); }
.split__media img.is-portrait { aspect-ratio: 3/4; }
.split__media { position: relative; }

/* ---------- property ---------- */

.property { padding-block: clamp(2.6rem, 5vw, 4rem); border-top: 1px solid var(--rule); }
.property:first-of-type { border-top: 0; padding-top: 0; }
.property__grid { display: grid; gap: clamp(1.6rem, 3.5vw, 3rem); align-items: start; }
@media (min-width: 900px) { .property__grid { grid-template-columns: 5fr 6fr; } }

.property__card {
  background: var(--paper-lift);
  border: 1px solid var(--rule); border-radius: var(--radius);
  overflow: hidden; box-shadow: var(--shadow);
}
.property__photo { width: 100%; aspect-ratio: 16/10; object-fit: cover; background: var(--steel-wash); }
.property__body { padding: 1.5rem 1.5rem 1.7rem; }
.property__loc {
  font-size: var(--t-eyebrow); font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--gold-deep); margin: 0 0 .5rem;
}
.property__name { font-size: 1.7rem; letter-spacing: -0.025em; }
.property__type { font-size: var(--t-small); color: var(--text-soft); margin: .4rem 0 1.1rem; }
.property__stats { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.property__stats li {
  font-size: var(--t-small); padding: .6rem 0 .6rem 1.35rem;
  border-bottom: 1px solid var(--rule); position: relative; color: var(--text);
}
.property__stats li:last-child { border-bottom: 0; }
.property__stats li::before {
  content: ""; position: absolute; left: 0; top: 1.05em;
  width: 7px; height: 7px; background: var(--gold); transform: rotate(45deg);
}
.property__status {
  display: inline-block; margin-top: 1rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  background: var(--gold-wash); color: var(--gold-deep);
  border: 1px solid var(--gold); padding: .3rem .6rem; border-radius: var(--radius);
}
.property__note { font-size: var(--t-small); color: var(--gold-deep); font-weight: 500; }

/* ---------- testimonials ---------- */

/* ---------- investor testimonials ---------- */
/* The card reads top to bottom in the order Ryan set 2026-09-17: stars, the
   quote, the film, then who said it. The film sits between the words and the
   name on purpose, so the face arrives while the quote is still being read and
   the name lands on someone the reader has already seen.

   The section sits on the dark field, so the card is a translucent panel
   rather than white. It is the same treatment as the plate card over the
   photograph, minus the backdrop blur: there is no photograph behind this one,
   so a blur would cost a compositing layer and buy nothing. */

/* No align-items: start. The cards have to stretch to the tallest one, or each
   card sizes to its own quote and the blockquote below has no slack to absorb;
   the films then sit at three different heights again. */
.tgrid { display: grid; gap: 1.5rem; margin-top: 2.5rem; }
@media (min-width: 860px) { .tgrid { grid-template-columns: repeat(3, 1fr); } }

.tcard {
  margin: 0;
  display: flex; flex-direction: column;
  background: rgba(9, 9, 6, .5);
  border: 1px solid rgba(242, 239, 232, .13);
  border-radius: var(--radius);
  padding: clamp(1.3rem, 2.2vw, 1.7rem);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 20px 50px rgba(0, 0, 0, .3);
}

/* Up from .95rem at Ryan's instruction. Five stars at the old size read as
   punctuation above the quote rather than as a rating. */
.tcard__stars {
  color: var(--gold-bright); letter-spacing: .1em;
  font-size: 1.32rem; line-height: 1; margin-bottom: 1rem;
}
/* flex: 1 so the quote absorbs the slack and the three films land on one line.
   The quotes are 15, 22 and 17 words, which without this put the films at three
   different heights and the names at three more; the row read as three
   unrelated cards rather than one set. The cost is a little air under a short
   quote, which is the cheaper of the two. */
.tcard blockquote {
  margin: 0; flex: 1; font-size: 1.02rem; line-height: 1.6; color: var(--on-dark);
}

/* The film. A silent loop with the hero's gold plate over it, and the same
   click: the plate opens the whole interview with sound in the shared
   lightbox. The loop carries no audio track at all, so there is nothing to
   unmute by accident. */
.tvid {
  position: relative; display: block; width: 100%; margin: 1.3rem 0 1.2rem;
  padding: 0; border: 0; cursor: pointer; overflow: hidden;
  background-color: var(--ink-soft); border-radius: var(--radius-sm);
  background-size: cover; background-position: center; background-repeat: no-repeat;
  -webkit-tap-highlight-color: transparent;
}
/* Transparent until there is picture, so the still underneath shows through.
   A <video> paints an opaque box even with nothing to paint, and that box is
   black. background: transparent is load-bearing here, not a tidy-up. */
.tvid video {
  display: block; width: 100%; aspect-ratio: 16/9; object-fit: cover;
  background: transparent; opacity: 0; transition: opacity .4s ease;
}
.tvid video.is-live { opacity: 1; }
.tvid::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(180deg, rgba(22,21,15,0) 58%, rgba(22,21,15,.5) 100%);
  pointer-events: none;
}
/* THE PLAY PLATE. One definition, worn by every click-to-play surface on the
   site: the three investor films and the three property films.
   The hero's plate at roughly half scale, same gradient and same double inset
   edge, because it has to read as the same control wherever it appears.

   It was two different things until 2026-09-17: a 68px translucent circle on
   the portfolio and this gold plate on the testimonials. Worse, the circle's
   rule was deleted when the portfolio rows were rebuilt and nothing replaced
   it, so the portfolio badges shipped unstyled. One class now, so that cannot
   happen again. Ryan asked for the gold plate on both, at this size. */
.playplate {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 43px; height: 32px; border-radius: 6px; z-index: 2;
  background: linear-gradient(180deg, #F0C042 0%, var(--gold) 58%, #B48814 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,244,210,.75),
    inset 0 -1px 0 rgba(90,66,8,.5),
    0 0 0 4px rgba(224,174,40,.13),
    0 6px 14px rgba(0,0,0,.45);
  display: grid; place-items: center;
  transition: transform .22s ease, box-shadow .22s ease;
}
.tvid:hover .playplate,
.deal__shot:hover .playplate {
  transform: translate(-50%,-50%) scale(1.06);
  box-shadow:
    inset 0 1px 0 rgba(255,244,210,.85),
    inset 0 -1px 0 rgba(90,66,8,.5),
    0 0 0 6px rgba(224,174,40,.18),
    0 7px 17px rgba(0,0,0,.5);
}
/* The glyph is cut rather than drawn: a light edge under it and a dark edge
   above read as a bevel pressed into the gold plate. */
.playplate svg { width: 12px; height: 14px; margin-left: 1px; display: block;
  filter: drop-shadow(0 1.5px 0 rgba(255,246,218,.55)) drop-shadow(0 -1px 0 rgba(58,42,4,.55)); }
.tvid:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

.tcard__who { margin-top: auto; }
.tcard__name { font-family: var(--display); font-weight: 700; font-size: .98rem; color: var(--paper-lift); }
.tcard__role { font-size: .82rem; color: var(--on-dark-soft); margin-top: .15rem; }

/* ---------- numbered steps ---------- */

.steps { list-style: none; counter-reset: s; margin: 2.25rem 0 0; padding: 0; display: grid; gap: 0; }
.steps li {
  counter-increment: s; position: relative;
  padding: 1.15rem 0 1.15rem 4rem;
  border-bottom: 1px solid var(--rule-dark);
  font-size: 1.06rem;
}
.steps li:last-child { border-bottom: 0; }
.steps li::before {
  content: counter(s, decimal-leading-zero);
  position: absolute; left: 0; top: 1.05rem;
  font-family: var(--display); font-weight: 700; font-size: 1.15rem;
  color: var(--gold-bright); letter-spacing: .02em;
}

/* ---------- the FAQ page head: a photograph, mostly in the dark ----------
   Ryan 2026-09-18. The band was flat ink and he asked for the treatment the
   20 Tate and Agave Azul pages use: the title centred with a rule running out
   either side of it, over a photograph that stays put while the page scrolls.
   His instruction on the photograph was specific, "maybe only 25% visible", so
   it adds an element without competing with the questions.

   The photograph is the dusk aerial of Starlight Horizon, and it was chosen
   because it is ALREADY dark. A daylight shot at 25% opacity is grey mush; a
   dusk shot keeps its lit windows as small warm points that pick up the gold
   in the masthead and the question numbers. It is a different frame from the
   sunset aerial on the homepage, deliberately, so the two pages do not repeat.

   HOW THE STICK WORKS, because it is not obvious. .pagehead--photo is
   position:sticky at top:0 with z-index:0, so it stays while the questions
   scroll up over it. .pagehead__stage that follows is height:0, which means it
   takes no space in the flow and its absolutely positioned copy lands ON the
   photograph. Take the zero height away and the title drops below the picture.
   Copied from the pattern on Agave Azul rather than reinvented. */

/* .pagehead.pagehead--photo, not .pagehead--photo. The single class ties with
   .pagehead on specificity and .pagehead is declared LATER in this file, so it
   won the tie and kept its padding-block. That put 56px of bare --ink above AND
   below the photograph inside the band: the "black bar at the top" and the
   "hard line at the bottom" Ryan reported were one bug wearing two hats,
   neither a gradient problem nor a crop problem. Measured on the live page
   before touching anything: band 75 to 398, image 131 to 341. */
.pagehead.pagehead--photo {
  /* top is the masthead height, NOT 0. Ryan 2026-09-18: "there's a little black
     bar, I can scroll down and the image scrolls up, once I hit the top of the
     image the image stays fixed." That was top:0. The masthead is sticky at
     top:0 and 74px tall, so the band sat at 74 and had 74px of travel before it
     pinned, and while it travelled its top slid under the masthead and showed
     as a black bar. Setting top to the masthead height makes the band's natural
     position its pinned position, so it never moves at all. */
  position: sticky; top: var(--masthead-h); z-index: 0;
  height: clamp(320px, 54svh, 580px);
  overflow: hidden; background: var(--ink);
  padding-block: 0;                 /* .section sets padding; this must not */
}
.pagehead__media {
  width: 100%; height: 100%; display: block; border: 0;
  object-fit: cover; object-position: center 52%;
}
/* The scrim. Two layers on purpose: a flat one that does the 25% and a
   gradient that lands on --navy at the bottom edge, so the band hands off into
   the questions section instead of stopping at a line. */
.pagehead--photo::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  /* Ryan 2026-09-18: it faded to navy, then hit a hard line, then went black.
     The navy was wrong. The section below is .darkfield--navy but it opens with
     a seam--ink, which paints INK over the navy at its top edge and fades it
     out downward. So the colour actually underneath the join is ink, and the
     band fading to navy put a navy stripe between two inks. Fading to ink
     instead hands straight off to the seam, and the seam carries on to navy.
     One continuous move, no line.
     The stops run long and late so the photograph is not crushed: it is still
     readable at 70% of the band's height and only goes fully to ink at the very
     bottom edge. */
  /* Retuned 2026-09-18 for the night photograph. The first picture was a
     daylight aerial and needed crushing; this one is shot at night with the
     cabin lights on, so the same scrim flattened it to nothing. The flat layer
     drops to .30 and the top barely darkens, because the masthead above is ink
     and the sky at the top of this frame is nearly ink already.
     The fall to black starts at 40% and runs the whole rest of the band. Ryan
     asked for a slow gradual fade rather than a join, and a fade needs
     distance; that is also why the band grew to 54svh. */
  background:
    linear-gradient(180deg,
      rgba(22,21,15,.26) 0%, rgba(22,21,15,.10) 16%,
      rgba(22,21,15,.18) 40%, rgba(22,21,15,.52) 66%,
      rgba(22,21,15,.86) 86%, var(--ink) 100%),
    linear-gradient(0deg, rgba(22,21,15,.28), rgba(22,21,15,.28));
}
.pagehead__stage { position: relative; height: 0; z-index: 2; margin: 0; padding: 0; }
.pagehead__copy {
  position: absolute; left: 0; right: 0; bottom: clamp(26px, 5vh, 54px); z-index: 3;
  display: flex; align-items: center; gap: clamp(14px, 3vw, 40px);
  color: var(--on-dark);
  text-shadow: 0 1px 24px rgba(22,21,15,.92);
}
.pagehead__rule { flex: 1 1 auto; height: 1px; background: currentColor; opacity: .42; }
.pagehead--photo + .pagehead__stage h1 {
  margin: 0; flex: 0 0 auto; max-width: none;
  font-size: var(--t-h1); line-height: 1.05; color: var(--paper-lift);
  white-space: nowrap;
}
@media (max-width: 720px) {
  /* The title has to be allowed to wrap before the rules are allowed to vanish. */
  .pagehead--photo + .pagehead__stage h1 { white-space: normal; flex: 0 1 auto; min-width: 0; }
  .pagehead__copy { gap: clamp(10px, 3vw, 14px); text-align: center; }
  .pagehead__rule { min-width: 18px; }
}
@media (prefers-reduced-motion: reduce) {
  .pagehead.pagehead--photo { position: relative; top: auto; }
}

/* ---------- questions (FAQ) ---------- */

.qlist { margin-top: 2.5rem; border-top: 1px solid var(--rule); }
.qitem { border-bottom: 1px solid var(--rule); }
.qitem__btn {
  width: 100%; display: flex; gap: 1rem; align-items: flex-start;
  background: none; border: 0; cursor: pointer; text-align: left;
  padding: 1.35rem 0; font-family: var(--display); font-weight: 700;
  font-size: clamp(1.02rem, 1.7vw, 1.22rem); line-height: 1.3;
  letter-spacing: -0.015em; color: var(--text);
}
.qitem__btn:hover { color: var(--gold-deep); }
.qitem__n {
  flex: none; font-size: .82rem; font-weight: 700; color: var(--gold-deep);
  font-family: var(--body); letter-spacing: .06em; min-width: 2.1rem;
  padding-top: .28rem;
}
.qitem__q { flex: 1; }
.qitem__sign {
  flex: none; width: 15px; height: 15px; margin-top: .42rem; position: relative;
}
.qitem__sign::before, .qitem__sign::after {
  content: ""; position: absolute; background: var(--gold);
  left: 50%; top: 50%; transform: translate(-50%,-50%);
  transition: opacity .18s ease, transform .18s ease;
}
.qitem__sign::before { width: 15px; height: 2px; }
.qitem__sign::after  { width: 2px; height: 15px; }
.qitem[data-open="true"] .qitem__sign::after { opacity: 0; transform: translate(-50%,-50%) rotate(90deg); }
.qitem[data-open="true"] .qitem__btn { color: var(--gold-deep); }

.qitem__panel { display: none; padding: 0 0 1.9rem; }
.qitem[data-open="true"] .qitem__panel { display: block; }
@media (min-width: 880px) {
  .qitem__panel { padding-left: 3.1rem; }
  .qitem__panel--video { display: none; }
  .qitem[data-open="true"] .qitem__panel--video { display: grid; grid-template-columns: 5fr 7fr; gap: 2rem; align-items: start; }
}
/* Ryan 2026-09-18: the answers wrapped well short of the space available. The
   66ch measure was fighting the row it sits in, because the question above it
   spans the full width and the answer stopped around 60% of it, which reads as
   a bug rather than as typography.

   Uncapped it ran 101 characters at the widest the page ever gets, since .wrap
   caps at 1180px, against a question row of 106. That closed the mismatch but
   overshot the comfortable measure, so Ryan set it to 85, which is the top of
   the readable range rather than past it. It is a third wider than the old cap
   and it is why this does not use --measure: 66ch is the right measure for a
   prose column, and this is not one, it is a row that has to agree with the
   full-width question above it.

   The video answers never had the problem. Their grid column is 57ch, so no
   cap has ever bound there. */
.qitem__answer { font-size: var(--t-body); color: var(--text-soft); max-width: 85ch; }
.qitem__answer ul, .qitem__answer ol { padding-left: 1.15rem; margin: 0 0 1.15em; }
.qitem__answer li { margin-bottom: .45em; }
.qitem__answer a { color: var(--gold-deep); }

.qvideo { border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden; background: var(--ink); position: relative; }
.qvideo video { width: 100%; aspect-ratio: 16/9; object-fit: cover; background: var(--ink); }
.qvideo__tag {
  font-size: .72rem; font-weight: 600; letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-faint); padding: .5rem .7rem; background: var(--paper-lift);
  border-top: 1px solid var(--rule);
}

/* ---------- form ---------- */

.formcard {
  background: var(--paper-lift); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: clamp(1.6rem, 3.5vw, 2.6rem);
  box-shadow: var(--shadow);
}
.field { margin-bottom: 1.15rem; }
.field label {
  display: block; font-size: .84rem; font-weight: 600; letter-spacing: .03em;
  color: var(--text); margin-bottom: .4rem;
}
.field .req { color: var(--gold-deep); }
.field input, .field textarea, .field select {
  width: 100%; font-family: var(--body); font-size: 1rem; color: var(--text);
  padding: .8rem .9rem; background: var(--paper);
  border: 1px solid var(--rule); border-radius: var(--radius);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: 2px solid var(--gold); outline-offset: 1px; background: var(--paper-lift);
}
.field textarea { min-height: 110px; resize: vertical; }
.field--row { display: grid; gap: 1.15rem; }
@media (min-width: 620px) { .field--row { grid-template-columns: 1fr 1fr; } }
.field--row .field { margin-bottom: 0; }
.input--hidden { position: absolute !important; left: -9999px !important; }
.formnote { font-size: .84rem; color: var(--text-faint); margin-top: 1rem; }

/* ---------- misc ---------- */

.disclaimer {
  font-size: .82rem; color: var(--text-faint); font-style: italic;
  border-top: 1px solid var(--rule); padding-top: 1.2rem; margin-top: 2.5rem;
  max-width: var(--measure);
}
/* On the dark field --text-faint is unreadable and --rule vanishes. The one
   under the portfolio has to stay legible: it is the only disclaimer sitting
   next to the return figures now that /track-record is gone. */
.darkfield .disclaimer {
  color: var(--on-dark-soft);
  border-top-color: rgba(242,239,232,.12);
}

.ctaband { text-align: center; }
/* Ryan 2026-09-18: one line on desktop. It already fitted, and the only thing
   breaking it was the 20ch cap here, which is 628px against a 1180px wrap. The
   cap is gone and the size tracks the viewport instead, so the line holds down
   to about 760px.

   Below that it has to wrap, and .nobreak decides where: never inside "A Top
   Producing Investor?", which is the phrase the whole band is built on, and
   which the old break split straight down the middle as "A Top / Producing
   Investor?". The nowrap is lifted again under 640px, where even that phrase
   is wider than the screen and holding it together would push the text off the
   side. */
.ctaband h2 {
  font-size: clamp(1.75rem, 4.4vw, 3.3rem);
  max-width: none; margin-inline: auto;
}
@media (min-width: 640px) { .ctaband .nobreak { white-space: nowrap; } }
.ctaband .lead { margin-inline: auto; max-width: 52ch; margin-top: 1.1rem; }
.ctaband .btn { margin-top: 2rem; }

/* ---------- the hero on a phone, and ONLY on a phone -------------------
   Ryan 2026-09-21, reviewing the homepage on an iPhone. Everything in this
   block is scoped to 600px and below and nothing above it changes: "I like the
   desktop version as it is."

   WHY 600 AND NOT 760. The headline already holds one line per row from about
   591px up, because 31.2px of Archivo needs 543px of column and the wrap gives
   it that at 591px of viewport. Scoping this any wider would SHRINK a headline
   that was already fine, which is the opposite of the ask.

   THE COST OF ONE LINE, MEASURED. "I Operate It With Elevated Standards." is
   the binding line at 17.4px of width per 1px of font size. A 390px phone gives
   the column 350px, so one line caps the headline at 20.1px. It is 31.2px now
   and the paragraph under it is 17.9px. So this buys the second row at the
   price of a headline barely larger than body copy.

   4.6vw, measured in WEBKIT, because Ryan reviews on an iPhone and WebKit sets
   this string a fraction wider than Chromium does. Three earlier values sat on
   the boundary and wrapped: 5.1, 4.95 and 4.8. The trap is that the h1 box is
   NOT the viewport minus a fixed gutter, it is about 78 to 80 percent of the
   viewport and the fraction moves, so vw arithmetic off one width is wrong at
   another. Measured with a hidden nowrap probe: the gold line costs 16.198px
   of width per 1px of font, the white line 15.019.

   AND THE HONEST NUMBER: at 4.6vw a 390px phone renders the headline at 17.9px
   and the paragraph under it at 17.92px. The headline is not larger than the
   body copy, it is very slightly smaller. That is not a bug in this rule, it is
   what "I Operate It With Elevated Standards." costs on one line at phone
   width. The fix is fewer words, not a smaller number here.

   ORDER. Ryan's running order on a phone is headline, film, supporting copy,
   button. The three text pieces are wrapped in a plain <div> for the desktop
   grid, so display:contents dissolves that wrapper and lets all four become
   grid items that `order` can move. The wrapper carries no role, no label and
   no styling of its own, which is what makes that safe here. */
@media (max-width: 600px) {
  .hero__grid { text-align: center; }
  .hero__grid > div { display: contents; }
  /* width:100% and NOT margin-inline:auto. The auto margins made the h1
     shrink-to-fit, so its box collapsed around whatever the browser had
     already wrapped and then the text could never un-wrap: the box followed
     the wrap instead of the wrap following the box. Measured at 390: box 291px
     against a 313px column, and forcing nowrap gave exactly 291. That is the
     circularity, and it is why three font sizes in a row failed to fix
     something that was never a font size problem. text-align on the parent
     does the centring. */
  .hero__title    { order: 1; width: 100%; }
  /* The headline and the gold line are one three-line statement, so they must
     sit at line spacing, not at section spacing. display:contents makes both
     of them grid items, so .hero__grid's 32px row-gap lands between them and
     the phone showed 37px where desktop shows 5. Ryan: "there's too much
     padding or a gap between the yellow and the gold text... I like that the
     desktop version has all three lines with about equal padding."

     -33px, arrived at by measuring rather than by arithmetic. Cancelling the
     32px row-gap exactly, at -27, still left 33px between the second headline
     line and the gold one where the headline's own lines sit 24 apart. The
     desktop proportion is 44 then 48, about 1.09; -27 gave 1.375. The extra
     comes from the gold line being 12% smaller, so its line box does not stack
     the way the headline's two identical lines do, and no amount of reasoning
     about the row-gap predicts it. -33 lands at 24 then 27.

     Same trick the retired eyebrow needed, for the same reason, which is the
     thing to remember: anything that belongs tight to its neighbour inside
     this grid has to buy its way out of the row-gap. */
  .hero__claim    { order: 1; width: 100%; margin-top: -33px; }
  .hero .vsl      { order: 2; }
  /* Left, not centred. Ryan 2026-09-21. The headline is two short lines and
     centring reads as deliberate; this is five lines of running prose and
     centred body copy gives every line a different starting edge, so the eye
     has to find the start again on each one. width:100% for the same reason
     the h1 has it: auto margins would make the block shrink-to-fit and the
     ragged right would then pull the box in. */
  .hero__sub      { order: 3; text-align: left; width: 100%; }
  .hero__cta      { order: 4; }
}

/* ---------- the sweep button's halo on a phone -------------------------
   Ryan 2026-09-21: "there is a dark box that is bounding the glow on the CTA
   button... it's not an obvious rectangle bounding the glow."

   He is right and it is iOS only. .sweep-cta::after draws the halo with
   filter: blur() at z-index -1. A filtered element is promoted to its own
   compositing layer, and on iOS Safari that layer is backed opaquely, so it
   paints its own rectangular bounds over whatever is behind it. The hero's
   gold field is behind it, which is why the rectangle reads as a dark box and
   why it shows worst on the top and left where that field is brightest.
   Neither desktop Chromium nor desktop WebKit reproduces it at 3.2x exposure;
   it was found by running an edge detector over Ryan's own phone screenshot,
   which is the only render that has the bug in it.

   The fix is to stop asking for a blurred layer at all on phones. A box-shadow
   follows border-radius, needs no layer, and cannot paint a rectangle. What it
   cannot do is sweep, so the halo goes static below 760px while the ring
   itself, which is ::before and unfiltered, keeps animating. On a screen this
   size a static bloom under a moving ring is the better trade anyway. */
@media (max-width: 760px) {
  .sweep-cta::after { display: none; }
  .sweep-cta {
    box-shadow: 0 0 20px 1px rgba(245, 210, 113, .34),
                0 0 44px 6px rgba(245, 210, 113, .16);
  }
}

/* ---------- why real estate ---------- */
/* Seven cards, each an icon, a two-word heading and one line about what the
   investor GETS. Two earlier drafts were thrown away here and the reason is
   worth keeping: both wrote body copy that defined the heading rather than
   stating the benefit. A card that says "Tax Advantages / depreciation and cost
   segregation" has told the reader nothing they wanted.

   Icons are inline stroke SVG, never an icon font and never emoji, and they are
   aria-hidden: each one duplicates its own heading, so a screen reader that
   announced them would hear everything twice.

   auto-fit rather than a fixed three columns. Seven items in a three-column
   grid leaves one card alone on a row of its own; at four columns it is four
   and three, and a short last row reads as a list ending rather than an
   orphan. */

.whys {
  display: grid; gap: 1.1rem;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  margin-top: clamp(1.8rem, 3vw, 2.6rem);
}
.why {
  padding: clamp(1.25rem, 2.2vw, 1.6rem);
  border: 1px solid rgba(242, 239, 232, .13);
  border-radius: var(--radius-sm);
  background: rgba(9, 9, 6, .42);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.045);
  transition: border-color .2s ease, background .2s ease;
}
.why:hover { border-color: rgba(224, 174, 40, .45); background: rgba(12, 12, 8, .55); }
.why__icon {
  display: grid; place-items: center; width: 42px; height: 42px;
  border-radius: 50%; margin-bottom: 1rem;
  background: rgba(200, 153, 26, .1);
  border: 1px solid rgba(224, 174, 40, .3);
}
.why__icon svg {
  width: 21px; height: 21px; display: block;
  fill: none; stroke: var(--gold-bright);
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.why h3 { font-size: clamp(1.02rem, 1.7vw, 1.16rem); color: var(--paper-lift); }
.why p {
  margin: .6rem 0 0; font-size: var(--t-small);
  color: var(--on-dark-soft); line-height: 1.58;
}

/* ---------- the portfolio, folded ---------- */
/* Ryan 2026-09-17, after two working mockups. Four deals laid out one to a
   full-width row was the longest section on the page by a distance, and an
   investor who wanted to skip it had to scroll past all of it. Each property is
   a disclosure now: folded it shows the photograph, the name, the city and the
   type; open it drops the numbers and the story underneath.

   ONE OPEN AT A TIME. Opening a property closes whichever was open, so the
   section has a ceiling: four folded rows plus one panel, whatever the reader
   does. That was the point of the exercise, and the independent-toggle version
   he saw alongside this one gave the ceiling up in exchange for comparing two
   deals side by side. He chose the ceiling.

   The photograph is NOT the toggle. Where a property has a film the photograph
   is the button that plays it, so making it also expand the row would put two
   actions on one target. The toggle is the text block and the chevron, which is
   still most of the card's width and its full height. */

.deals { margin-top: clamp(2.2rem, 4vw, 3.4rem); display: flex; flex-direction: column; gap: 1.1rem; }

/* The gold box moved out here from .deal__card: the card IS the row now, and
   the gold marks WHICH row is open. Ryan 2026-09-17.

   Folded rows take a quiet border; the open one takes the gold; hover sits
   between the two. The width stays 3px in every state on purpose. Changing it
   would move every row below by however much it changed, on every click.

   Only one row can be open, so only one gold frame is ever on screen, which is
   what makes it read as a position marker rather than decoration. */
.deal {
  border: 3px solid rgba(242, 239, 232, .13);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: rgba(7, 14, 20, .5);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.045);
  transition: border-color .2s ease, background .2s ease;
}
.deal:hover { border-color: rgba(224, 174, 40, .55); background: rgba(9, 18, 25, .62); }
.deal[data-open="true"] { border-color: var(--gold); background: rgba(9, 18, 25, .62); }
.deal[data-open="true"]:hover { border-color: var(--gold-bright); }

/* cursor on the head, because the whole head toggles the row as of
   2026-09-18. The heading block inside it is still the focusable
   button; this only changes what the mouse reports as clickable. */
.deal__head { display: flex; align-items: center; gap: clamp(1rem, 2vw, 1.4rem);
  padding: 1.1rem; cursor: pointer; }

.deal__shot {
  position: relative; display: block; flex: none;
  width: clamp(170px, 26vw, 300px); aspect-ratio: 5/3;
  border-radius: 6px; overflow: hidden; background: var(--steel-wash);
  border: 0; padding: 0;
}
.deal__shot img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* The loop, over the poster. It fades in on .is-live, which site.js sets on
   loadeddata, so a clip that never arrives leaves the poster showing rather
   than a black box. Same contract as .tvid video on the investor cards. */
.deal__loop {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity .5s ease; pointer-events: none;
}
.deal__loop.is-live { opacity: 1; }
button.deal__shot { cursor: pointer; -webkit-tap-highlight-color: transparent; }
button.deal__shot:focus-visible { outline: 3px solid var(--gold); outline-offset: -3px; }

/* The toggle. A heading wrapping a button is the accordion pattern the
   questions list already uses on this site, and it is the one arrangement that
   is valid both ways round: a button may sit inside an h3, an h3 may not sit
   inside a button. */
.deal__h { margin: 0; flex-grow: 1; min-width: 0; }
.deal__toggle {
  font: inherit; color: inherit; background: none; border: 0; cursor: pointer;
  width: 100%; text-align: left; padding: .3rem 0; display: flex;
  align-items: center; gap: 1rem; -webkit-tap-highlight-color: transparent;
}
.deal__toggle:focus-visible { outline: 3px solid var(--gold); outline-offset: 4px; }
.deal__who { flex-grow: 1; min-width: 0; }

.deal__name {
  display: block; font-family: var(--display); font-weight: 700;
  font-size: clamp(1.35rem, 2.4vw, 1.9rem); letter-spacing: -0.025em; color: var(--paper-lift);
}
.deal__type {
  display: block; font-size: var(--t-small); font-weight: 600;
  color: var(--on-dark); margin-top: .45rem;
}
.deal__status {
  display: inline-block; margin-top: .7rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink); background: var(--gold); padding: .3rem .6rem; border-radius: var(--radius-pill);
}

/* NOTE ON PLACEMENT. Everything below overrides .deal__name, .deal__type and
   .deal__status above, at the SAME specificity, so it only works because it
   comes after them. It was first written 200 lines earlier in this file and
   had no effect at all: the rules shipped, the browser loaded them, and the
   originals won on source order. A media query adds no specificity, so being
   inside @media does not save an earlier rule either. If this block is ever
   moved, it has to move downwards. */

/* ---------- the portfolio card head on a phone ------------------------
   Ryan 2026-09-21, once all four cards started folded and you could finally
   see four heads at once: "Edit the size of the text so that it wraps in a
   good way. Keep the size of the thumbnails where they are, that is
   important." So the thumbnail's clamp(170px, 26vw, 300px) is untouched.

   WHERE THE 336px GOES. Measured at 390: thumbnail 170, then the padding, the
   flex gap and the chevron take another 84, which leaves the name and the
   location sharing 82px. "Legends on Storey Lane" broke into four lines and
   "Round Rock, TX, 30-Unit Multifamily (Built 2023)" into five, and no font
   size fixes an 82px column: shrinking type to fit it just makes small text
   that still wraps badly.

   So the gap and the padding give up what they can spare first, which costs
   the thumbnail nothing, and the type comes down second. 82px becomes about
   140, and at that width the name holds two lines at 1.15rem and the location
   two or three at .78rem.

   The chevron keeps its 17px. It is the only thing on a folded bar that says
   the bar opens. */
@media (max-width: 600px) {
  .deal__head   { gap: .6rem; padding: .85rem; }
  /* The second gap. .deal__toggle is itself a flex row of text plus chevron
     with a 16px gap in it, which is 16 of the 129px the heading gets. Cutting
     it to 4 is what finally took the text column past 100 and let "Legends on
     Storey Lane" hold two lines instead of three. */
  .deal__toggle { gap: .25rem; }
  .deal__chev   { gap: 0; }
  .deal__name   { font-size: 1.1rem; letter-spacing: -0.02em; line-height: 1.2; }
  .deal__type   { font-size: .78rem; margin-top: .3rem; line-height: 1.35; }
}

/* ---------- "Sold August 2024" stops being a button -------------------
   Ryan 2026-09-21: "this Sold August 2024 button draws too much attention. I
   think we just need to have maybe an asterisk and have it also be white text,
   but not even bolded, just a little bit thinner white text than above it."

   It was a gold pill: ink on gold, 700 weight, uppercase, tracked out. On a
   card whose whole job is to introduce a property, the loudest element on it
   was a date. It is now a line of dimmer text under the location, lighter in
   weight than the location above it rather than heavier, with the asterisk
   supplied by the pseudo-element so the content in build.py keeps saying just
   "Sold August 2024" and the mark stays a presentation detail.

   Not scoped to phones. Ryan was looking at a phone, but a gold pill shouting
   a date is the same mistake at every width, and this is the kind of thing
   that looks deliberate on one screen and like a bug on the other if you only
   half-change it. If he wants the pill back on desktop, this whole block is
   the thing to delete. */
.deal__status {
  display: block; margin-top: .35rem;
  font-size: .82rem; font-weight: 400; letter-spacing: 0; text-transform: none;
  color: rgba(242, 239, 232, .62);
  background: none; padding: 0; border-radius: 0;
}
.deal__status::before { content: "* "; }



/* The affordance. The frame brightens, the chevron drops two pixels and the
   label slides in from the right. The label is aria-hidden: aria-expanded on
   the button already tells a screen reader the state, and reading the hint
   aloud as part of the name would say it twice. */
.deal__chev {
  flex: none; display: flex; align-items: center; gap: .55rem;
  color: rgba(242,239,232,.5); transition: color .2s ease, transform .2s ease;
}
.deal__chev svg { width: 17px; height: 17px; stroke: currentColor; fill: none;
                  stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; display: block; }
.deal__cl {
  font-family: var(--display); font-size: .69rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; white-space: nowrap;
  opacity: 0; transform: translateX(6px); transition: opacity .22s ease, transform .22s ease;
}
.deal:hover .deal__chev { color: var(--gold-bright); transform: translateY(2px); }
.deal:hover .deal__cl  { opacity: 1; transform: translateX(0); }
@media (max-width: 720px) { .deal__cl { display: none; } }

/* The chevron turns over when the card is open. Ryan 2026-09-21: "the close
   button still has the down arrow. The arrow should be pointing up when it's
   closing." It never turned; the only transform on it was the two-pixel hover
   nudge, so an open card said CLOSE next to an arrow still inviting you down.

   The rotation goes on the SVG and the hover nudge stays on the .deal__chev
   wrapper, because a transform on one element cannot hold both: whichever
   rule won would drop the other, and the arrow would either stop turning on
   hover or stop nudging while open. Two elements, one transform each. */
.deal__chev svg { transition: transform .2s ease; }
.deal[data-open="true"] .deal__chev svg { transform: rotate(180deg); }

.deal__panel { display: none; padding: 0 1.1rem 1.4rem; }
.deal[data-open="true"] .deal__panel { display: block; }
.deal__cols {
  border-top: 1px solid rgba(242,239,232,.12); padding-top: 1.25rem;
  display: grid; gap: clamp(1.2rem, 2.6vw, 2rem);
  animation: dealin .26s ease both;
}
@media (min-width: 820px) { .deal__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@keyframes dealin { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .deal__cols { animation: none; } }

.deal__stats { list-style: none; margin: 0; padding: 0; }
.deal__stats li {
  position: relative; padding-left: 1.15rem; margin-bottom: .55rem;
  font-size: var(--t-small); color: var(--on-dark-soft); line-height: 1.5;
}
.deal__stats li:last-child { margin-bottom: 0; }
.deal__stats li::before {
  content: ""; position: absolute; left: 0; top: .52em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--gold);
}
.deal__story p + p { margin-top: 1.1em; }

/* ==========================================================================
   THE DARK FIELD
   ==========================================================================
   The page's one ground system, approved by Ryan 2026-09-17. Every section
   below the fold is either ink or navy; nothing on the homepage is white any
   more. Three things vary and they vary independently:

     1. THE GROUND. --ink or --navy, and NOT strictly alternating. The page
        runs ink, ink, navy, photograph, navy, ink, navy, ink.

        It ran in pairs when the system was approved on 2026-09-17: ink, ink,
        navy, navy, ink, ink, photograph, navy, navy, ink, two of each so a
        pair of sections read as one chapter and the change of ground was the
        chapter break. Three sections came out later the same day (Why Invest,
        the Lifestyle block, and the whole /track-record page) and the write-off
        section moved down to sit above the questions, which left the pairs
        broken. What is there now is single sections alternating, which is a
        weaker rhythm but not a wrong one: the portfolio is the only thing in
        the top half wearing its own ground, and the portfolio is the proof.

        The page still opens and closes on ink, and the 20 Tate plate is still
        the hinge. If sections are added back, pair them again.

     2. THE TEXTURE, on .darkfield__tex. Five of them: dots, grain, lines,
        hatch and none. No two sections running wear the same one, and every
        texture is masked so it fades out rather than tiling to the edges.
        Three sections carry no texture at all, on purpose: the write-offs, the
        lifestyle section and the questions accordion hold the most body copy
        on the page, and a pattern behind a paragraph is the fastest way to
        make it tiring to read. Those three are told apart by light alone.

     3. THE LIGHT, on .darkfield__glow. Placed by hand per section, never by
        rule, and no section repeats another's arrangement. Each ink section
        carries some steel and each navy section carries some gold, so neither
        ground is ever alone; that is what stops the two halves of the page
        reading as two different sites.

   The hero is NOT part of this. It keeps its own .hero rules, deliberately:
   it is signed off and frozen, and it has a third layer (the sheen) that
   nothing else gets. If it is ever reopened, fold it in and delete the copy.
   ========================================================================== */

.darkfield {
  position: relative; overflow: hidden; isolation: isolate;
  background: var(--ink); color: var(--on-dark);
}
.darkfield--navy { background: var(--navy); }
.darkfield h1, .darkfield h2, .darkfield h3 { color: var(--paper-lift); }
.darkfield .lead { color: var(--on-dark-soft); }
.darkfield > .wrap { position: relative; z-index: 1; }

.darkfield__tex  { position: absolute; inset: 0; z-index: -3; pointer-events: none; }
.darkfield__glow { position: absolute; inset: -14% -6%; z-index: -2; filter: blur(7px); pointer-events: none; }

/* The seam. A change of ground at a hard line is a line you hit; this makes it
   a distance you scroll through. The layer is the PREVIOUS section's ink,
   opaque at the top edge and gone by the bottom of the band, so the two
   grounds cross over rather than butt together.

   It sits at z-index -1, above both the texture and the light, because it has
   to cover them too: a seam that fades the ground but not the grain on top of
   it just moves the hard edge onto the texture.

   Scaled to the viewport rather than fixed. At 250px on a 2860px section it
   was right on a 600px mock and too short on a monitor. */
.darkfield__seam {
  position: absolute; left: 0; right: 0; top: 0; z-index: -1; pointer-events: none;
  height: clamp(200px, 18vw, 320px);
}
/* Which ground the seam is fading FROM, i.e. the colour of the section above.
   The alpha stops have to be literals rather than var(): a CSS variable cannot
   carry a colour into a gradient stop and then be given an alpha. Keep these in
   step with --ink and --navy by hand if either token ever moves. */
.seam--ink  { background: linear-gradient(180deg, #16150F 0%, rgba(22,21,15,.74) 34%, rgba(22,21,15,0) 100%); }
.seam--navy { background: linear-gradient(180deg, #0F1A23 0%, rgba(15,26,35,.74) 34%, rgba(15,26,35,0) 100%); }

/* ---- the five textures ---- */

.tex--dots {
  background-image: radial-gradient(circle at center, rgba(233,226,208,.10) 1px, transparent 1.3px);
  background-size: 26px 26px;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 20%, #000 0%, rgba(0,0,0,.5) 52%, transparent 84%);
          mask-image: radial-gradient(120% 90% at 50% 20%, #000 0%, rgba(0,0,0,.5) 52%, transparent 84%);
}
/* Fading out downward rather than from the centre: this one sits under the
   hero and the texture has to run out, not restart. */
.tex--dots-fall {
  background-image: radial-gradient(circle at center, rgba(233,226,208,.10) 1px, transparent 1.3px);
  background-size: 26px 26px;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.42) 40%, transparent 74%);
          mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.42) 40%, transparent 74%);
}
/* Grain, not geometry. Ryan picked this 2026-09-17 over four alternatives,
   after the vertical streaks it replaces read as pinstripes: 1.5px lines at a
   9px pitch are a pattern on the wall, and he wanted the ground felt rather
   than seen.

   Three dot fields at different sizes, offsets and one of them faintly gold,
   blurred together. The sizes are deliberately coprime-ish (7, 11x13, 19x17)
   so the three never line up into a visible repeat, and the blur is what turns
   the last of the geometry into grain. It has NO direction, which is the whole
   point: there is no axis for the eye to read a stripe along.

   The blur is load-bearing. Drop it and this becomes three moire patterns.

   inset is negative because blurring a full-bleed layer thins its own edges;
   the section's overflow: hidden crops the surplus back off. */
.tex--grain {
  inset: -8px;
  background-image:
    radial-gradient(circle at center, rgba(186,210,232,.16) .9px, transparent 1.4px),
    radial-gradient(circle at center, rgba(186,210,232,.11) .9px, transparent 1.5px),
    radial-gradient(circle at center, rgba(200,153,26,.09) 1px, transparent 1.6px);
  background-size: 7px 7px, 11px 13px, 19px 17px;
  background-position: 0 0, 3px 5px, 8px 2px;
  filter: blur(2.2px);
  -webkit-mask-image: radial-gradient(120% 92% at 50% 34%, #000 0%, rgba(0,0,0,.55) 56%, transparent 90%);
          mask-image: radial-gradient(120% 92% at 50% 34%, #000 0%, rgba(0,0,0,.55) 56%, transparent 90%);
}
/* Blueprint. Removed 2026-09-17 with the Why Invest section and restored the
   same day for Three Ways To Own Real Estate, which is a section ABOUT
   structure: three named paths set against each other. Nothing adjacent wears
   it, so the no-two-running rule still holds. */
.tex--lines {
  background-image:
    linear-gradient(rgba(242,239,232,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(242,239,232,.055) 1px, transparent 1px);
  background-size: 68px 68px, 68px 68px;
  -webkit-mask-image: radial-gradient(90% 110% at 78% 50%, #000 0%, rgba(0,0,0,.45) 54%, transparent 86%);
          mask-image: radial-gradient(90% 110% at 78% 50%, #000 0%, rgba(0,0,0,.45) 54%, transparent 86%);
}
.tex--hatch {
  background-image: repeating-linear-gradient(45deg,
    rgba(242,239,232,.05) 0 1px, transparent 1px 15px);
  -webkit-mask-image: linear-gradient(115deg, #000 0%, rgba(0,0,0,.4) 46%, transparent 82%);
          mask-image: linear-gradient(115deg, #000 0%, rgba(0,0,0,.4) 46%, transparent 82%);
}

/* ---- the light, one recipe per section ---- */

/* Under the hero: both pools centred ABOVE the top edge, so only their lower
   falloff is on screen. Light spilling over the seam, not two new sources. */
.glow--decay {
  inset: -4% -6% 0; filter: blur(9px);
  background:
    radial-gradient(62% 48% at 10% -8%, rgba(49,91,123,.32) 0%, rgba(49,91,123,.11) 46%, transparent 76%),
    radial-gradient(66% 34% at 88% -12%, rgba(200,153,26,.22) 0%, rgba(200,153,26,.07) 48%, transparent 78%);
}
/* Portfolio: gold low and wide so the photographs sit in warmth, cool corner. */
.glow--floor {
  background:
    radial-gradient(84% 44% at 50% 104%, rgba(200,153,26,.20) 0%, rgba(200,153,26,.06) 48%, transparent 76%),
    radial-gradient(40% 40% at 6% 8%, rgba(49,91,123,.20) 0%, transparent 72%);
}
/* One bloom under the three paths, nothing else. Restored with .tex--lines.
   .glow--warm went out with the write-off section it lit. */
.glow--under {
  background:
    radial-gradient(58% 62% at 50% 118%, rgba(224,174,40,.24) 0%, rgba(200,153,26,.07) 46%, transparent 76%);
}
/* Process: cool from directly overhead, the only pool on the centre axis. */
.glow--above {
  background:
    radial-gradient(70% 52% at 50% -10%, rgba(49,91,123,.30) 0%, rgba(49,91,123,.09) 48%, transparent 78%),
    radial-gradient(30% 34% at 90% 88%, rgba(200,153,26,.14) 0%, transparent 74%);
}
/* Questions: the quietest thing on the page. One low haze, gold in a corner. */
.glow--hush {
  background:
    radial-gradient(76% 40% at 50% 108%, rgba(49,91,123,.22) 0%, transparent 74%),
    linear-gradient(to top right, transparent 76%, rgba(200,153,26,.09) 100%);
}
/* The closing band: the hero again, quieter. */
.glow--close {
  background:
    radial-gradient(48% 62% at 78% 18%, rgba(200,153,26,.26) 0%, rgba(200,153,26,.09) 44%, transparent 72%),
    radial-gradient(42% 52% at 18% 84%, rgba(49,91,123,.26) 0%, transparent 70%),
    radial-gradient(86% 58% at 50% 112%, rgba(224,174,40,.14) 0%, transparent 62%);
}

/* ==========================================================================
   CONTENT ON THE DARK FIELD
   ==========================================================================
   Everything below the fold used to sit on paper. These are the overrides that
   move it onto ink and navy. They are scoped to .darkfield on purpose: the
   inner pages are still light and share every one of these components.
   ========================================================================== */

/* Hairlines. --rule is a paper colour and disappears on a dark ground.
   .deal is deliberately NOT in this list. It used to be, from when the rows
   were separated by a top hairline rather than being cards, and the selector
   was `.deal + .deal`: every row except the FIRST had its border-color
   overwritten on all four sides. That is why the gold frame sat on 20 Tate
   whatever the reader opened. The rows carry their own border now. */
.darkfield .qlist,
.darkfield .qitem { border-color: rgba(242,239,232,.10); }

/* Process items. */
.darkfield .vitem p { color: var(--on-dark-soft); }

/* The questions accordion. Gold has to step up to its on-dark value or it
   goes muddy against near-black. */
.darkfield .qitem__btn { color: var(--on-dark); }
.darkfield .qitem__btn:hover,
.darkfield .qitem[data-open="true"] .qitem__btn { color: var(--gold-bright); }
.darkfield .qitem__n { color: var(--gold-bright); }
.darkfield .qitem__answer { color: var(--on-dark-soft); }
.darkfield .qitem__answer a { color: var(--gold-bright); }

/* ---------- the steel room: questions on the navy ground ----------
   Ryan picked direction 03 off the options canvas, 2026-09-18. Two dark rooms
   rather than one: ink for the masthead and the heading, navy for the
   questions themselves. The navy ground and every dark override above already
   existed for the homepage, so what is actually new is three things.

   Scoped to .darkfield--navy .qitem, which is "an FAQ item on a navy ground".
   That is both places one exists: this page, and the five questions at the
   foot of the homepage, which have been sitting on exactly this ground since
   the homepage went dark. Scoping it to the page instead would have given one
   component two open states on one site. */

/* 1. The hairline goes cool. rgba(242,239,232,.10) is a warm white and it is
      right on --ink; on navy it reads slightly yellow. */
.darkfield--navy .qlist,
.darkfield--navy .qitem { border-color: rgba(163,191,214,.16); }

/* 2. So does the body copy, for the same reason --on-navy-soft exists. */
.darkfield--navy .qitem__answer { color: var(--on-navy-soft); }

/* 3. The open question gets a room of its own: a steel panel and a gold rail.
      Drawn with a pseudo-element rather than a border and padding, so opening
      a question moves no text sideways. It bleeds past the wrap on both sides
      so the rail sits outside the column rather than inside it. */
.darkfield--navy .qitem { position: relative; }
.darkfield--navy .qitem[data-open="true"]::before {
  content: ""; position: absolute; z-index: -1;
  top: 0; bottom: 0; left: -1.5rem; right: -1.5rem;
  background: rgba(49,91,123,.17);
  border-left: 3px solid var(--gold);
  pointer-events: none;
}
@media (max-width: 560px) {
  /* The gutter is 1.5rem, so the full bleed would put the rail off-screen. */
  .darkfield--navy .qitem[data-open="true"]::before { left: -.75rem; right: -.75rem; }
}

/* ---------- the inner pages, on the dark ground ----------
   Ryan 2026-09-18: "yes, let's go ahead and apply the coloring to those pages
   as well." /about, /ryan-tanel and /invest were the last three on paper, and
   clicking a nav item from the dark homepage was a jump to white.

   Everything above was written for the homepage and the FAQ. What follows is
   only the components those three pages use and the homepage does not: prose
   body copy, the two bios, the credentials list, the numbered steps, and the
   form. Each had a paper colour baked in that either disappears or shouts on
   ink. */

.darkfield .prose,
.darkfield .prose p,
.darkfield .prose li { color: var(--on-dark-soft); }
.darkfield .prose strong { color: var(--on-dark); }

/* The bios. --gold-deep is graded for paper and goes muddy here.
   .prose .bio__role, not .bio__role: the role sits INSIDE .prose, so the
   `.darkfield .prose p` rule above ties it on class count and wins on being
   later. Caught on the live page, where the role rendered grey instead of
   gold. */
.darkfield .bio__name { color: var(--paper-lift); }
.darkfield .prose .bio__role { color: var(--gold-bright); }

/* Credentials and steps are both hairline-separated lists. */
.darkfield .creds li,
.darkfield .steps li { border-bottom-color: rgba(242,239,232,.10); color: var(--on-dark); }
.darkfield .creds li::before,
.darkfield .steps li::before { color: var(--gold-bright); }

/* The form. This is the one that would have broken rather than merely looked
   wrong: a --paper input on a near-black card is a white box, and --text
   labels vanish into the ground. The card takes the same lifted steel the open
   FAQ question uses, so the two pages agree on what a panel on the dark ground
   is. */
.darkfield .formcard {
  background: rgba(49,91,123,.15);
  border-color: rgba(163,191,214,.18);
  box-shadow: 0 2px 4px rgba(0,0,0,.24), 0 18px 44px rgba(0,0,0,.34);
}
.darkfield .field label { color: var(--on-dark); }
.darkfield .field input,
.darkfield .field select,
.darkfield .field textarea {
  background: rgba(11,16,23,.55);
  border-color: rgba(163,191,214,.22);
  color: var(--on-dark);
}
.darkfield .field input::placeholder,
.darkfield .field textarea::placeholder { color: var(--on-dark-soft); opacity: .7; }
.darkfield .field input:focus,
.darkfield .field select:focus,
.darkfield .field textarea:focus { border-color: var(--gold); outline-color: var(--gold); }
.darkfield .formnote { color: var(--on-dark-soft); }
.darkfield .req { color: var(--gold-bright); }

/* A photograph on a dark ground wants a hairline, not the paper shadow. */
.darkfield .bio__photo,
.darkfield .split__media img { border: 1px solid rgba(242,239,232,.08); }

/* btn--ink is a near-black button and vanishes on a near-black ground.

   Ryan 2026-09-18: it was an outline with gold text and read as weak, so the
   whole button is gold now with white on it. --gold rather than --gold-bright
   for the rest state deliberately: it is the darker of the two, which is the
   better of the two backgrounds to put white on. */
.darkfield .btn--ink {
  background: var(--ink); color: var(--gold-bright); border: 2px solid var(--gold);
  box-shadow: 0 2px 0 rgba(0, 0, 0, .35), 0 14px 32px rgba(0, 0, 0, .4);
}
.darkfield .btn--ink:hover {
  background: var(--gold); color: var(--ink); border-color: var(--gold);
}

/* ---------- the closing CTA, overlaid on the skyline scene ---------- */
/* No longer its own section (see cta_band()'s header comment in build.py for
   why: a separate .ctafin darkfield box put a hard colour step right under
   the button). .foot__cta is a child of .foot__scene, positioned in the
   HTML that footer() emits: see .foot__scene below for the svg it sits on
   top of and how its `bottom` offset is computed so the button lands on the
   same approved 22px, now against Waterline's tip at any width rather than
   against one width tuned in CSS. */
.foot__cta {
  position: absolute; left: 0; right: 0; z-index: 2;
  padding: .3rem 1rem 1.4rem;
}
.foot__cta .ctaband h2 { color: var(--paper-lift); }
/* Ryan 2026-09-20: "the CTA is now too close to the Heading, needs a bit
   more padding." Was a flat .6rem (9.6px); targets 36px at a 965px viewport
   (his reference, chrome-less screenshot). Written as a vh-scaled clamp, not
   a fixed px value, because the CTA box is bottom-anchored to the skyline
   (see .foot__cta above): every px this gap grows pushes the heading that
   much further up toward the sticky header. At 965 there is 40px of blank
   sky already sitting above the CTA doing nothing (SKY_PAD sized for a
   taller CTA box than this one turned out to need), so the growth here
   mostly spends slack that already existed rather than shrinking headroom.
   At the shorter 800px viewport the clamp settles back to the old 9.6px
   floor, matching what already shipped there, so a short window never sees
   the heading crowd the header worse than it does today. */
.ctafin__cta { margin-top: clamp(9.6px, 16vh - 118.4px, 36px); display: flex; justify-content: center; }

.creds { list-style: none; margin: 1.6rem 0 0; padding: 0; display: grid; gap: .1rem; }
.creds li { padding: .85rem 0 .85rem 1.5rem; border-bottom: 1px solid var(--rule); position: relative; font-size: 1.02rem; }
.creds li::before { content: ""; position: absolute; left: 0; top: 1.3em; width: 8px; height: 8px; background: var(--gold); transform: rotate(45deg); }
.section--ink .creds li { border-color: var(--rule-dark); }

.ytgrid { display: grid; gap: 1.25rem; margin-top: 2rem; }
@media (min-width: 760px) { .ytgrid { grid-template-columns: repeat(3, 1fr); } }
.ytgrid .videoframe iframe { aspect-ratio: 16/9; }

.bio { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); align-items: start; padding-block: clamp(2rem, 4vw, 3rem); border-top: 1px solid var(--rule); }
@media (min-width: 760px) { .bio { grid-template-columns: 260px 1fr; } }
.bio__photo { width: 100%; border-radius: var(--radius); object-fit: cover; aspect-ratio: 1/1; }
.bio__name { font-size: var(--t-h3); }
.bio__role { font-size: var(--t-eyebrow); font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--gold-deep); margin: .4rem 0 1rem; }

/* ---------- footer ---------- */

/* This section's bottom padding is the plain --s-section token again, and
   that is deliberate: it was a vh-scaled clamp from 2026-09-20 until later
   the same day, and the clamp is gone because what it was working around is
   gone.

   What it worked around: Ryan, at a tall window, saw a sliver of this
   section's own "Read All Of The Common Investor Questions" button under the
   sticky header at the page bottom. The panel below (skyline plus footer)
   was ~816px, so past a certain viewport height the panel plus a fixed gap
   plus the 75px header stopped adding up to the window and the button poked
   out. clamp(104px, 100vh - 881px, 560px) grew the gap with the viewport so
   the 100vh term cancelled out of the button's on-screen position, which
   held everywhere inside the linear region and necessarily broke at the cap,
   leaving one ~40px crossing near 1728x1451-1498. That was documented and
   accepted as a property of a capped linear function.

   Why it is gone: .foot--panel is now min-height 100svh, so the closing
   panel IS the window at the page bottom and everything above it, this
   button included, is off the top of the screen by construction. Measured
   after that change, at 1728 wide, the button's bottom edge sits at -559.7
   at 1451, 1475, 1498 and 1600 alike -- the same number at every height,
   because the panel absorbs the difference. The clamp was then buying
   nothing and still charging for it: at 1728x1400 it was laying down 519px
   of empty navy between the button and the panel. Below 965 it sat at its
   104px floor, so removing it changes nothing at the height Ryan tests. */

/* .foot__lead-in is the section directly above the closing panel. It is not a
   layout class; it marks the one section on each animated page (the home
   FAQ, the questions accordion, the About experience block) whose bottom
   edge has to hand over to the skyline's sky.

   What goes wrong there, and it is the line Ryan reported 2026-09-20: every
   .darkfield section is overflow:hidden and wears a texture and a glow, and
   those layers are simply cut off at the boundary rather than finishing at
   it. The sky below starts on that section's exact base colour, so there is
   nothing to hide the cut behind, and what is left at the join is the
   lighting's own clipped edge. Sampled off his screenshot, the last row
   above it read (16,28,38) at x300 and (18,30,40) at x1000 against a flat
   (15,25,35) below: brighter in the middle, which is the glow, and a step
   that varies across the width cannot be closed by matching one colour to
   another. That is why `join` already being --navy did not close it.

   This is the mirror of .darkfield__seam, which fades a section IN from the
   ground above it. Here the section fades out to its OWN ground, so the
   texture and the glow are both gone before the edge and the handover is
   base colour to base colour. z-index -1 puts it over __tex (-3) and
   __glow (-2) and under the content (1), which is the same stacking seam
   uses and for the same reason: fading the ground but not the grain on top
   of it only moves the hard edge onto the texture.

   The alphas have to be literals. A CSS variable cannot carry a colour into
   a gradient stop and then be given an alpha; keep these in step with --ink
   and --navy by hand, exactly as .seam--ink and .seam--navy do.

   Measured after, at the join, all three pages: 0.00 step and 0 spread. */
.foot__lead-in::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; z-index: -1;
  height: clamp(140px, 16vw, 280px); pointer-events: none;
  background: linear-gradient(0deg, #16150F 0%, rgba(22,21,15,.82) 38%, rgba(22,21,15,0) 100%);
}
.foot__lead-in.darkfield--navy::after {
  background: linear-gradient(0deg, #0F1A23 0%, rgba(15,26,35,.82) 38%, rgba(15,26,35,0) 100%);
}

/* Background is the skyline's own ground colour (row 3's fill, SKYLINE_FILLS[3]
   in build.py), not --ink. .foot__scene crops hard at the ground line (see
   below); row 3 covers the full width below its own roofline, so whatever
   colour sits behind/after it has to be this exact value or the crop reads as
   a seam. This is the third time that exact defect has been rejected: match
   the colour, do not eyeball it. */
.foot {
  background: #0E0D09; color: var(--on-dark-soft);
  /* No bottom padding of its own: the item-7 gap (copyright bottom -> page
     bottom) moved onto .foot__legal's own padding-bottom 2026-09-20 (see
     .foot__legal below) so that box's rendered height literally IS the band
     from the divider to the page bottom, which is what .foot__mark now
     centres on. Two padding-bottoms stacked here and there would double the
     gap. */
  padding-block: 0;
  font-size: var(--t-small);
  position: relative; overflow: hidden;
}

/* The closing panel is never shorter than the window.

   Ryan 2026-09-20, looking at the page bottom on a 16" MacBook: "There is a
   seem right here. Right above the Heading. I like where the heading is on
   the whole, so just add some padding to the top of the heading until it
   fills the whole screen." Measured at 1728x965 before this: scene 436.3 +
   footer 383.9 = 820.2, so the panel started 144.3px down the screen, 69.3px
   of it below the sticky header and in plain view.

   The join itself is a separate defect with a separate fix, and both were
   needed. It is not a gap in the colours: the section above ends on its own
   texture and glow, cut off mid-stride by .darkfield's overflow:hidden. That
   is handled where it happens, by .foot__lead-in::after above, which fades
   the section out to its own ground before its edge. This rule handles the
   other half of what Ryan asked for, which is that the join not be on screen
   at all when the page is at rest.

   min-height rather than a taller viewBox: the riser is a flex-grow child,
   so it takes exactly the shortfall and collapses to zero the moment the
   panel covers the window on its own. Baking the same sky into the svg would
   have meant choosing one amount, correct at one window size and paying for
   itself in page length at every other. The heading does not move either
   way: .foot__cta is anchored to the bottom of the scene, on the skyline. */
.foot--panel {
  display: flex; flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;  /* iOS: 100vh is the toolbar-less height, which overshoots */
}
.foot--panel > * { flex: 0 0 auto; }
/* Painted --join, which footer() sets per page on .foot: the exact colour
   stop 0 of the sky gradient starts on, so this is the scene's first pixel
   repeated upward rather than a band of its own. */
.foot__riser { flex: 1 1 auto; min-height: 0; background: var(--join); }
/* Ryan 2026-09-20: "there is room... it is cramming the FAQ button and
   section above into the very bottom of the frame" and "I want the footer
   and the very bottom of the page to read as one panel," not three stacked
   bands with no room between them. Was a flat .8rem (12.8px); targets 44px
   at 965. vh-scaled clamp for the same reason as .ctafin__cta above: this
   gap adds directly to the closing panel's total height, and every added px
   pushes the heading up. Settles back to the shipped 12.8px at 800 so a
   short viewport is no worse than it was before this pass. */
.foot > .wrap { position: relative; z-index: 1; padding-top: clamp(12.8px, 18.91vh - 138.47px, 44px); }

/* ---- the skyline scene ----
   Ported from the approved artboard (build.py's SKYLINE constant is the
   source of truth for the geometry; this is only how it sits on the page).

   The svg carries its own intrinsic size, always 1200 wide: width 100%,
   height auto, so it scales as one piece at the correct ratio, and the full
   1200-wide panorama stays in frame at every width, sail to Waterline, only
   ever smaller, never cropped sideways.

   Vertically it is cropped hard to the skyline itself via the svg's own
   viewBox, not a CSS trick, on the four pages with no CTA: viewBox="0 372
   1200 328", where 372 is Waterline's tip, "the ceiling Ryan approved" per
   the artboard's own header comment, and 700 is the ground. On the three
   pages WITH a CTA, build.py widens that same viewBox upward by SKY_PAD so
   the heading and button (.foot__cta below) have sky to sit on instead of a
   separate section's flat background; .foot__scene's aspect-ratio is set
   inline per page for exactly this reason, so the box's own ratio always
   matches whichever viewBox this page got rather than depending on the svg
   loading first. Either way nothing below 700 ships: that was 260 units of
   solid ground fill the artboard needed to host its own welded footer text,
   which put ~340px of dead air over the real footer's copy and is the exact
   defect Ryan rejected in September ("the text... is way under the closest
   row of buildings"). */
/* The phone closing-CTA defect, found 2026-09-20 and fixed 2026-09-21 the
   way the note here said it would have to be: structurally, not by tweaking
   the clip.

   What it was. .foot__cta is bottom-anchored inside this box. At 390x844 the
   box is 98.5px tall and the CTA is 162.3px, so the heading and the top half
   of the button fell outside it and overflow:hidden removed them. Ryan's
   screenshot: a sliced button with no heading over it. Taking the clip off
   alone was tried and rejected, because it only moved the problem: the
   heading then landed at y 54 under a sticky header that owns 0 to 75, and at
   375x667 the box hung above .foot's own top edge where .foot's own clip
   (which the travelling footer copy needs) destroyed it instead.

   The fix, in the phone block near the bottom of this file: below 760px the
   CTA stops being absolutely positioned and flows above the skyline, and this
   box drops its aspect-ratio so it sizes to what it holds. Nothing is
   anchored to a box too small to hold it, so nothing is clipped. The ratio
   rides a custom property for exactly this reason, so the phone rule can drop
   it without having to out-shout an inline style.

   The clip itself stays. It is what keeps the CTA's glow inside the scene at
   desktop widths, where the CTA does fit. */
.foot__scene {
  position: relative; overflow: hidden; background: #0E0D09;
  aspect-ratio: var(--scene-ratio);
}
.foot__scene svg { display: block; width: 100%; height: auto; }

/* ---- the watermark ----
   Ryan 2026-09-21: "this little watermark of our logo at the very bottom isn't
   doing much. Let's remove it from there. I want to put it off to the right,
   similar to the size, shape, and location that we did for the agave plant
   logo for Agave Azul."

   So this is Agave's .agave-mark.fmark, transplanted. What that rule does, and
   why, taken from its own comments on that site:

     - ITS FOOT ON THE FOOT OF THE LINK COLUMNS, not on the bottom of the
       footer. A watermark lying across the phone number or the disclaimer is
       not a watermark, it is a smudge on the one thing down there somebody
       needs to read. Here that means bottom:0 inside .foot__grid.
     - ITS RIGHT EDGE ON THE RIGHT EDGE OF THE PAGE, inset 32px. The footer is
       full bleed and .wrap is a 1180px block centred in it, so the two right
       edges are (100vw - 1180)/2 + 24 apart; that is what the offset below
       subtracts, floored at the wrap's own 24px gutter for widths where the
       wrap is narrower than 1180 and the gutter is all there is.
     - SIZED BY THE SPACE, NOT BY A CONSTANT. The two link columns come to
       about 561px and sit centred, so the clear space to their right is
       (100vw - 561)/2. The mark takes that, less the 32px inset and a 24px
       breath, capped at the 320px Agave settled on.
     - The EMBLEM ONLY, never the full lockup. Agave learned that one the hard
       way: the full logo with its lettering "read as a second headline rather
       than as a watermark". tpic-watermark.png is already the bull and the
       towers with the wordmark cropped off, which is why it is a separate
       asset from the header logo.

   What it replaces: a 48-64px mark centred behind the copyright line, which
   is the one Ryan just called out for not doing much. It was that size and in
   that place because it was fitted to the copyright row's own box.

   Below 1100px the space to the right of the columns is too narrow to hold a
   mark worth drawing, and at 620 the columns take the full width anyway, so
   it goes. Agave draws the same line at the same width. */
.foot__grid { position: relative; }
.foot__mark {
  position: absolute; z-index: 0; pointer-events: none; user-select: none;

  /* CENTRED IN THE CLEAR BAND, both ways, Ryan 2026-09-21: "a bit more padding
     above and to the right of it, so that it sits in the center between top
     and bottom of the footer section, and side distance on the right edge, and
     the box with the Contact details text." It was hard against the right edge
     at 32px and its foot was on the columns, which put its top above the
     footer entirely, overlapping the skyline.

     HORIZONTALLY. The band runs from the contact column's right edge to the
     page's right edge, and both are measurable from this element's own
     containing block, .foot__grid:
       - grid right edge to page right edge is --mark-page below, which is half
         the overflow past the 1180px wrap plus the wrap's own 24px gutter,
         floored at that gutter for widths where the wrap is narrower than 1180.
       - grid right edge to the columns' right edge is a CONSTANT 282.7px from
         1280 up, measured at 1280, 1512, 1728, 1920 and 2560. The two columns
         come to 566.7px and sit centred in the grid's 1132, so the figure is
         (1132 - 566.7) / 2. It drifts to 269 by 1150 as the column gap starts
         clamping down, which only makes the band wider than this assumes, so
         the mark stays clear either way.
     The mark then takes the middle of that band, which is what puts equal air
     on both sides instead of 32px on one and 220 on the other.

     VERTICALLY. The band runs from the top of the footer's wrap to the top of
     the disclaimer, because the disclaimer and the copyright row are full
     width and a watermark behind them is the smudge Agave's own rule warns
     about. 61% of the grid's height is that band's centre: at 1728x965 it puts
     the centre at 705 against a true 706.6, and at 1728x800, where the wrap's
     padding and the row margins all shrink on their vh clamps, at the same
     61% against a true 80/130.3. One number, right at both.

     SIZE. 280 rather than Agave's 320, which is what buys the padding: at 320
     the mark stands 225 tall in a 250 band and leaves 11px above it. At 280 it
     is 197 tall and leaves 25 above and 28 below.

     AND THE HEIGHT IS CAPPED BY THAT BAND, not only by the width, because the
     band is shorter on a shorter window. Everything between the wrap's top and
     the disclaimer except the grid itself is on a vh clamp: the wrap's own
     padding-top, the social row's margin and the disclaimer's margin. So the
     band is 250px at 965 and 186px at 800, and a 197px mark that fits the
     first overhangs the second at both ends by 6px. --mark-band-h re-adds the
     same three clamps, verbatim, plus the grid's 130.3 and the social row's
     20, and the cap leaves 24px of air top and bottom.

     The cap has to come through the WIDTH, not through max-height. max-height
     on a replaced element whose width is already fixed clamps the height and
     leaves the width alone, so the first attempt squashed the mark: at
     1728x800 it rendered 280 by 137.5, an aspect of 2.04 against the asset's
     own 1.42. Converting the height cap into a width cap with the asset's
     ratio, 520/366 = 1.4208, keeps it in proportion. Measured after: 1.421 at
     every width and height tested. */
  --mark-page: max(24px, (100vw - 1180px) / 2 + 24px);
  --mark-band: calc(282.7px + var(--mark-page));
  --mark-w: min(280px,
                calc(var(--mark-band) - 120px),
                calc((var(--mark-band-h) - 48px) * 1.4208));

  --mark-band-h: calc(150.3px
     + clamp(12.8px, 18.91vh - 138.47px, 44px)
     + clamp(12.8px, 9.21vh - 60.9px, 28px)
     + clamp(9.6px, 11.15vh - 79.61px, 28px));

  width: var(--mark-w); height: auto;
  right: calc((var(--mark-band) - var(--mark-w)) / 2 - var(--mark-page));
  left: auto; bottom: auto;
  top: 61%; transform: translateY(-50%);

  /* Ryan: "the watermark is too hard to see. Let's make it slightly more
     visible." Agave's .07 is on navy; this ground is #0E0D09, near black, so
     the same alpha lands a third darker.

     AND IT IS THE LOGO'S OWN PIXELS, not a recolour. tpic-watermark-gold.png
     is now the top 366 rows of tpic-logo.png with nothing but the wordmark
     cropped off: black building bodies, white chevrons on their faces, the
     gold bull with its own gradient, the gold ground arc. _source/
     make_watermark.py does the crop and asserts the alignment.

     Two earlier versions were wrong in the same place and Ryan caught both off
     the rendered page. tpic-watermark.png is the emblem flattened to one warm
     near-white with the shape carried only in the alpha channel. That was
     right at .055 behind the copyright line, where internal detail would have
     turned to mud, but it is an INVERSION: it paints 238,233,223 on the black
     buildings and 238,233,223 on the white chevrons alike, so out here on a
     dark ground the building bodies glow and the chevrons read as dark gaps.
     The first gold pass kept that file as its base and pulled RGB from the
     logo only where the logo was BRIGHT gold, so it fixed the bull and left
     the inversion standing, and it missed the bull's own shadow side, which is
     gold in the original but failed the brightness test and stayed near-white.
     Ryan: "you have your colors inverted... ours is actual gold for the bull,
     and yours is looking like something similar, just slightly off."

     So the building bodies are now near-black over a near-black footer and are
     close to invisible on purpose. The mark reads as the gold bull and arc
     with the skyline drawn in fine white chevron lines and no body behind
     them, which is what the logo actually is. Do not lighten them.

     .1375 is Ryan's "25% brighter", taken literally off the .11 it replaced.
     On a ground this dark the rendered lift is proportional to the alpha, so
     25% more alpha is 25% more lift. At this alpha over the footer's 14,13,9:
     the chevrons lift 32 points, the bull 27.8 of red and 22.4 of green, and
     the buildings sit 1 point BELOW the ground. */
  opacity: .1375;
}
@media (max-width: 1100px) { .foot__mark { display: none; } }

.foot__grid { display: grid; gap: 2.2rem; }
/* TRIAL 2026-09-21: two columns on a phone as well. */
@media (max-width: 619px) {
  .foot__grid {
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 1.25rem;
  }
  .foot__grid ul, .foot__grid p { overflow-wrap: anywhere; }
}
@media (min-width: 620px) {
  .foot__grid {
    grid-template-columns: repeat(2, minmax(0, max-content));
    justify-content: center;
    gap: clamp(3.5rem, 13vw, 9.5rem);
  }
}
.foot h4 { font-size: var(--t-eyebrow); letter-spacing: .12em; text-transform: uppercase; color: var(--gold-bright); margin-bottom: .5rem; font-family: var(--body); font-weight: 600; }
/* line-height tightened from the inherited body value (1.65) 2026-09-20: at
   four rows in the taller column that inherited height, plus each row's own
   margin below, was most of the "loose" 440px of footer content Ryan's
   scrolled-to-bottom screen couldn't fit alongside the heading and skyline. */
.foot ul { list-style: none; margin: 0; padding: 0; line-height: 1.3; }
.foot li { margin-bottom: .2rem; }
.foot a { color: var(--on-dark-soft); text-decoration: none; }
.foot a:hover { color: var(--gold-bright); }
/* Its own centred row, above the disclaimer. Was clamp(2.2rem,4vw,3rem),
   maxing out at 3rem well before 1728px; same tightening pass. Margin-top
   reopened 2026-09-20 as part of the closing-panel spacing pass (was a flat
   .8rem/12.8px, targets 28px at 965); see .ctafin__cta above for why this is
   a vh-scaled clamp and not a fixed value. */
.foot__social {
  display: flex; gap: 1.35rem; justify-content: center;
  margin-top: clamp(12.8px, 9.21vh - 60.9px, 28px);
}
.foot__social a { color: var(--on-dark-soft); }
.foot__social svg { width: 20px; height: 20px; fill: currentColor; display: block; }
.foot__social a:hover { color: var(--gold-bright); }
/* margin-top (space above the divider line) reopened 2026-09-20 in the
   closing-panel spacing pass: was a flat .8rem/12.8px, targets 24px at 965.
   padding-top (divider line to the copyright text below it) is untouched;
   it is not one of the spec's ten gaps.

   padding-bottom is item 7 (copyright bottom -> page bottom), moved here
   2026-09-20 from .foot's own padding-block so this box's rendered height
   spans the FULL band .foot__mark centres in, not just the content row
   above the trailing gap -- see .foot__mark above. Was a flat .6rem/9.6px
   there; target raised from 32 to 40 at 965 (still inside the +/-8
   tolerance) specifically to give the mark a few more px of room, at
   Ryan's/the reviewer's direction. See .ctafin__cta above for why every one
   of these is a vh-scaled clamp. */
.foot__legal {
  position: relative;
  margin-top: clamp(14.3px, 5.88vh - 32.73px, 24px); padding-top: .6rem;
  padding-bottom: clamp(9.6px, 18.42vh - 137.79px, 40px);
  border-top: 1px solid var(--rule-dark);
  display: flex; flex-wrap: wrap; gap: .6rem 1.5rem; justify-content: space-between;
  font-size: .82rem; color: var(--text-faint);
}
/* Ryan 2026-09-18: no cap. The disclaimer sits alone across the full footer
   with nothing beside it, so 78ch left a third of the row empty and folded
   the text into four lines instead of three. margin-top reopened 2026-09-20:
   was a flat .6rem/9.6px, targets 28px at 965; see .ctafin__cta above for
   why it's a vh-scaled clamp. */
.foot__risk { font-size: .78rem; line-height: 1.5; color: var(--text-faint); margin-top: clamp(9.6px, 11.15vh - 79.61px, 28px); }

/* ---------- page head ---------- */

.pagehead { background: var(--ink); color: var(--on-dark); padding-block: clamp(2.6rem, 5.5vw, 4.5rem); }
/* Ryan 2026-09-18: "Frequently Asked Questions" broke across two lines. The
   20ch cap was set when the heading was "Every Question, Answered", which
   WANTED the break. It is 26 characters now, and "Have Ryan On Your Podcast"
   is 25, so both were being folded for no reason. 30ch clears the two that
   should hold one line and still folds the 41-character heading on /invest,
   which genuinely needs two. */
.pagehead h1 { font-size: var(--t-h1); color: var(--paper-lift); max-width: 30ch; }
.pagehead .lead { margin-top: 1.1rem; max-width: 60ch; }

/* /invest only. Ryan 2026-09-21: "this heading should be centered and go on one
   line across the heading there, one row."

   The 30ch cap above is the only thing that was folding it: 30ch is 628px and
   the line needs more, so it broke after "Top" every time regardless of how
   much room the wrap had. Dropping the cap is the whole fix, exactly as it was
   for the closing band on 2026-09-18, which carries this same sentence.

   .nobreak is the same span the closing band uses and it decides WHERE the
   line breaks once the screen is too narrow to hold it: never inside "A Top
   Producing Investor?", which is the phrase the page is built on. It is lifted
   under 640 where that phrase alone is wider than the screen. */
.pagehead--center { text-align: center; }
.pagehead--center h1 { max-width: none; margin-inline: auto; }
@media (min-width: 640px) { .pagehead--center .nobreak { white-space: nowrap; } }

.skip {
  position: absolute; left: -9999px; background: var(--gold); color: var(--ink);
  padding: .7rem 1.1rem; z-index: 200; font-weight: 600; border-radius: var(--radius);
}
.skip:focus { left: var(--gutter); top: .6rem; }

/* ---------- the playbook: alternating system rows ---------- */
/* Ryan 2026-09-17 sent hiddengem.media's systems section as the reference.
   What that layout actually does: one idea per screen, a gold-outlined icon
   tile as the only ornament, body copy kept under about forty words, and a
   large visual on the side the text is not on, alternating down the page so
   the eye crosses the column on every row.

   Their rhythm carries six items. Ours carries twelve steps, which at one row
   each would run roughly four screens, so the row is spent on the PHASE and
   its three steps nest in the text column. The numerals still run 01 to 12
   unbroken across the four rows: the phases are chapters of one sequence, and
   restarting at 01 four times would say the opposite.

   Their visual is an abstract dark interface mock with gold blocks. Ours is a
   photograph, because there is no software product here to draw. */

.sysstack {
  display: grid;
  gap: clamp(3.2rem, 7vw, 6rem);
  margin-top: clamp(2.2rem, 4.4vw, 3.8rem);
}

.sysrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.04fr);
  gap: clamp(1.8rem, 4vw, 4.2rem);
  align-items: center;
}
/* The flip is done with `order` rather than by reversing the source, so the
   reading order stays heading-then-photograph on every row and in every
   screen reader, no matter which side the photograph is drawn on.

   The fractions swap with it. Without that the photograph sits in the 1fr
   column on flipped rows and the 1.04fr column on the others, and the four
   photographs come out at two different widths down the page. */
.sysrow--flip { grid-template-columns: minmax(0, 1.04fr) minmax(0, 1fr); }
.sysrow--flip .sysrow__txt { order: 2; }

.sysrow__h {
  /* The bottom margin is the standfirst's, inherited. Ryan cut the four phase
     ledes 2026-09-17 and the heading sat straight on top of step 01; this is
     the air that line used to hold open, minus the line.

     Top margin is zero because the icon tile it used to clear came off the
     same day. The heading is the first thing in the column now, and the row
     centres itself against the panel, so any top margin here just pushes the
     whole column off centre. */
  margin: 0 0 clamp(1.15rem, 2.2vw, 1.55rem);
  font-size: clamp(1.42rem, 2.5vw, 2rem);
  line-height: 1.16;
  letter-spacing: -0.022em;
  color: var(--on-dark);
}

.sysli { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(.95rem, 1.7vw, 1.35rem); }
.sysli li { display: grid; grid-template-columns: 2.6rem minmax(0, 1fr); align-items: start; }

.sysli__n {
  font-family: var(--body);
  font-weight: 700;
  font-size: clamp(.72rem, .95vw, .8rem);
  letter-spacing: .1em;
  color: var(--gold-bright);
  font-variant-numeric: tabular-nums;
  padding-top: .28rem;
}
.sysli__s {
  display: block;
  font-size: clamp(1rem, 1.28vw, 1.12rem);
  font-weight: 600;
  line-height: 1.34;
  letter-spacing: -0.012em;
  color: var(--on-dark);
}
.sysli__d {
  display: block;
  margin-top: .3rem;
  font-family: var(--body);
  font-size: clamp(.86rem, 1.05vw, .96rem);
  line-height: 1.55;
  /* Measured against --navy, not against ink: this section is the navy ground.
     .62 composites to 6.4:1 there. */
  color: rgba(242, 239, 232, .62);
}

.sysrow__media {
  border-radius: 5px;
  overflow: hidden;
  border: 1px solid rgba(242, 239, 232, .12);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .45);
}
.sysrow__media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 8 / 5;
  object-fit: cover;
}

@media (max-width: 880px) {
  .sysrow { grid-template-columns: minmax(0, 1fr); gap: clamp(1.4rem, 4vw, 1.9rem); }
  /* Both orders reset: stacked, the photograph always follows its own heading,
     which is the only arrangement where a row still reads as one row. */
  .sysrow--flip .sysrow__txt { order: 0; }
  .sysrow__media { order: 0; }
}

/* ---------- the panels: a fake interface, honestly drawn ---------- */
/* Technique read off hiddengem.media 2026-09-17 at Ryan's request. There is no
   library behind theirs: no Lottie, no canvas, no SVG, no video. Divs and spans
   with percentage widths, rounded pills standing in for text, and hand-written
   keyframes. Twenty-five CSS rules drive a hundred and sixteen elements.

   Three things worth copying, and they did all three:
     - one clock. Every element in a panel shares the same duration, so the
       panel plays as one choreographed loop instead of a pile of independent
       twitches. Stagger comes from animation-delay, never from a second
       duration.
     - the resting state IS the finished state. Nothing here depends on an
       animation having run: with every animation stripped the panel still
       reads as a populated interface. That is what makes the reduced-motion
       rule at the bottom a one-liner instead of a second design.
     - gate on the viewport. Four panels times roughly forty elements is a lot
       of compositing to run behind the fold forever.

   One thing not to copy: they ship no prefers-reduced-motion rule at all. */

.mk {
  display: flex;
  flex-direction: column;
  aspect-ratio: 8 / 5;
  background: #070C11;
  overflow: hidden;
}

.mk__chrome {
  flex: none;
  display: flex;
  align-items: center;
  gap: 3%;
  height: 13%;
  padding: 0 4%;
  border-bottom: 1px solid rgba(242, 239, 232, .10);
}
/* The one piece of brand in the whole panel. It is the same rotated square as
   the gold diamond used elsewhere on the site, at the size a favicon would be
   in a real browser chrome. */
.mk__dot { flex: none; width: 9px; height: 9px; transform: rotate(45deg); background: var(--gold); }
.mk__field { flex: 1; min-width: 0; height: 40%; max-height: 17px; border-radius: 999px; background: rgba(242, 239, 232, .055); }
.mk__btn { flex: none; width: 12%; height: 40%; max-height: 17px; border-radius: 999px; border: 1px solid rgba(242, 239, 232, .11); }

.mk__body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 5%; padding: 5% 4%; }

/* --- 01 the funnel: 140 arrive, one is chosen ---
   Prototyped and approved as its own artifact 2026-09-17 before landing here.
   It is the one panel of the four that runs on a beat machine rather than a
   single looping keyframe, because it tells four things in order and the
   fourth only means anything after the third: a hundred and forty properties
   arrive, a hundred and thirty-nine fall away, the survivor turns gold, and
   only then does it become the diamond. A keyframe can hold that timeline but
   not survive being edited; named beats can.

   The count is the argument. Step 01 beside it claims 100 to 150
   opportunities, so the grid draws 140, a real number inside the range rather
   than a round one that happens to tile neatly. Twenty columns by seven rows
   also draws each building LARGER than ten by ten did, which is not obvious:
   140 cells in a wide, short box come out at roughly 16 by 23, much closer to
   the building's own proportion than the 32 by 15 that ten columns gave, so
   almost none of each cell is spent centring the drawing inside it. */
.mk--funnel .mk__body { display: flex; }
.mk__grid {
  flex: 1; min-height: 0;
  display: grid;
  grid-template-columns: repeat(20, 1fr);
  grid-template-rows: repeat(7, 1fr);
  /* Row gap and column gap set separately: a percentage gap resolves against
     its own axis, and 2.2% of the width is 8.7px, nineteen of which would eat
     half the panel. */
  gap: 2.2% 1%;
}

.mk__tile {
  position: relative;
  display: block;
  color: #333E4D;
  opacity: 0;
  transform: scale(.72);
  transition:
    opacity calc(560ms / var(--beat, 1)) ease,
    transform calc(560ms / var(--beat, 1)) cubic-bezier(0, 0, .2, 1);
}

.mk__bld {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  transition:
    color calc(760ms / var(--beat, 1)) ease,
    opacity calc(420ms / var(--beat, 1)) ease;
}
.mk__bld .b { fill: currentColor; }
/* Windows are darker than their building, never lighter. Lit windows on a dark
   block made the window the brightest thing in the tile, so a field of
   buildings read as a field of dot clusters and the silhouette disappeared.
   A dark opening reads against slate and against gold alike, so the colour
   never has to change. */
.mk__bld .w { fill: #0B1017; }
/* The diamond's cuts are strokes, because a girdle is a line and a window is a
   hole. Three of them: a full brilliant cut is eight strokes converging on one
   point, which at fifteen pixels resolves to a smudge. */
.mk__bld .c { fill: none; stroke: #0B1017; stroke-width: .55; stroke-linecap: round; }

/* The diamond shares the building's cell and scale but not its footprint. A
   diamond is wider than tall and a building is taller than wide, so forcing
   them to fill the same box turned the gem into an ice cream cone. It sits
   centred in the same cell instead. It needs no colour rule of its own: .mk__bld
   already gives it position and a currentColor body, so it is gold the moment
   it appears. */
.mk__gem { opacity: 0; }

/* beat 2: all 140 arrive, blooming outward from the survivor */
.mk--funnel[data-beat="bloom"] .mk__tile,
.mk--funnel[data-beat="narrow"] .mk__tile,
.mk--funnel[data-beat="gem"] .mk__tile { opacity: 1; transform: none; }
.mk--funnel[data-beat="bloom"] .mk__tile { transition-delay: calc(var(--in) * 820ms / var(--beat, 1)); }

/* beat 3: 139 fall away from the outside in, and the survivor turns gold.
   .18, not zero: the whole claim is one out of a hundred and forty, and one
   gold building alone in an empty box is just one building. The field is the
   denominator. */
.mk--funnel[data-beat="narrow"] .mk__tile:not(.mk__tile--pick),
.mk--funnel[data-beat="gem"] .mk__tile:not(.mk__tile--pick) {
  opacity: .18;
  transition-delay: calc(var(--out) * 900ms / var(--beat, 1));
}
.mk--funnel[data-beat="narrow"] .mk__tile--pick .mk__bld,
.mk--funnel[data-beat="gem"] .mk__tile--pick .mk__bld {
  color: var(--gold-bright);
  transition-delay: calc(420ms / var(--beat, 1));
}

/* beat 4: and only then, the survivor becomes the thing being looked for. The
   building goes first and the diamond follows it in, rather than the two
   dissolving through each other: at fifteen pixels a fifty-fifty blend of two
   gold shapes is a blob, and a blob is not a transformation. Nothing moves,
   nothing grows. */
.mk--funnel[data-beat="gem"] .mk__tile--pick .mk__bld { opacity: 0; transition-delay: 0ms; }
.mk--funnel[data-beat="gem"] .mk__tile--pick .mk__gem {
  opacity: 1;
  transition-delay: calc(300ms / var(--beat, 1));
}

/* --- 03 the screen: a laptop, drawn rather than sourced ---
   Ryan offered to find a photograph of a computer. Drawing it wins on three
   counts: it takes this site's palette instead of importing another
   photographer's lighting, it stays sharp at every size a photograph would
   not, and it costs 112KB for the screenshot rather than that plus a megabyte
   of laptop. It is also the only one of the four media boxes that holds
   evidence rather than illustration, so it is not hidden from a screen reader
   and its image carries a real alt.

   Proportions are load bearing. The lid's screen is 16:10 and the panel is
   8:5, so the padding here is what decides whether the machine fits: at 2% top
   and bottom and 10% at the sides the whole assembly comes to about 0.536 of
   the panel's width against 0.585 available, which leaves it room to sit
   rather than filling the box edge to edge. Widen the lid and the base runs
   out of panel. */
/* No frame on this one. Ryan 2026-09-17: the media box's border, fill and
   shadow drew a rectangle around a rectangle, and a laptop reads as an object
   only when it is sitting on something rather than inside something. The row
   keeps its 8:5 box so the four rows still line up; the box just stops being
   visible.

   The lid grows to fill what the frame used to occupy. The ceiling is
   arithmetic, not taste: lid height is .655 of the lid's own width once the
   screen's 16:10 and the 1.5% bezel are counted, plus about .02 of the panel
   width for the base, against .625 available. That puts the maximum lid width
   at roughly .92 of the panel. 5% of side padding leaves it just inside. */
.sysrow__media--bare {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
}

.mk--screen {
  display: grid;
  place-items: center;
  padding: 0 5%;
  background: none;
}
.lap { width: 100%; }

/* Aluminium, lit from the top left like everything else on this page. The
   inner hairline is what stops the lid reading as a flat grey rectangle. */
.lap__lid {
  padding: 1.5%;
  border-radius: 9px 9px 3px 3px;
  background: linear-gradient(158deg, #3A444F 0%, #222A33 40%, #151B21 100%);
  /* Two shadows, not one. The tight one seats the lid against the base; the
     wide one is what stops a frameless machine looking pasted onto the
     section. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .14),
    inset 0 0 0 1px rgba(255, 255, 255, .05),
    0 6px 14px rgba(0, 0, 0, .45),
    0 30px 60px rgba(0, 0, 0, .55);
}

.lap__scr {
  position: relative;
  display: flex;
  flex-direction: column;
  aspect-ratio: 16 / 10;
  border-radius: 3px;
  overflow: hidden;
  background: #0A0E13;
}

/* The browser bar is drawn, not captured. His own browser is not the point,
   and a screenshotted one carries whatever he happened to have open. */
.lap__bar {
  flex: none;
  height: 8%;
  display: flex;
  align-items: center;
  gap: 1.6%;
  padding: 0 2.2%;
  background: #1A2028;
}
.lap__bar i { flex: none; width: 4px; height: 4px; border-radius: 50%; background: rgba(242, 239, 232, .24); }
.lap__url { flex: 1; height: 46%; margin-left: 2%; border-radius: 999px; background: rgba(242, 239, 232, .08); }

.lap__scr img {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: block;
  object-fit: cover;
  object-position: top center;
}

/* One diagonal sheen, and a shallow one. Any more and it stops reading as
   glass and starts reading as a sticker. */
.lap__scr::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(108deg, rgba(255, 255, 255, .085) 0 18%, rgba(255, 255, 255, 0) 44%);
  pointer-events: none;
}

/* The base is what makes it a laptop rather than a monitor: wider than the
   lid, tapering, with the thumb notch cut out of the front edge. */
.lap__base {
  position: relative;
  width: 112%;
  margin-left: -6%;
  height: clamp(7px, 1.5vw, 12px);
  background: linear-gradient(180deg, #3E4854 0%, #232B34 55%, #131920 100%);
  clip-path: polygon(0 0, 100% 0, 97.5% 100%, 2.5% 100%);
}
.lap__base::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  width: 13%;
  height: 38%;
  border-radius: 0 0 5px 5px;
  background: rgba(0, 0, 0, .42);
}

/* ---- motion, only once the panel is on screen ---- */




/* The rent line does not move until the work orders are closed. That order is
   the phase's whole argument, so it is the one thing in this panel that is
   timed against the others rather than staggered off them. */



/* Asked for less motion, gets none. Every panel still reads, because the
   resting state is the finished state. */
@media (prefers-reduced-motion: reduce) {
  .mk, .mk * { animation: none !important; transition: none !important; }
}


/* ---- the closing CTA on a phone ----
   Below 760px the scene is too short to host the CTA: at 390 wide it renders
   98.5px tall against a 162.3px CTA box. So the CTA leaves the absolute
   layer and flows above the skyline instead, and the scene sizes to its
   contents rather than to a fixed ratio.

   Everything the desktop layout relies on is scoped to the absolute position
   and goes with it: the inline `bottom` that lands the button on Waterline's
   tip is inert on a static box, and the box no longer needs to be inside the
   clipped scene for the glow to be contained, because it is not overflowing
   anything. .foot__cta's own 1.4rem of bottom padding survives and becomes
   the gap between the button and the rooflines, which is what it always was.

   Measured at 390x844 before: heading absent, button sliced through the
   middle. After: both whole. */
@media (max-width: 760px) {
  .foot__scene { aspect-ratio: auto; overflow: visible; }
  /* The background matters as much as the position here. Absolutely
     positioned, the CTA sat ON the sky and inherited it. In normal flow it
     sits ABOVE the svg, and what shows behind the heading is .foot__scene's
     own ground colour, #0E0D09, which is black. Ryan, on a phone: "on
     desktop the background colour for the heading and CTA is all a
     consistent blue. On mobile, there is a black background." --join is the
     colour the sky gradient's own first stop uses, so the riser above the
     CTA, the CTA itself and the svg's top edge are all the same value and
     the sky simply starts higher. */
  .foot__cta { position: static; background: var(--join); }

  /* Ryan 2026-09-21: "I want there to be more padding between the Read All
     FAQs and the Ready To Become A Top Producing Investor headline, similar to
     the same space we have on desktop."

     On a desktop width that space is mostly sky: the section's own 104px of
     bottom padding, then a riser that takes whatever is left of the viewport,
     which at 1728x965 is another 145px. On a phone the panel already fills the
     screen, so the riser collapses to about 4px and the gap falls to 65.

     This pays the difference directly. It does NOT move the heading: at rest
     the panel's bottom is pinned to the page bottom and everything is measured
     up from there, so padding added ABOVE the heading grows the panel upward
     and the heading stays exactly where it was. What it moves is the section
     above, which is the thing Ryan is asking to push away. Measured at
     390x844: the gap goes from 65px to 195, against 254 on the desktop
     reference. */
  .foot__cta { padding-top: clamp(88px, 16vh, 144px); }
}

/* The "Read All FAQs" button under the homepage accordion. Centred on both
   widths, Ryan 2026-09-21, deliberately against the left-aligned heading and
   question list above it: it is the one action in a section that is otherwise
   all reading, and centring is what separates it from the list. The margin was
   an inline style on the <p> and moved here with it, so the two properties
   that make this button what it is sit together. */
.faqmore { margin-top: 2.2rem; text-align: center; }

/* The line under "Investor Sign Up", Ryan 2026-09-21: tell them what they are
   actually signing up for before they fill anything in. It sits between the
   heading and the first field, so it has to read as a subheading rather than
   as another paragraph of body copy: smaller than the labels below it, and on
   --on-dark-soft so the labels stay the brightest thing in the card. */
/* The end pages (/thank-you, /confirmed) are a heading, two lines and a
   button, and the skyline starts immediately under them. Ryan 2026-09-21:
   "add more space of padding below the CTA so that there's a little bit of
   breathing room before we get to the bottom of the page." The button was
   101px clear of the scene; this takes it to roughly 300 on a laptop and
   scales down rather than eating a phone screen. */
.section--endpage { padding-bottom: clamp(120px, 14vh, 240px); }

/* investments@topproducerinvestmentcapital.com is 409px of unbreakable string
   and a 375px phone gives it 327. It ran 58px past the edge and the tail was
   silently cut, because the section clips its overflow: the reader saw
   "...topproducerinvestmentcapit" and no way to get the rest, on the one line
   whose whole job is to tell them what to look for in their spam folder.
   The <wbr> tags say where it may break; this says it may break at all, for
   any address that turns up here later without them. */
.wrapany { overflow-wrap: anywhere; }

.formlead {
  margin: 0 0 1.5rem;
  font-size: .92rem;
  line-height: 1.55;
  color: var(--on-dark-soft);
  /* No measure cap. Ryan 2026-09-21: "subheading should not be fixed width."
     A 46ch cap broke it at three lines inside a card that is already only
     640px wide, so it read as a narrow column inside a narrow column. The
     card is its own measure. */
}
