:root{
  --navy:#11112D; --green:#166232; --blue:#2D317D; --deep:#082111;
  --bg:#0b0b1c; --card:#16162e; --card2:#1d1d3a; --line:#262649;
  --text:#eef0f6; --muted:#9aa0b8; --accent:#2f9e5c;
  --safe: env(safe-area-inset-bottom, 0px);
  /* Installed to the home screen, iOS runs this full-screen under a
     translucent status bar (apple-mobile-web-app-status-bar-style in
     index.html), so the top of the viewport is behind the clock and the
     battery. The bar pads itself by this much: the navy still reaches the
     very top of the screen, but the wordmark starts below the notch.
     Zero in a normal browser tab, where the browser owns that strip. */
  --safe-top: env(safe-area-inset-top, 0px);
  /* Dark is this app's native look, so it lives on bare :root. Light is defined
     twice below — once behind prefers-color-scheme for people who never open
     the setting, once behind [data-theme] for people who do — and each guard
     excludes the other so an explicit choice always beats the operating system.
     Every colour goes through a token: a literal that only reads on one ground
     is how an app ends up with dark text on a dark card. */
  --page:#07070f;
  --avbg:#23234a;
  --quote:#d6dae9;
  --about:#cdd2e2;
  --vid-a:#1c2f24; --vid-b:#131333; --vid-ic:#7fbf9a;
  --frame:#0b0b1c;
  --warn:#7a5a20;
  --star:#e0a72a;
  --onbrand:#fff;
  --navbg:rgba(17,17,45,.97);
  --appshadow:0 0 70px rgba(0,0,0,.7);
  /* Headline stack, kept identical to the Premiere Partner portal so the two
     surfaces read as one brand. "Copperplate" must come FIRST: that is the
     family name on macOS and iOS, where nearly every client opens this. The
     "Copperplate Gothic *" names are the Windows/Adobe ones and match nothing
     on an iPhone — with only those listed, Apple devices fell straight through
     to Optima, which is why the headings looked wrong on the phone. */
  --head: Copperplate, "Copperplate Gothic Bold", "Copperplate Gothic",
          "Big Caslon", "Palatino Linotype", Palatino, Georgia, serif;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{background:var(--page);color:var(--text);line-height:1.5;display:flex;justify-content:center;
  font-family:Calibri,"Segoe UI",system-ui,-apple-system,sans-serif}
h1,h2,h3,h4{font-family:var(--head);
  letter-spacing:.06em;text-transform:uppercase}
a{color:var(--accent)}

.app{width:100%;max-width:460px;min-height:100vh;background:var(--bg);display:flex;flex-direction:column;
  box-shadow:var(--appshadow);position:relative}
@media(min-width:520px){.app{border-left:1px solid var(--line);border-right:1px solid var(--line)}}

.topbar{position:sticky;top:0;z-index:20;background:var(--navy);border-bottom:2px solid var(--green);
  padding:calc(11px + var(--safe-top)) 14px 11px;display:flex;align-items:center;gap:9px;
  min-height:calc(50px + var(--safe-top));color:#fff}
/* The real TFC mark. The artwork is transparent and sits straight on the navy
   bar, so it needs no plate behind it — but that also means the bar IS the
   background. The master's top face is near-black, which on #11112D is a 1.07:1
   contrast and simply vanishes, so the bar uses tfc-icon-light.png, the same art
   with that one face recoloured white. --navy is not themed, so this holds in
   light mode too. The near-black master is still correct anywhere the ground is
   light. */
.cube{width:30px;height:30px;flex:0 0 auto;display:block}
.cube img{width:100%;height:100%;object-fit:contain;display:block}
.wordmark{font-family:var(--head);font-size:11px;letter-spacing:.13em;flex:1;line-height:1.25}
.backbtn{background:none;border:0;color:#5fcf8f;font-size:16px;cursor:pointer;padding:0 4px 0 0;font-family:inherit}
.backbtn[hidden]{display:none}

main{flex:1 1 auto;padding:14px 14px 96px}
/* Auto columns, not a fixed four: a co-branded app carries a fifth tab for the
   partner, and a hard-coded repeat(4) squeezed it off the end of the bar. */
.nav{position:fixed;bottom:0;left:0;right:0;z-index:30;margin:0 auto;max-width:460px;
  background:var(--navbg);backdrop-filter:blur(10px);border-top:1px solid var(--line);
  display:grid;grid-auto-flow:column;grid-auto-columns:1fr;padding:8px 0 calc(10px + var(--safe))}
.nav button{background:none;border:0;color:var(--muted);font-size:10px;cursor:pointer;padding:2px 2px;
  display:flex;flex-direction:column;align-items:center;gap:3px;font-family:inherit;min-width:0}
/* The fifth tab is labelled with a real first name, and names get long. At five
   tabs on a 390px screen each one has about 74px, so the label truncates rather
   than wrapping the bar into two rows. */
.nav button .lb{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav button .ic{font-size:17px;line-height:1}
.nav button.on{color:var(--accent)}

.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px;margin-bottom:11px}
.card.flush{padding:0;overflow:hidden}
.sect{font-size:10px;color:var(--muted);letter-spacing:.15em;text-transform:uppercase;margin:20px 0 9px;
  font-family:var(--head)}
.sect:first-child{margin-top:4px}

.hero{text-align:center;padding:18px 14px 14px}
.av{width:78px;height:78px;border-radius:50%;border:3px solid var(--accent);display:grid;place-items:center;
  margin:0 auto 10px;font-size:22px;background:var(--avbg);color:var(--text);overflow:hidden;
  font-family:var(--head)}
.av img{width:100%;height:100%;object-fit:cover}
.av.sm{width:50px;height:50px;font-size:14px;border-width:2px;margin-bottom:7px}
/* The realtor beside their own listing. Small enough that a third initial
   would be unreadable, which is why the feed sends two. */
.av.xs{width:28px;height:28px;font-size:10.5px;border-width:2px;margin:0;flex:0 0 auto}
.av.blue{border-color:var(--blue)}
.hero h2{font-size:20px;margin-bottom:4px}
.hero .s{font-size:12px;color:var(--muted)}
.stars{color:var(--star);font-size:14px;margin-top:6px;letter-spacing:2px}

/* ---------- the portrait hero (co-branded apps only) ----------------------
   The second shape a partner's card can take: their photo standing down the
   left, their details beside it. Chosen per partner in Admin; the round-photo
   hero above is still the default and still what most partners get.

   The photo STRETCHES to whatever height the card ends up being, rather than
   the card being sized to a 3:4 box. That is deliberate: a long name or a long
   brokerage wraps to a second line, the card grows, and the photo grows with
   it — so the text has room to adjust and the picture never has to be the
   thing that gives. min-height keeps it a portrait when the text is short.

   The crop itself is not this app's business. The 3:4 file is cut in the
   portal, where the person choosing it can see what it does to a face; every
   attempt to make a square photo work in a tall frame from this end is how the
   top of somebody's head ends up outside the card. */
.hero.portrait{display:flex;align-items:stretch;gap:0;padding:0;overflow:hidden;text-align:left}
.hero.portrait .pic{flex:0 0 128px;min-height:172px;position:relative;background:var(--avbg);
  border-right:3px solid var(--brok,var(--blue))}
.hero.portrait .pic img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.hero.portrait .meta{flex:1 1 auto;min-width:0;padding:16px 14px 15px;
  display:flex;flex-direction:column;justify-content:center}
/* A name is the one string here nobody controls the length of, so it wraps
   rather than truncating — a partner cut off mid-surname on their own app is
   worse than a card one line taller. */
.hero.portrait h2{font-size:19px;line-height:1.15;margin-bottom:5px;overflow-wrap:break-word}
.hero.portrait .s{line-height:1.45;overflow-wrap:break-word}
/* 390px is the width this has to hold at: 128 for the photo leaves about 204
   for the text once the padding is off it. */
@media(max-width:359px){
  .hero.portrait .pic{flex-basis:108px;min-height:144px}
  .hero.portrait h2{font-size:17px}
}
.socials{display:flex;justify-content:center;gap:15px;margin-top:12px;font-size:16px;opacity:.85}
.socials a{text-decoration:none;color:inherit;display:flex;align-items:center}
/* Sized in em so the existing font-size cascade still shrinks them: .socials.sm
   drops to 13px and the marks follow without a second rule. */
.socials svg{width:1em;height:1em;display:block}
.cob{display:grid;grid-template-columns:1fr auto 1fr;gap:9px;align-items:start;text-align:center}
.cob .amp{color:var(--muted);font-size:11px;padding-top:20px}
.cob h4{font-size:13.5px;margin-bottom:3px}
.cob .s{font-size:10px;color:var(--muted);line-height:1.35}
.pill{display:inline-block;font-size:9px;letter-spacing:.11em;text-transform:uppercase;color:var(--muted);
  border:1px solid var(--line);background:var(--card2);padding:3px 9px;border-radius:99px}

.btn{background:var(--green);color:var(--onbrand);border:0;border-radius:10px;padding:13px;width:100%;font-size:14px;
  font-weight:600;cursor:pointer;font-family:inherit;display:block;text-align:center;text-decoration:none}
.btn.alt{background:var(--blue)}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--text);font-weight:400}
.btn.sm{padding:10px;font-size:13px}
.two{display:grid;grid-template-columns:1fr 1fr;gap:9px}

.row{display:flex;align-items:center;justify-content:space-between;gap:11px;padding:13px 14px;
  border-bottom:1px solid var(--line);cursor:pointer;text-decoration:none;color:inherit}
.row:last-child{border-bottom:0}
.row:active{background:var(--card2)}
.row .l{display:flex;align-items:center;gap:11px;font-size:14px;min-width:0}
/* The name of the thing is heavier than the line explaining it. A list of eight
   links set entirely in one weight reads as a wall; bolding the title alone is
   what lets the eye pick a row out without enlarging anything. The icon square
   and the sub-line opt back out below — both live inside the same title div. */
.row .l > div:not(.ic){font-weight:600}
.row .ic{width:30px;height:30px;border-radius:8px;background:var(--card2);display:grid;place-items:center;
  font-size:14px;flex:0 0 auto}
.row .sub{font-size:11px;color:var(--muted);line-height:1.3;font-weight:400}
.row .ar{color:var(--muted);font-size:16px;flex:0 0 auto}

/* ---------- the Listings tab ----------------------------------------------
   Every approved listing from every partner, on the PLAIN app only. A
   co-branded app never renders any of this — see navItems() in app.js.

   A card rather than a .row, and the one place in this app that earns one: a
   row gives a price, an address, a details line and an attribution the same
   weight, and the price is the line that decides whether a client taps. The
   green rail down the left is what separates one house from the next at a
   glance when four of them are stacked. */
.lst{display:block;background:var(--card);border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:14px;padding:13px 14px;margin-bottom:11px;text-decoration:none;color:inherit}
.lst:active{background:var(--card2)}
.lst .top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
/* Copperplate and tabular figures: four prices stacked should line up on the
   comma, which proportional digits do not. */
.lst .price{font-family:var(--head);font-size:20px;letter-spacing:.03em;line-height:1;
  font-variant-numeric:tabular-nums}
/* An unpriced listing is a COMPLETE listing, not a broken one — it says where
   the number is instead of leaving a gap. Set small and muted so it reads as a
   sentence rather than as a figure that failed to load. */
.lst .price.none{font-size:12px;color:var(--muted);letter-spacing:.04em;font-family:inherit;
  font-weight:400;padding-top:3px}
.lst .tag{font-size:9px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:#9fd4b4;
  border:1px solid rgba(47,158,92,.5);border-radius:4px;padding:3px 7px;flex:0 0 auto;white-space:nowrap}
.lst .addr{font-size:14px;font-weight:600;margin-top:7px;line-height:1.3}
.lst .facts{font-size:11.5px;color:var(--muted);margin-top:4px;line-height:1.35}
/* The attribution, on the card rather than only in the footnote below: the
   disclosure turns on each property being listed by the realtor named on it,
   so the name belongs beside the house, not four scrolls down. */
.lst .by{display:flex;align-items:center;gap:9px;margin-top:11px;padding-top:11px;
  border-top:1px solid var(--line)}
.lst .who{min-width:0;flex:1}
.lst .who b{display:block;font-size:12px;font-weight:600;line-height:1.25}
.lst .who span{display:block;font-size:10.5px;color:var(--muted);line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Where the tap goes, printed before it is made. The same guarantee the
   partner's own buttons give. */
.lst .go{font-size:10.5px;color:var(--muted);flex:0 0 auto;white-space:nowrap}
.lcount{font-size:11px;color:var(--muted);margin:-3px 0 11px}
.lempty{text-align:center;padding:22px 8px;color:var(--muted);font-size:13px;line-height:1.55}
/* The CTA heading inside the apply card. The card itself is the existing
   object; only its heading is new here.

   ⚠️ The colour is EXPLICIT and not themed, because the card is not themed: its
   gradient is built from --deep and --navy, which stay dark in light mode. An
   inherited --text would be near-black on near-black there and the heading
   would simply vanish — which is exactly what it did on the first pass. Its
   siblings are pinned for the same reason, one rule down and one at line 440. */
.applycard .ctah{font-family:var(--head);font-size:14px;letter-spacing:.04em;
  margin-bottom:6px;color:#fff}

.applycard{background:linear-gradient(140deg,var(--deep),var(--navy));border:1px solid var(--green)}
.applycard .lbl{font-size:11px;color:#9fd4b4;letter-spacing:.1em;text-transform:uppercase;margin-bottom:9px}

.vid{height:88px;border-radius:10px;background:linear-gradient(140deg,var(--vid-a),var(--vid-b));
  display:grid;place-items:center;font-size:22px;margin-bottom:8px;color:var(--vid-ic)}
.tile{background:var(--card);border:1px solid var(--line);border-radius:13px;padding:11px;cursor:pointer;
  text-decoration:none;color:inherit;display:block}
.tile .t{font-size:12px;line-height:1.3;font-weight:600}
.tile .ic{font-size:20px;display:block;margin-bottom:6px}

.quote{font-size:13px;font-style:italic;color:var(--quote)}
.by{font-size:11px;color:var(--muted);margin-top:6px}

.calcwrap{margin:-14px -14px 0}
.calchead{padding:13px 14px 11px;border-bottom:1px solid var(--line)}
.calchead h2{font-size:14px;margin-bottom:2px}
.calchead p{font-size:11px;color:var(--muted)}
iframe.broki{width:100%;border:0;display:block;background:var(--frame);height:640px;transition:height .18s ease}
.loading{padding:40px 14px;text-align:center;color:var(--muted);font-size:13px}
.disc{font-size:10px;color:var(--muted);line-height:1.5;padding:12px 14px 0}
.warncard{border-color:var(--warn)}

footer{font-size:10px;color:var(--muted);line-height:1.6;text-align:center;padding:22px 6px 4px}
.note{font-size:11px;color:var(--muted);line-height:1.5}
code{background:var(--card2);padding:1px 5px;border-radius:4px;font-size:11px}

/* Install lives in the page — not in a floating bar that covered content and
   could be dismissed forever. It is one of the few things we actually want
   every client to do, so it should still be there tomorrow.

   The strip sits at the top of main, so it has to cancel main's 14px padding to
   reach both edges and sit flush under the bar. Same trick as .calcwrap. It is
   deliberately not sticky: it scrolls away with the page. */
.installstrip{display:flex;align-items:center;gap:8px;padding:9px 10px 9px 12px;
  margin:-14px -14px 14px;background:var(--card2);border-bottom:1px solid var(--line)}
.installstrip .ico{width:20px;height:20px;flex:0 0 auto;color:var(--accent)}
/* One line at 390px is the whole design — a strip that wraps is 52px, not 41,
   and stops reading as a strip. The type is sized to the longest string it
   carries; anything longer than "Add this app to your home screen" needs this
   re-measured, not just dropped in. */
.installstrip .txt{flex:1;min-width:0;font-size:12px;line-height:1.25;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.installstrip .chip{flex:0 0 auto;background:var(--accent);color:var(--onbrand);border:0;
  border-radius:8px;font-size:11.5px;font-weight:600;padding:5px 10px;font-family:inherit;cursor:pointer}
.installstrip .chip.ghost{background:transparent;color:var(--accent);border:1px solid var(--accent)}
.installstrip .x{flex:0 0 auto;width:22px;height:22px;border:0;background:transparent;
  color:var(--muted);font-size:15px;line-height:1;font-family:inherit;cursor:pointer}

/* Folded. 52px closed against the 232px this used to take, because once the app
   is on a home screen none of this should be part of the app any more — and
   until then it should not be the loudest thing on the page either. */
.installcard{background:var(--card);border:1px solid var(--accent);border-radius:12px;
  margin-bottom:11px;overflow:hidden}
.installcard .hd{display:flex;align-items:center;gap:11px;padding:11px 13px;width:100%;
  background:transparent;border:0;text-align:left;font-family:inherit;color:inherit;cursor:pointer}
.installcard .hd:active{background:var(--card2)}
.installcard .ico{width:26px;height:26px;flex:0 0 auto;color:var(--accent)}
.installcard .t{flex:1;min-width:0;font-size:13px;font-weight:600;line-height:1.3}
.installcard .t span{display:block;font-size:11px;font-weight:400;color:var(--muted);margin-top:1px}
.installcard .ar{color:var(--muted);font-size:15px;flex:0 0 auto;transition:transform .18s ease}
.installcard.open .ar{transform:rotate(90deg)}
.installcard .steps{border-top:1px solid var(--line);padding:11px 13px}
.installcard .why{border-top:1px solid var(--line);padding:8px 13px}

/* The same steps unfolding inside the More list, where the container is a flush
   card and the row above has already drawn the dividing line. */
.rowsteps{background:var(--card2);border-bottom:1px solid var(--line)}
.rowsteps:last-child{border-bottom:0}
.rowsteps .steps{padding:12px 14px}
.rowsteps .why{padding:0 14px 12px}
/* Drawn, not an emoji — so it takes the row icon's colour instead of a
   platform's idea of what a phone looks like. */
.row .ic .ico{width:16px;height:16px;color:var(--accent);display:block}

@media (prefers-reduced-motion: reduce){
  .installcard .ar{transition:none}
}
/* ---------- the install sheet ----------------------------------------------
   The one install surface that arrives on its own, so it is the one that has to
   earn the interruption. Everything else here — the strip, the card, the row —
   waits to be found.

   Fixed to the bottom rather than centred, and capped to the app's own column
   on a wide screen so it never floats loose in the middle of a desktop window.
   A bottom sheet is also the shape a phone has taught people to dismiss: the
   thumb is already there. */
.sheetscrim{position:fixed;inset:0;z-index:40;background:rgba(4,4,12,.62);
  opacity:0;transition:opacity .26s ease}
.sheetwrap{position:fixed;left:0;right:0;bottom:0;z-index:41;margin:0 auto;max-width:460px;
  background:var(--card);border-top:1px solid var(--line);border-radius:18px 18px 0 0;
  padding:9px 16px calc(18px + var(--safe));
  box-shadow:0 -20px 50px rgba(0,0,0,.45);
  transform:translateY(101%);transition:transform .3s cubic-bezier(.32,.72,0,1)}
/* The class goes on one frame after the nodes are in the document, so the
   browser has a start position to animate FROM. Set at insert time it is not a
   transition at all — the sheet simply appears, which reads as a bug. */
.sheetscrim.up{opacity:1}
.sheetwrap.up{transform:translateY(0)}

/* Not decoration: it says "this drags/dismisses" before any word is read. */
.sheetwrap .grab{width:38px;height:4px;border-radius:2px;background:var(--line);
  margin:0 auto 12px}
.sheetwrap .hd{display:flex;align-items:center;gap:13px;margin-bottom:12px}
/* The real home-screen icon, taken from the apple-touch-icon link so a partner's
   app shows THEIR icon here — the initial on their brokerage colour — and the
   plain app shows the TFC mark. One definition of which icon this app has, in
   the head, exactly as index.html insists. */
.sheetwrap .appicon{width:58px;height:58px;flex:0 0 auto;border-radius:14px;display:block;
  box-shadow:0 4px 14px rgba(0,0,0,.4)}
.sheetwrap h2{font-size:14px;line-height:1.25}
.sheetwrap .sub{font-size:12px;color:var(--muted);margin-top:4px;
  font-family:Calibri,"Segoe UI",system-ui,-apple-system,sans-serif;
  letter-spacing:0;text-transform:none}
.sheetwrap .go{display:block;width:100%;background:var(--accent);color:var(--onbrand);
  border:0;border-radius:10px;padding:13px;font-size:14px;font-weight:600;
  font-family:inherit;cursor:pointer}
.sheetwrap .go:active{filter:brightness(.93)}
/* ⚠️ The button stays TFC green on a co-branded app. The brokerage's colours
   reach the top bar and nothing else — an Install button in a realtor's red on
   a mortgage app starts to read as the realtor offering the mortgage, which is
   the line FSRA/MBLAA does not allow to blur. Their icon is right beside it and
   carries the co-branding on its own. */
.sheetwrap .later{display:block;width:100%;background:transparent;border:0;color:var(--muted);
  font-size:12.5px;font-family:inherit;padding:11px 0 3px;cursor:pointer}
.sheetwrap .why{border-top:1px solid var(--line);padding-top:10px}

@media (prefers-reduced-motion: reduce){
  .sheetscrim,.sheetwrap{transition:none}
}

/* Numbered steps, left-aligned inside a centred card: a three-step
   instruction read centred is genuinely harder to follow, because the eye
   loses the left edge between steps. */
.steps{text-align:left;margin:0;padding:0;list-style:none;counter-reset:step}
.steps li{position:relative;padding:0 0 0 24px;margin-bottom:7px;font-size:11.5px;line-height:1.45;
  color:var(--quote);counter-increment:step}
.steps li:last-child{margin-bottom:0}
.steps li::before{content:counter(step);position:absolute;left:0;top:1px;width:17px;height:17px;
  border-radius:50%;background:var(--accent);color:var(--onbrand);font-size:9.5px;font-weight:700;
  display:grid;place-items:center;line-height:1}
.steps .k{color:var(--text);font-weight:600}
.why{font-size:10.5px;color:var(--muted);line-height:1.5}

/* A review is a quote with a name, a date and a star line. Whole reviews, in
   full — a review trimmed to its best sentence is not the client's review
   any more, and Google shows the same words to anyone who looks. */
.rev{padding:14px;border-bottom:1px solid var(--line)}
.rev:last-child{border-bottom:0}
.rev .h{display:flex;align-items:baseline;justify-content:space-between;gap:9px;margin-bottom:5px}
.rev .who{font-size:13px;font-weight:600}
.rev .when{font-size:10.5px;color:var(--muted);flex:0 0 auto}
.rev .stars{margin:0 0 7px;font-size:12px}
.rev .quote{font-style:normal;font-size:13px;color:var(--quote);white-space:pre-wrap}
/* Google requires its reviews be shown as Google reviews. One line under the
   list says where they came from and links to the profile they live on. */
.revsrc{font-size:10.5px;color:var(--muted);text-align:center;padding:12px 6px 0;line-height:1.5}

/* A Learn row may carry a real logo instead of an emoji — the podcast is its own
   brand, not a category. Fills the same 30px square the emoji sits in. */
.row .ic.img{padding:0;overflow:hidden;background:#000}
.row .ic.img img{width:100%;height:100%;object-fit:cover;display:block}

/* ---- light theme ---------------------------------------------------------
   Not an inversion: the topbar keeps its navy and green so the brand does not
   change with a display setting, and the accent darkens so it reads against
   white instead of glowing on it.

   Defined twice on purpose. The media query serves everyone who never opens the
   setting; the [data-theme] rule serves everyone who does. Each guard excludes
   the other case so an explicit choice always beats the operating system. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
  --bg:#f4f6fb; --card:#ffffff; --card2:#eef1f8; --line:#dde1ee;
  --text:#14162b; --muted:#5c6280; --accent:#166232;
  --page:#e7eaf3;
  --avbg:#e4e8f4;
  --quote:#2a2e46;
  --about:#3a3f57;
  --vid-a:#e8f0ea; --vid-b:#e6e8f4; --vid-ic:#2f7a52;
  --frame:#ffffff;
  --warn:#b98a2c;
  --star:#c98a12;
  --navbg:rgba(255,255,255,.97);
  --amberbg:#fdf3e3;--ambertx:#7a5010;--amberln:#f0e0c0;
  --appshadow:0 0 60px rgba(20,25,60,.14);
  }
}
:root[data-theme="light"] {
  --bg:#f4f6fb; --card:#ffffff; --card2:#eef1f8; --line:#dde1ee;
  --text:#14162b; --muted:#5c6280; --accent:#166232;
  --page:#e7eaf3;
  --avbg:#e4e8f4;
  --quote:#2a2e46;
  --about:#3a3f57;
  --vid-a:#e8f0ea; --vid-b:#e6e8f4; --vid-ic:#2f7a52;
  --frame:#ffffff;
  --warn:#b98a2c;
  --star:#c98a12;
  --navbg:rgba(255,255,255,.97);
  --amberbg:#fdf3e3;--ambertx:#7a5010;--amberln:#f0e0c0;
  --appshadow:0 0 60px rgba(20,25,60,.14);
}

/* The About paragraph was an inline colour that only worked on a dark ground. */
.about{font-size:13px;color:var(--about)}

/* Co-brand socials sit under each person, so they are smaller and tighter than
   the solo hero's row — and each half gets the same set, which is the point. */
.socials.sm{gap:11px;margin-top:7px;font-size:13px}

/* Appearance control. A segmented three-way rather than a switch, because
   "System" is a real third choice and a two-state toggle cannot express it. */
.themecard{background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:14px;margin-bottom:11px}
.themecard .t{font-size:13px;font-weight:600;margin-bottom:3px}
.seg{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:11px;
  background:var(--card2);border:1px solid var(--line);border-radius:11px;padding:4px}
.seg button{background:none;border:0;border-radius:8px;padding:9px 4px;cursor:pointer;
  color:var(--muted);font-family:inherit;font-size:12.5px;display:flex;align-items:center;
  justify-content:center;gap:6px}
.seg button.on{background:var(--card);color:var(--text);font-weight:600;
  box-shadow:0 1px 3px rgba(0,0,0,.18)}
.seg button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* The apply card keeps its dark gradient in both themes — it is the one
   deliberately heavy block on the page, and it should not become a pale panel
   in light mode. Everything inside it therefore takes fixed light colours: page
   tokens would flip out from under it and put dark text on a near-black ground,
   which is exactly what happened the first time light mode was rendered. */
.applycard .note{color:#b9c2d6}

/* ---------- the partner's own content ------------------------------------
   A launcher on Home for whatever the partner has posted. Rows only exist for
   kinds that have something behind them: a row that opens an empty list has
   already cost the client a tap.

   These are plain `.row`s in a flush card, so they need no layout of their own
   — they are deliberately the same object as "Where You Stand" below them and
   the partner's own tab behind them. Only the count needs a rule, and only
   because `.row` had nothing like it. (The half-width `.lnchr` tiles this
   replaced were 86px tall and left a gap beside a partner's only listing.) */
.row .n{font-size:10px;font-weight:700;color:var(--accent);background:var(--card2);
  border:1px solid var(--line);border-radius:20px;padding:2px 8px;min-width:22px;
  text-align:center;flex:0 0 auto;margin-left:auto}

.partnercard{display:flex;align-items:center;gap:14px;text-align:left}
.partnercard .av{margin:0;flex:0 0 auto}
.partnercard .pw{min-width:0}
.partnercard .nm{font-family:var(--head);font-size:16px;letter-spacing:.02em;line-height:1.2}
.partnercard .fm{font-size:12px;color:var(--muted);margin-top:3px}
.partnercard .ti{font-size:11px;color:var(--muted);opacity:.8}
.socials.mt{justify-content:flex-start;margin-top:13px}
.socials.left{justify-content:flex-start;margin-top:13px}
.note.tiny{font-size:10.5px;text-align:center;margin:14px 4px 0;opacity:.85}

/* ---------- their brokerage's chrome (co-branded apps only) ----------------
   The bar hands the top of the screen to the partner. Its colours come from the
   feed and are set inline in paintChrome(), so nothing here hard-codes one
   brokerage's palette.

   The accent reaches exactly two more things — the active tab and the partner's
   photo ring — and stops. Buttons stay TFC green, the Apply CTA especially: a
   realtor is not licensed for mortgages, and mortgage buttons wearing the
   brokerage's colours start to read as though they were. */
.topbar[data-brok]{border-bottom-width:3px}
/* Their mark sits on a white plate. Brokerage artwork is drawn for light
   grounds — RE/MAX's own SVG carries #000e35, the same navy as their bar, so
   half of it would disappear into the background. */
.topbar[data-brok] .cube{background:none;border:0;padding:0;width:auto;height:auto}
.plate{background:#fff;border-radius:6px;padding:4px 6px;display:flex;align-items:center;
  flex:0 0 auto}
.plate img{height:15px;display:block}
.topbar[data-brok] .wordmark{line-height:1.2}
.wordmark .bnm{display:block;font-family:var(--head);font-size:11px;letter-spacing:.09em}
.wordmark small{display:block;font-size:8.5px;letter-spacing:.05em;opacity:.72;
  font-family:var(--head);margin-top:2px}
.nav button.on{color:var(--brok,var(--accent))}
.partnercard .av,.cob .av.blue,.hero .av.blue{border-color:var(--brok,var(--blue))}

/* Stephen, on a screen whose bar is no longer his. A labelled block rather than
   a line of fine print: with no TFC bar this is the identification the rules
   actually turn on. */
.attrib{border-left:3px solid var(--green)}
.attrib .lb{font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
  margin-bottom:8px}
.attrib .who{display:flex;align-items:center;gap:11px}
.attrib .tfcmini{width:30px;height:30px;object-fit:contain;flex:0 0 auto;border-radius:7px}
.attrib .nm{font-family:var(--head);font-size:12.5px;letter-spacing:.03em}
.attrib .ro{font-size:11.5px;color:var(--muted);margin-top:2px}
.attrib .lic{font-size:10.5px;color:var(--muted);opacity:.85;margin-top:3px;line-height:1.4}

/* The tester, saying so. Amber rather than red: this is a note about what you
   are looking at, not a fault. Mirrors the strip the partner page already
   carries so the two surfaces admit it the same way. */
/* ---------- setup mode: the partner's own view of the gaps -----------------
   Amber throughout, and dotted throughout, so "waiting on you" reads as one
   thing wherever it appears — the bar, the avatar, the social row. It must not
   look broken and it must not look finished. Only the partner ever sees any of
   it; a client opening the same address gets the app with none of this on it. */
.setupstrip{display:flex;gap:10px;align-items:flex-start;
  background:var(--amberbg,#3a2f10);color:var(--ambertx,#f0d9a0);
  border:1px solid var(--amberln,#5c4a1c);border-radius:10px;padding:10px 12px;
  font-size:12px;line-height:1.4;margin-bottom:12px;text-align:left}
.setupstrip .n{flex:0 0 auto;width:20px;height:20px;border-radius:50%;
  background:var(--ambertx,#f0d9a0);color:var(--amberbg,#3a2f10);
  display:grid;place-items:center;font-weight:800;font-size:11px}
.setupstrip .priv{display:inline-block;margin-top:4px;opacity:.8;font-size:11px}
/* The tag itself: a plus, a label, and a tap that opens an email. */
.gaptag{display:inline-flex;align-items:center;gap:5px;font-size:10.5px;font-weight:800;
  letter-spacing:.05em;text-transform:uppercase;text-decoration:none;
  color:#8a6d1f;background:#fdf4dd;border:1px solid #ecd9a4;border-radius:999px;
  padding:3px 10px;white-space:nowrap}
.gaptag::before{content:"+";font-size:12px;line-height:1;font-weight:800}
/* On the dark bar the amber pill would shout. Outline only. */
.gaptag.onbar{background:transparent;border:1px dashed rgba(255,255,255,.45);
  color:rgba(255,255,255,.75);font-size:9.5px;padding:2px 8px;margin-top:2px}
/* A dotted plate where the brokerage mark will go. */
.plate.gap{background:rgba(255,255,255,.06);border:1.5px dashed rgba(255,255,255,.45);
  color:rgba(255,255,255,.75);font-size:8.5px;font-weight:800;line-height:1.15;
  letter-spacing:.04em;text-align:center;padding:5px 6px}
/* The avatar, waiting on a photo: their initials in a dotted ring. */
.avwrap{display:flex;flex-direction:column;align-items:center;gap:8px}
.av.gap{border-style:dashed !important;border-color:#b9c2cc !important;
  background:#f4f6f8;color:#9aa3ac}
/* An empty social slot, in the position the real one will take. */
.socials a.gapicon{border:1.5px dashed #b9c2cc;border-radius:50%;color:#aeb6bf;
  width:38px;height:38px;display:inline-flex;align-items:center;justify-content:center}
.gapline{font-size:11px;color:#8a6d1f;text-align:center;margin-top:8px}
/* No brokerage means no brokerage colours to borrow: TFC navy, dashed rule. */
#topbar[data-setup]{border-bottom-style:dashed;border-bottom-color:#3a4a6b}

.demostrip{background:var(--amberbg,#3a2f10);color:var(--ambertx,#f0d9a0);
  border:1px solid var(--amberln,#5c4a1c);border-radius:10px;padding:8px 11px;
  font-size:10.5px;letter-spacing:.05em;text-align:center;margin-bottom:12px}

/* The two home tools above the calculators. A green edge is the only thing
   separating them from the calculator card below — they are the app's own, not
   a partner's, and the border says so without a second heading style. */
.hometools{border-color:var(--green)}

/* ---------- the contact card ----------------------------------------------
   The QR is the one element on this app that ignores the theme. A code drawn
   light-on-dark is a code that a good half of the camera apps in the world
   will not read, so it keeps its white plate in dark mode and the plate keeps
   a quiet margin of its own — the four-module quiet zone is inside the SVG,
   and this padding is what stops a dark card crowding it on screen. */
.qrcard{padding:16px 14px 14px;text-align:center}
.qrplate{background:#fff;border-radius:12px;padding:10px;display:block;
  max-width:320px;margin:0 auto}
.qrplate svg{width:100%;height:auto;display:block}
.qrwho{margin-top:13px;line-height:1.35}
.qrwho strong{display:block;font-size:14px;font-weight:600}
.qrwho span{display:block;font-size:11.5px;color:var(--muted);margin-top:2px}
.qrhint{margin-top:10px;text-align:center}

/* What the card contains, spelled out rather than promised. Two columns on a
   390px screen leaves the values room to wrap, which several of them need —
   an email address and a LinkedIn URL are both longer than half a phone. */
.contactlist .crow{display:grid;grid-template-columns:82px 1fr;gap:11px;
  padding:11px 14px;border-bottom:1px solid var(--line);align-items:baseline}
.contactlist .crow:last-child{border-bottom:0}
.contactlist .k{font-size:10px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);line-height:1.4}
.contactlist .v{font-size:12.5px;line-height:1.45;word-break:break-word;overflow-wrap:anywhere}

/* ---------- legal & privacy ------------------------------------------------
   The long-read screen. Everything else in this app is scannable rows and
   figures; this is the one place somebody actually reads sentences, so the
   measure is narrower, the line height is looser, and the headings are small
   enough not to shout at a person who came here worried. */
.card.legal{padding:16px 15px}
.card.legal h3{font-size:12.5px;font-weight:700;margin:18px 0 7px;color:var(--text);
  letter-spacing:.01em}
.card.legal h3:first-child{margin-top:0}
.card.legal p{font-size:13px;line-height:1.62;color:var(--muted);margin:0 0 9px;max-width:60ch}
.card.legal p:last-child{margin-bottom:0}
.card.legal b{color:var(--text);font-weight:650}
.card.legal a{color:var(--accent)}

/* The footer's own link. A button rather than an anchor so it does not leave a
   stray #legal on every address a client might share, and restyled back to
   looking like the text around it. */
.legallink{background:none;border:0;padding:0;margin:4px 0 0;font:inherit;
  color:var(--muted);text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.legallink:hover{color:var(--text)}
