/* ==========================================================================
   HOMUS salesperson trust page. Prism, render 5, 07-09-2026. Example: Jeff.
   Palette "Warm Stone", frozen in Homus HQ/design.md 02-09-2026. No new colours.
   Single light theme on purpose: the build target inherits Homus's theme and
   the brand has no dark mode, so inventing one here would invent a decision.
   Designed at 390px first. Near 100% of traffic is a tap from WhatsApp.

   RENDER 2, from Kyler 07-09-2026: circular hero photo over a warm band with
   the name below and never beside; a credential strip under the name; a
   personal quote high in the display face; both strips auto-advancing on
   transform, never scrollLeft (see the JS header for why that is not
   negotiable).

   RENDER 3, from Kyler on his phone, 07-09-2026. Five amendments:
   1. The pull-quote's opening mark did not render. It was &ldquo; in Fraunces;
      it is now inline SVG, and so is every other mark and arrow on the page.
   2. Review cards no longer hold a portrait aspect. Height follows content,
      the four-line clamp bounds the tallest card, and the footer became one
      filled 46px bar instead of two loose fragments on a hairline.
   3. The review ask was rebuilt out of the page's own type and buttons. The
      bordered box, the four-colour Google G and the outlined pill are gone.
   4. Every project photo renders in ONE frame, 1080 x 1350 (portrait 4:5), object-fit cover,
      set by --proj-aspect and nothing else.
   5. Company block: four stat squares with icons, and the dated footer removed.

   Also raised on Kyler's second research sweep: the hero circle from 41vw to
   51vw, about 199px on a 390 screen.

   RENDER 4, 07-09-2026, two changes and no layout change:
   a. The project frame flipped to PORTRAIT 1080 x 1350 -- Kyler corrected his
      own render-3 spec, which had said 1350 x 1080.
   b. The display face is Newsreader, not Fraunces: "use a different font, this
      font is jiggly." Brand-wide, not page-level -- Fraunces has never shipped
      anywhere. See the note on --display below, and Homus HQ/design.md.

   RENDER 5, 07-09-2026. A COPY pass, and one defect CLASS, not a list of fixes.

   ⚠ THE PAGE STATES THINGS. IT NEVER NARRATES ITSELF.
   Kyler found seven sentences in one sitting that describe how the page works,
   where its content comes from, what it excludes, or why it should be believed
   -- faster than they were being fixed one at a time, which is the signal that
   it is a class. All seven are gone, and a sweep of every eyebrow, sub-line,
   caption and footer found three more, also gone. A stranger deciding whether
   to trust Jeff does not care how the count is derived, and a page that keeps
   explaining itself sounds like one that expects to be doubted.

   Every honest-design property those sentences claimed to carry is carried by
   the DESIGN and survives their deletion, which is the proof they were never
   load-bearing: proof separation is MATERIAL (hairline white cards on white for
   Jeff's own reviews, a solid stone slab with gold numerals for the company's),
   and the review count is self-verifying because it IS the cards. DO NOT
   reintroduce any of them in another form.

   The rest of render 5:
   a. Company block flipped positive. "HOMUS THE COMPANY, NOT JEFF" and "these
      are Homus's numbers, not Jeff's" were de-sells, which breach the standing
      rule that outranks every playbook (memory/sell-the-product-not-the-facts).
      It became "More about us" in render 5 and "The company behind Jeff /
      Homus" in render 6.
   b. Review ask is Kyler's copy, verbatim, and it qualifies on satisfaction.
   c. Masthead is the HOMUS wordmark in POPPINS BOLD, live text and not an
      image. See the note on --wordmark below.
   d. Jeff is a SALES MANAGER, not a sales consultant. Title is a per-person
      field and never a default.
   e. SME500 sits beside three numerals without reading as a failed number.
      See the note on .stat .v.mark.

   RENDER 6, 07-09-2026. A COPY pass on four blocks, plus two real numbers.

   a. COMPANY BLOCK, Kyler's reversal and his dictated direction. Eyebrow "The
      company behind Jeff", heading "Homus", and a lede rewritten from his own
      words: advisory-driven rather than transactional, fixture choices that fit
      lifestyle, design and taste, deep technical knowledge, a smoother
      renovation. Ran through the humanizer, which is what he asked for; his
      draft carried "it's" for "its" and "smoothen".
      ⚠ This is NOT the return of the line he rejected. He rejected "HOMUS THE
      COMPANY, NOT JEFF", the NEGATION. Do not re-raise the pairing.
      ⚠ With his name in the eyebrow, proof separation now rests on the MATERIAL,
      on a one-word company name as the heading, and on two of the four squares
      being unreadable as a person. Measured, see the note on the section.
   b. WHATSAPP BLOCK. Heading is "Contact Jeff on WhatsApp"; the sub-line "Ask
      him anything before you come down" is DELETED. It presumed the reader was
      already coming down, which is the decision the button is asking for. The
      43px it freed went back into the button gap, not into new copy.
   c. YEARS ON THE FLOOR IS REAL. Jeff 2 (Stanley 4, Sze Yee 1, per Kyler
      07-09-2026). The greyed .pend treatment comes off it. HOMES FITTED STAYS
      GREYED at 80 until Otto returns the lifetime invoice count.
   d. THE PULL-QUOTE IS JEFF'S. From the provisional set in
      Homus HQ Resources/SalespersonBrandingProgram.md, derived from his own
      reviews (patient x16, helpful x18, friendly x13).
      ⚠ Kyler ruled these ship with NO visible provisional marking: "Use this
      until they decide to amend." SETTLED. Do not mark it, gate it or re-raise
      it. Swapping in his real sentence later is a copy edit, not a re-approval.
   ========================================================================== */
:root{
  color-scheme: light;

  --ink:#1B1614;        /* 17.9:1 on white   body + headings        */
  --ink-2:#5A4A42;      /*  8.4:1 on white   secondary              */
  /* ⚠ CORRECTED 07-09-2026, and design.md is corrected to match.
     The frozen token was #877569, recorded there as 4.6:1 on white. Measured,
     it is 4.39:1 on white, 3.95:1 on --band and 3.53:1 on --band-2, so every
     meta label on render 1 was below AA, on a page whose whole premise is
     that a stranger can read it. This is the same hue (22.8deg against 24deg)
     darkened until it passes on all three grounds it actually sits on:
     5.70:1 white, 5.12:1 --band, 4.58:1 --band-2. Kyler's call to keep. */
  --ink-3:#756358;

  --ground:#FFFFFF;
  --band:#F6F2EF;
  --band-2:#EDE5DF;
  --line:#E3DAD3;
  --line-2:#CFC2B8;

  --stone:#3A2E28;      /* 13.1:1  derived from the live #AA9991 hue */
  --stone-2:#251D19;
  --on-stone:#EFE6E0;   /* 10.4:1 on --stone */
  --on-stone-2:#D6C7BE; /*  7.6:1 on --stone */
  --on-stone-3:#B3A198; /*  4.9:1 on --stone */
  --stone-line:#4C3C34;

  --clay:#9A4A21;       /* white on it: 6.2:1. The WhatsApp ask, nothing else */
  --clay-hi:#7C3A18;

  --greige:#AA9991;     /* 2.74:1  NEVER behind text. Rules, marks, tints  */
  --gold:#C9A24B;       /* 7.5:1 on --stone only                          */

  --shadow-1:0 1px 2px rgba(27,22,20,.05), 0 4px 14px rgba(27,22,20,.05);
  --shadow-2:0 2px 6px rgba(27,22,20,.08), 0 14px 34px rgba(27,22,20,.10);

  /* ⚠ DISPLAY FACE CHANGED 07-09-2026, brand-wide, on Kyler's call: "use a
     different font, this font is jiggly." He was looking at the name in
     Fraunces. Fraunces is a soft, deliberately irregular face and WONK 0 was
     already turning down as much of that as the axis allows; what he saw is
     what was left. Newsreader replaces it — Production Type, opsz 6..72,
     low stroke contrast, conventional letterforms, no wonk axis. It keeps a
     real display voice (this page is NOT solving jiggly by going bland) and
     its numerals hold at 26px in gold on the dark slab, which a Didone's
     hairlines would not. Georgia is now a genuinely close fallback rather
     than a distant one. Recorded in Homus HQ/design.md. */
  --display:"Newsreader","Iowan Old Style",Georgia,serif;
  --body:"Montserrat","Helvetica Neue",Arial,sans-serif;

  /* ⚠ RENDER 5. A THIRD TYPE ROLE: the wordmark face, and only the wordmark.
     Kyler, 07-09-2026: "use this homus logo on the header instead of just
     random words. Our logo font is Poppins Bold." The masthead had been HOMUS
     set in the display face at .24em, which is display type pretending to be a
     logo, and he read it as exactly that.
     It is LIVE TEXT, not an image, and that is a decision rather than a
     shortcut: the logo is a pure type wordmark, so text reproduces it exactly,
     stays crisp at any size, needs no asset request, and inverts for free if it
     ever lands on the dark slab. Decisive: the artifact CSP blocks external
     image hosts, so a logo file served from homussingapore.com would render as
     nothing on the phone Kyler actually checks this on.
     Poppins was already a recorded Homus brand standard for roadshow banners
     (Homus HQ/events.md) and had never reached design.md. It is now a third
     role there. It does NOT replace the display or the body face. */
  --wordmark:"Poppins","Helvetica Neue",Arial,sans-serif;

  --pad:clamp(20px,5.6vw,56px);
  --maxw:1080px;

  /* RENDER 3: raised from clamp(148px,41vw,176px) on Kyler's second research
     sweep. 51vw of a 390 screen is 199px. The circle is the first thing on the
     page and it was reading small against the name beneath it. */
  --av:clamp(176px,51vw,208px);
  --cardw:clamp(238px,72vw,320px);
  --cgap:12px;

  /* ⚠ THE PROJECT FRAME. ONE TOKEN, ONE FRAME, EVERY PHOTO.
     1080 x 1350, PORTRAIT 4:5. Kyler corrected his own "1350 x 1080" to this on
     07-09-2026. Every project photo renders into this box with object-fit:cover
     regardless of what came off the salesperson's phone, so a strip of thirty
     uploads never goes ragged. Portrait also suits the subject: a shower or a
     run of cabinetry is a tall thing. One token; nothing else moves. */
  --proj-aspect:1080 / 1350;

  /* The company-slab value size, hoisted so the word-mark square can be sized
     off it rather than repeating the clamp. See .stat .v.mark. */
  --statv:clamp(26px,7.2vw,33px);
  --markf:1.0217;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  background:var(--ground);
  color:var(--ink);
  font-family:var(--body);
  font-size:16px;
  line-height:1.6;
  overflow-x:hidden;
  padding-bottom:92px;              /* clears the sticky WhatsApp bar */
}
img,svg{max-width:100%;display:block}
a{color:inherit}
h1,h2,h3{font-family:var(--display);font-weight:600;margin:0;line-height:1.12;
  text-wrap:balance}
p{margin:0}
button{font:inherit}
:focus-visible{outline:3px solid var(--clay);outline-offset:3px;border-radius:2px}

.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--pad)}
.eyebrow{display:block;font-size:11.5px;font-weight:600;letter-spacing:.17em;
  text-transform:uppercase;color:var(--ink-3)}
.num{font-variant-numeric:tabular-nums}

/* ---------- masthead ---------------------------------------------------- */
.masthead{border-bottom:1px solid var(--line);background:var(--ground)}
.masthead .wrap{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding-block:15px}
/* ⚠ RENDER 5. Was the display face at 19px / .24em, which is why it read as
   "just random words" rather than a logo. A wordmark holds together; letter-
   spacing that wide pulls it apart into six separate characters. Poppins Bold,
   modest tracking, sized so its cap height sits level with the showroom label
   opposite it. */
.logo{font-family:var(--wordmark);font-size:21px;font-weight:700;letter-spacing:.055em;
  line-height:1;color:var(--ink)}
.masthead .where{font-size:11.5px;font-weight:600;letter-spacing:.13em;text-transform:uppercase;
  color:var(--ink-3);text-align:right}

/* ---------- hero -------------------------------------------------------- */
/* A circle overlapping a warm band that carries the name. The circle throws
   away the background of an amateur phone photo and has no straight edge to
   expose a crooked horizon. It is also the shape the customer just tapped in
   the WhatsApp profile, so the recognition is free. */
.hero{position:relative;overflow:hidden}
.hero-top{height:calc(var(--av) * .67);background:var(--ground)}
.hero-body{
  background:var(--band-2);
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
  padding-top:calc(var(--av) * .33 + 22px);
  padding-bottom:26px;
  text-align:center;
  position:relative;
}
.hero-body::before{                    /* depth, not decoration for its own sake */
  content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(78% 120% at 50% -18%, rgba(170,153,145,.42) 0%,
             rgba(170,153,145,0) 66%);
}
.hero-body .wrap{position:relative}

.avatar{
  position:absolute;top:0;left:50%;transform:translateX(-50%);z-index:3;
  width:var(--av);height:var(--av);border-radius:50%;overflow:hidden;margin:0;
  box-shadow:0 0 0 5px var(--ground);   /* a thin white stroke. No drop shadow */
  background:
    radial-gradient(110% 90% at 58% 14%, #C9B7AD 0%, rgba(201,183,173,0) 64%),
    linear-gradient(168deg, var(--band-2) 0%, var(--greige) 48%, var(--stone) 100%);
}
.avatar .figure{position:absolute;inset:0;display:grid;place-items:end center}
.avatar .figure svg{width:74%;height:auto;opacity:.34}
.ph-chip{position:absolute;left:50%;bottom:9px;transform:translateX(-50%);z-index:4;
  background:rgba(37,29,25,.86);color:var(--on-stone);font-size:9.5px;font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;padding:5px 9px;border-radius:2px;
  white-space:nowrap}

.hero h1{font-size:clamp(30px,8.2vw,44px);letter-spacing:-.015em}
.hero .role{margin-top:10px;font-size:13.5px;font-weight:600;color:var(--clay);
  letter-spacing:.02em}

/* the credential slot. Every mature page in this genre puts a checkable line
   directly under the name. A Homus salesperson has no licence number, so this
   is what fills it: a distinct plate, not body copy. */
.cred{margin-top:20px;background:var(--ground);border:1px solid var(--line);
  border-radius:2px;box-shadow:var(--shadow-1);
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr))}
.cred-i{padding:14px 8px 15px;min-width:0}
.cred-i+.cred-i{border-left:1px solid var(--line)}
.cred-i .v{display:block;font-family:var(--display);font-size:clamp(24px,6.4vw,30px);
  font-weight:600;line-height:1;font-variant-numeric:tabular-nums}
.cred-i .v.pend{color:var(--ink-3)}
.cred-i .k{display:block;margin-top:7px;font-size:11px;line-height:1.35;font-weight:500;
  color:var(--ink-2)}
/* ⚠ RENDER 5. .cred-note is GONE. It said "that last number is the reviews
   below it, counted. Every one links to Google." The number IS the card count
   in code, and every card IS a link, so the sentence was describing something
   the reader can check by scrolling. Explaining a proof is what a page does
   when it does not trust its own proof. */

/* ---------- personal quote. The one part written by the person. --------- */
.quote-sec .wrap{padding-block:38px 40px;position:relative}
.pq{margin:0;position:relative;padding-top:40px}
/* ⚠ 14px until 07-09-2026. The mark is 31px tall at top:-4, so it ended 27px
   into the block and the first line box began at 14 -- a 10px collision,
   measured, that Fraunces' unusually short ascenders had been hiding. The
   moment the face changed to Newsreader the ink walked into the mark. 40px
   clears it by 13 and the mark now reads as a deliberate element above the
   line rather than a smudge across it. */
/* ⚠ RENDER 3. The opening quote was &ldquo; set in Fraunces at 76px and it did
   not render on Kyler's phone. A decorative mark that depends on a webfont
   arriving is a mark that ships broken to whoever the font fails for, and on a
   page whose whole job is looking trustworthy in the first two seconds that is
   the worst possible thing to leave to chance. It is now inline SVG: no glyph,
   no font, no fallback stack, currentColor. */
.pq .qm{position:absolute;top:-4px;left:-2px;width:clamp(40px,11vw,52px);height:auto;
  color:var(--greige);pointer-events:none}
.pq .qm svg{width:100%;height:auto}
.pq p{position:relative;font-family:var(--display);font-weight:500;
  font-size:clamp(23px,5.9vw,34px);line-height:1.3;letter-spacing:-.005em;
  color:var(--ink);max-width:22ch;text-wrap:pretty}
.pq-by{margin-top:18px;padding-top:14px;border-top:1px solid var(--line);
  font-size:12.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);max-width:22ch}

/* ---------- generic section -------------------------------------------- */
.sec{padding-block:36px}
.sec.band{background:var(--band);border-block:1px solid var(--line)}
/* ⚠ RENDER 5. Both section sub-lines are GONE, and with them .sec-head p.
   Reviews said "Homus customers on Google who wrote his name. Swipe, or tap one
   to read the whole review" -- where the content comes from, plus instructions
   for operating a carousel. Projects said "Jeff adds these himself as jobs
   finish", which is the content pipeline explained to a customer who is not
   buying a content pipeline. Both sections now run eyebrow, heading, evidence.
   The affordances they described are carried by the cards: a peeking card is
   how a strip says swipe, and the filled footer bar is how a card says tap. */
.sec-head{max-width:50ch}
.sec-head h2{margin-top:10px;font-size:clamp(24px,6.4vw,33px);letter-spacing:-.01em}

/* ---------- the carousel. One component, used twice, so the two strips
   read as one system. Motion is transform-only: see the JS header. ------- */
.car{position:relative;margin-top:22px}
.car-vp{overflow:hidden}
.car-track{display:flex;gap:var(--cgap);align-items:stretch;will-change:transform;
  touch-action:pan-y;
  padding-inline:max(var(--pad), calc((100% - var(--maxw))/2 + var(--pad)))}
.car-track.dragging{cursor:grabbing}
.card{flex:0 0 var(--cardw);min-width:0;display:flex;flex-direction:column}

/* ⚠ RENDER 3. The arrows are absolutely positioned over the strip, and at 390
   that means a 44px disc sitting on top of the first character of every review
   and half the author's name. Measured, not guessed: the left disc covers
   x 5..49 and the card's text starts at x 22. On a page whose job is being
   read, that is not a decoration problem.
   They are hidden below 680 and returned above it. Touch already has drag with
   momentum, and the strip advances itself, so nothing is lost on a phone. The
   ≥680 rule lives in the one breakpoint block at the bottom. */
.car-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:6;display:none;
  width:44px;height:44px;padding:0;border-radius:50%;background:var(--ground);
  border:1px solid var(--line-2);box-shadow:var(--shadow-2);cursor:pointer;
  place-items:center;color:var(--ink);
  transition:border-color .18s ease,background .18s ease}
.car-nav:hover{border-color:var(--greige);background:var(--band)}
.car-nav svg{width:19px;height:19px}
.car-prev{left:5px}
.car-next{right:5px}

/* THIN STATE. At two items or fewer the strip becomes a stack: no peek, no
   arrows, no motion. The peek is a promise of more content, and with two
   cards the next one is a repeat, which is what makes a short carousel read
   as broken. A stack has nothing to promise, so it survives 1, 2 and 30. */
.car.is-static .car-track{flex-direction:column;gap:14px;transform:none !important}
.car.is-static .card{flex:0 0 auto;width:100%}
.car.is-static .car-nav{display:none}
/* ⚠ RENDER 5. .thin-note is GONE, and so is the element that hosted it. It read
   "Jeff started posting jobs this month. More go up as they finish", which is
   an empty-state apology. A thin section that says nothing reads as new; one
   that apologises reads as lacking. Two projects presented without comment are
   two projects. The stack-at-two rule above is what makes that state look
   deliberate, and it needs no sentence beneath it. */

/* ---------- review card. Personal proof: hairline white on white. ------- */
/* ⚠ RENDER 3, Kyler: the portrait card was wrong and it was wrong for a
   structural reason, not a taste one. Homus reviews are mostly one or two
   lines, so a fixed 1.42 portrait box around "Great service, very patient!"
   is roughly two thirds empty. THE SHORT REVIEW IS THE NORMAL CASE and the
   card is now sized for it.
   No min-height. Height comes from content. The strip stays level because the
   track is a flex row with align-items:stretch, so every card takes the height
   of the tallest one in the set, and the four-line clamp below is what keeps
   that tallest one from being tall. Two lines against a four-line ceiling is a
   card that looks full; two lines against a portrait box is a card that looks
   broken. */
.rev{position:relative;text-decoration:none;background:var(--ground);
  border:1px solid var(--line);border-radius:2px;padding:16px 16px 0;
  display:flex;flex-direction:column;overflow:hidden;
  transition:border-color .18s ease,box-shadow .18s ease}
.rev:hover{border-color:var(--greige);box-shadow:var(--shadow-1)}
.gbadge{position:absolute;top:12px;right:12px;width:30px;height:30px;border-radius:50%;
  background:var(--ground);border:1px solid var(--line);display:grid;place-items:center;
  box-shadow:var(--shadow-1)}
.gbadge svg{width:15px;height:15px}
.stars{display:flex;gap:2px}
.stars svg{width:14px;height:14px}
.rev .who{margin-top:11px;font-size:15px;font-weight:600;line-height:1.3;padding-right:34px}
.rev .when{margin-top:3px;font-size:12.5px;color:var(--ink-3)}
.rev .text{margin-top:11px;margin-bottom:14px;font-size:14.5px;color:var(--ink-2);
  display:-webkit-box;-webkit-line-clamp:4;line-clamp:4;-webkit-box-orient:vertical;
  overflow:hidden}
/* In the stack, a card is full width and owns its own height, so the longest
   review here is about four lines anyway. Nothing is hidden in the state most
   salespeople will actually be in. */
.car.is-static .rev .text{-webkit-line-clamp:none;line-clamp:none;display:block;
  overflow:visible}

/* ⚠ RENDER 3, Kyler: "the bottom 'verified on google' and 'read it' isn't
   properly buttoned." It was two loose fragments on a hairline. It is now one
   filled bar, bled to the card's own edges, 46px tall, that reads as the
   card's target. THE WHOLE CARD IS STILL THE ANCHOR: the bar is what the eye
   and the thumb aim at, not a second link competing with the first. */
.rev .foot{margin-top:auto;margin-inline:-16px;padding:0 15px;min-height:46px;
  background:var(--band);border-top:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  transition:background .18s ease}
.rev:hover .foot{background:var(--band-2)}
.verified{font-size:12px;font-weight:600;color:var(--ink-2)}
.readon{display:inline-flex;align-items:center;gap:5px;font-size:13px;font-weight:600;
  color:var(--ink);white-space:nowrap}
.readon svg{width:13px;height:13px;flex-shrink:0}
/* ⚠ RENDER 5. .rev-foot is GONE. It said "Homus doesn't pick which of these
   show up. If a review names Jeff, it's here." Nobody had accused the page of
   curating, and protesting an impartiality that was never questioned is how a
   page invents its own doubt. */

/* ---------- the review ask. Visible, and never a peer of WhatsApp. ------
   It speaks to someone who has already bought. The qualifying line is the
   hierarchy device: it self-selects a different reader, so it cannot compete
   with the WhatsApp button for the stranger who is still deciding. */
/* ⚠ RENDER 3, Kyler: "good idea, but design is very off what's uniformed of
   the page." He was right. Render 2 gave this its own bordered box, its own
   26px four-colour Google G and its own outlined pill, which is three visual
   devices the rest of the page does not use anywhere else. It read as a
   third-party widget somebody pasted in.
   Rebuilt out of the page's own parts and nothing else: the same .eyebrow, the
   same display h-level one step down, the same body size, and the same .btn as
   WhatsApp with the fill taken off. Same family, plainly subordinate. The
   Google G is gone, and the clay is NOT spent here: design.md reserves it for
   showroom actions, and asking for a review is not one. A hairline rule
   separates it from the reviews so it does not read as an eleventh card. */
/* ⚠ RENDER 5. Kyler's copy, verbatim, two lines and no third:
     "Purchased and happy with his service? / Name him in your review"
   The third line ("a review that mentions him by name shows up here") is GONE
   as part of the sweep. The button says what to do; how the review reaches this
   page is not the customer's problem.
   The question is NOT set as .eyebrow. At 11.5px uppercase on .17em tracking it
   measures within 10px of the whole content width at 390 and wraps at the first
   long name, and a shouted tracked question reads as a banner rather than as
   someone asking. It takes the register the hero .role already established on
   this page: sentence case, 13.5px, weight 600. Same family, not a new device.
   It also does the hierarchy work: qualifying on satisfaction self-selects a
   reader who has already bought, so this can never compete with WhatsApp for
   the stranger who is still deciding. */
.ask{margin-top:26px;padding-top:24px;border-top:1px solid var(--line-2)}
.ask .lead{display:block;font-size:13.5px;font-weight:600;line-height:1.4;
  letter-spacing:.01em;color:var(--ink-3);max-width:34ch}
.ask h3{margin-top:7px;font-size:clamp(20px,5.2vw,26px);letter-spacing:-.008em}

/* ---------- project card ----------------------------------------------- */
.proj{background:var(--ground);border:1px solid var(--line);border-radius:2px;
  display:flex;flex-direction:column;overflow:hidden}
/* ⚠ RENDER 3, Kyler: "project photo leave it at always showing 1350px x 1080px,
   fill to fit." One frame, every photo, no exceptions. The aspect lives in
   --proj-aspect and nowhere else. object-fit:cover is the "fill to fit": a
   portrait phone photo and a wide DSLR shot both come out as the same box with
   the middle kept, which is the only way a strip of thirty self-uploaded
   photos stays level. */
.proj .shot{position:relative;aspect-ratio:var(--proj-aspect);overflow:hidden;
  background:linear-gradient(150deg,var(--band-2) 0%, var(--greige) 100%)}
.proj .shot img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center}
.proj:nth-child(3n+2) .shot{background:linear-gradient(200deg,var(--band-2) 0%,#BCA79C 100%)}
.proj:nth-child(3n+3) .shot{background:linear-gradient(120deg,#D8CAC2 0%,var(--stone) 145%)}
.proj .shot .glyph{position:absolute;inset:0;display:grid;place-items:center}
.proj .shot .glyph svg{width:58px;height:58px;opacity:.36}
.proj .chip{position:absolute;top:11px;right:11px;background:rgba(255,255,255,.94);
  color:var(--ink-2);font-size:10px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;padding:5px 8px;border-radius:2px}
.proj .sample{position:absolute;left:11px;bottom:11px;background:rgba(37,29,25,.84);
  color:var(--on-stone);font-size:10px;font-weight:700;letter-spacing:.12em;
  text-transform:uppercase;padding:5px 8px;border-radius:2px}
.proj .body{padding:13px 14px 15px}
.proj .meta{font-size:11px;font-weight:600;letter-spacing:.11em;text-transform:uppercase;
  color:var(--ink-3)}
.proj .cap{margin-top:6px;font-size:14px;color:var(--ink-2)}
.proj .cap em{color:var(--ink-3);font-style:italic}

/* ---------- company proof. A SOLID SLAB. Not a card, on purpose. -------- */
.company{background:var(--stone);color:var(--on-stone)}
.company .wrap{padding-block:36px}
.company .tag{display:inline-block;background:var(--gold);color:var(--stone-2);
  font-size:11px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  padding:6px 10px;border-radius:2px}
.company h2{margin-top:14px;font-size:clamp(23px,6vw,31px);color:#FFFFFF}
.company .lede{margin-top:11px;font-size:14.5px;color:var(--on-stone-2);max-width:48ch}
/* ⚠ RENDER 3, Kyler: four stat squares with icons, and the dated footer gone.
   The two Business-Profile rating cards are retired.
   ⚠ THIS RAISES THE SEPARATION RISK, IT DOES NOT LOWER IT. Two cards labelled
   with a showroom name each were self-evidently about a place. Four bare
   numerals are the kind of thing a reader will happily read as being about the
   man whose face is at the top of the page. So the separation is carried three
   ways at once and none of them is a caption you could skim past: the gold chip
   above them, a lede that says whose numbers these are in plain words, and the
   material itself. Gold numerals on a solid stone slab cannot be confused with
   the hairline white review cards on white, because they are not made of the
   same thing. */
.stats{margin-top:22px;display:grid;gap:12px;grid-template-columns:repeat(2,minmax(0,1fr))}
.stat{aspect-ratio:1;min-width:0;background:var(--stone-2);
  border:1px solid var(--stone-line);border-radius:2px;padding:14px 11px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center}
.stat .ic{width:26px;height:26px;margin-bottom:9px;color:var(--gold);opacity:.9}
.stat .ic svg{width:100%;height:100%}
.stat .v{font-family:var(--display);font-size:var(--statv);font-weight:600;
  line-height:1;color:var(--gold);font-variant-numeric:tabular-nums}
.stat .k{margin-top:8px;font-size:11.5px;line-height:1.35;font-weight:500;
  color:var(--on-stone-2)}

/* ⚠ RENDER 5. THE SME500 SQUARE. Prism's own flag from render 4, and Kyler's
   to hand back solved: a six-character word-mark was sitting in a slot built
   for numerals, in the numeral face, at the numeral size, and it read as the
   one square that had failed to load a number.

   The fix is not to shrink it or to invent a quantity out of it. It is to let
   it declare itself as a NAME while keeping the square structurally identical
   to the other three: icon, value, unit. Two moves.

   1. THE FACE. It is set in the body face, uppercase, tracked. A reader stops
      trying to parse a word as a figure the moment it stops being dressed as
      one, and the square reads as an award mark rather than a broken tally.
   2. THE SIZE IS MATCHED BY CAP HEIGHT, NOT BY FONT-SIZE. Newsreader's lining
      figures and Montserrat's caps do not share a cap height at the same
      font-size, so setting both to 28px leaves the word sitting visibly short
      of the "2" beside it in the second row. Measured with canvas
      actualBoundingBoxAscent at 280px, ten times up because the API returns
      whole pixels at 28: Newsreader 600 inks 205.625 for "2", "20,000" and
      "1,000+" alike (0.7344em, lining figures); Montserrat 700 inks 201.25 for
      "SME500" (0.71875em, caps). The word therefore has to be set 1.0217x the
      numerals to land on their cap line. --markf is that measurement.
      ⚠ I GUESSED 0.958 AND THE GUESS WAS WRONG IN BOTH DIRECTION AND SIZE.
      Re-measure this, never re-read it, if either face ever changes.

   3. AND THEN THE MEASUREMENT EXPOSED A WIDTH BIND WORTH KEEPING. A six-glyph
      word at the numerals' cap height is ~133px wide against "2" at 17px, and
      the square that has to hold it is at its NARROWEST exactly where --statv
      is at its widest: from 680 up the grid goes to four columns, so the square
      loses width (118.5px of usable inner at 680, against 145.2px at 390) while
      the clamp is pushing the type from 28px to 33px. Cap-matching alone
      overflows there, and only for this square: "20,000" needs 107px of the
      118.5 and fits.
      So the mark takes the SMALLER of the cap-matched size and a fraction of
      its own square, which makes it correct by construction at every width
      instead of at the widths anybody remembered to check. It lands cap-matched
      cap-matched at every width the page actually ships at, once the
      four-column breakpoint moved from 680 to 900 (see the second breakpoint
      block at the bottom, which is what that measurement forced). The 22cqw
      arm never binds in that range -- cap-matching needs 20.0cqw at 390 and
      21.2cqw at 900 -- so it is a safety net against a future narrower tile,
      not the operative constraint.
   The tracking is what a word-mark needs at that weight, and what the eye reads
   as deliberate rather than as condensed. */
.stat{container-type:inline-size}
.stat .v.mark{font-family:var(--body);font-weight:700;letter-spacing:.045em;
  font-size:min(calc(var(--statv) * var(--markf)), 22cqw)}

/* ---------- CTA. WhatsApp alone. The review ask already had its moment. - */
.cta .wrap{padding-block:42px}
.cta h2{font-size:clamp(25px,6.6vw,35px)}
/* ⚠ RENDER 6. .cta .sub is GONE and so is the rule that styled it. It said
   "Ask him anything before you come down." Kyler: "that just sounds wrong."
   He is right twice over. It presumes the reader is already coming down, which
   is the thing the button is asking them to decide; and "ask him anything" is
   the page instructing a stranger how to use WhatsApp. The block is now
   eyebrow, heading, button, which is what a CTA is. The gap the sub-line was
   occupying is given back to the button rather than backfilled with new copy
   -- see .cta .btn below. */
.btn{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;
  min-height:56px;padding:0 20px;border-radius:2px;text-decoration:none;
  font-size:15.5px;font-weight:600;letter-spacing:.01em;
  transition:background .18s ease,border-color .18s ease}
.btn svg{width:19px;height:19px;flex-shrink:0}
.btn-primary{background:var(--clay);color:#FFFFFF;border:1px solid var(--clay)}
.btn-primary:hover{background:var(--clay-hi);border-color:var(--clay-hi)}
/* The subordinate member of the same family. Defined here, after .btn, because
   both are single-class selectors and source order is the only thing deciding
   which min-height wins. */
.btn-ghost{background:var(--ground);color:var(--ink);border:1px solid var(--ink);
  min-height:50px;font-size:15px}
.btn-ghost:hover{background:var(--band-2)}
/* ⚠ RENDER 6. 22px until the sub-line came out. With eyebrow, heading and
   button and nothing between, 22px put a 56px slab directly under a two-line
   headline and the two read as one crowded object. 30px is the reclaimed
   space going back into the block instead of into new copy, which is what
   Kyler asked for. The section still loses 43px net against render 5. */
.cta .btn{margin-top:30px;max-width:420px}
.ask .btn{margin-top:17px;max-width:340px}

/* ---------- footer ------------------------------------------------------ */
.foot{background:var(--band);border-top:1px solid var(--line);font-size:13.5px;
  color:var(--ink-2)}
.foot .wrap{padding-block:30px}
.foot h3{font-size:12px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);font-family:var(--body)}
.showrooms{margin-top:15px;display:grid;gap:18px;grid-template-columns:minmax(0,1fr)}
.showroom .n{font-weight:600;color:var(--ink)}
.showroom .a{margin-top:4px}
.foot .hrs{margin-top:20px;padding-top:15px;border-top:1px solid var(--line);font-size:13px}
.foot .hrs p+p{margin-top:2px}
/* ⚠ RENDER 5. .foot .legal is GONE. It read "Jeff is a Homus sales consultant.
   For pricing, stock and delivery, message him directly or ask at either
   showroom." Kyler: "this part is de-selling too and it sounds weird."
   REMOVED rather than reworded. It existed to explain why the page carries no
   prices, and a page that never mentions pricing needs no sentence explaining
   that it doesn't. The rule is omit, never negate. Its one useful half, message
   him directly, is already the page's primary CTA in two places.
   ⚠ This does NOT weaken the no-promises rule. That rule is enforced by the
   absence of any price, delivery, warranty or stock claim, and in the build by
   the save-time scan that blocks one if a salesperson writes it. The disclaimer
   was never the enforcement. Showroom hours and the main line stay. */
/* ⚠ RENDER 3. The render-2 handoff recorded this control as clearing 44px. It
   did not: measured at a true 390 it came back 28.8px, because padding-block:4px
   on a 13px line box gets you 28.8 and nothing else. The number is the second
   most useful thing in the footer on a phone, so it now sits on its own line
   with enough padding to be a real target. Measured after the change, not
   asserted. */
.foot a{color:var(--clay);font-weight:600;text-decoration:none;
  display:inline-block;padding-block:12px}
.foot a:hover{text-decoration:underline}

/* ---------- sticky bar -------------------------------------------------- */
.sticky{position:fixed;left:0;right:0;bottom:0;z-index:40;background:var(--ground);
  border-top:1px solid var(--line);box-shadow:0 -6px 22px rgba(27,22,20,.09);
  padding:10px var(--pad) calc(10px + env(safe-area-inset-bottom,0px))}
.sticky .inner{max-width:var(--maxw);margin-inline:auto;display:flex;gap:10px;
  align-items:stretch}
.sticky .btn{flex:1 1 auto;min-height:52px;font-size:15px;margin-top:0}
.sticky .icon{flex:0 0 52px;width:52px;min-height:52px;display:grid;place-items:center;
  border:1px solid var(--line-2);border-radius:2px;background:var(--ground);
  transition:border-color .18s ease,background .18s ease}
.sticky .icon:hover{border-color:var(--greige);background:var(--band)}
.sticky .icon svg{width:21px;height:21px}

/* ---------- motion ------------------------------------------------------ */
@keyframes rise{from{opacity:.001;transform:translateY(10px)}to{opacity:1;transform:none}}
.stg{animation:rise .38s cubic-bezier(.22,.9,.28,1.06) both}
@media (prefers-reduced-motion: reduce){
  .stg{animation:none}
  *{transition-duration:.01ms !important}
}

/* ---------- ONE breakpoint block. Every responsive override lives here,
   because a media query adds no specificity and one placed above the rule
   it means to override is silently dead at every width. ------------------ */
@media (min-width:680px){
  .hero-body{padding-bottom:32px}
  .cred-i .k{font-size:12px}
  .pq p{max-width:26ch}
  .pq-by{max-width:26ch}
  .sec{padding-block:52px}
  .company .wrap{padding-block:48px}
  .cta .wrap{padding-block:58px}
  .stat .k{font-size:12px}
  .showrooms{grid-template-columns:repeat(2,minmax(0,1fr))}
  .car.is-static .car-track{flex-direction:row;gap:var(--cgap)}
  .car.is-static .card{flex:1 1 0;width:auto}
  .car-nav{display:grid}
  .car-prev{left:10px}
  .car-next{right:10px}
  .ask{display:flex;align-items:flex-end;justify-content:space-between;gap:32px}
  .ask .copy{flex:1 1 auto;min-width:0}
  .ask .btn{margin-top:0;flex:0 0 auto;width:auto;padding-inline:28px}
  .masthead .where{font-size:12px}
}

/* ⚠ RENDER 5. THE STATS ROW GOES FOUR-ACROSS AT 900, NOT AT 680, and the
   measurement is why. Four square tiles at 680 leave 118.5px of usable width
   each while the clamp has pushed the numerals to 33px: "20,000" alone eats
   108.2 of that 118.5, so the whole row was at 91% of its width, not just the
   word-mark square. It was the SME500 fix that surfaced it, but the constraint
   was never about SME500 -- the breakpoint was simply landing before the
   content fit, and every tile was one longer number away from clipping.
   At 900 the tile carries 165.3px, which holds the widest thing in the row
   (the cap-matched word-mark, 156.2px) with 9px to spare. Between 680 and 900
   the row stays 2x2, which is the arrangement measured clean at 390 and the one
   with the most headroom of any state on the page.
   This is the whole reason there is a second breakpoint block. It sits AFTER
   the 680 one, because a media query adds no specificity and the later rule is
   the one that wins. */
@media (min-width:900px){
  .stats{grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}
}

/* ---------- BUILD ADDITION, and the only one. --------------------------
   The signed render has no portrait rule because it has no portrait: photos
   were deferred by Kyler on 07-09-2026 and every avatar in the render is the
   designed gradient well. This rule is dormant until a photo field is filled,
   and it changes nothing while they are empty. It exists so that dropping a
   real image in later needs no build -- which is what the handoff asks for.
   It reproduces the well's own geometry: fill the circle, cover, centred.
   ⚠ The render's "Photo pending" chip is deliberately NOT carried over. It is
   preview furniture: on a live page it announces to a stranger that the page
   is unfinished, which is the self-narration class Kyler swept in render 5.
   The empty circle reads as deliberate on its own. */
.avatar .portrait{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center}
