/* bNear landing — design_handoff_bnear/"bNear Landing v3".
   The prototype carried its styling inline; here it is a stylesheet reading
   from tokens.css, so the landing, the admin console and the dev console all
   move together when a token changes. */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* Belt and braces. The causes above are fixed, but a single overflowing
   element makes the whole page pan sideways on a phone, and that reads as
   broken — so it is stopped here as well. */
html { -webkit-text-size-adjust: 100%; overflow-x: hidden; }
/* An author `display` beats the UA stylesheet's `[hidden] { display: none }`,
   and the button rules here set `display: inline-flex` — so a button with the
   hidden attribute rendered anyway. That was showing "Activar notificações"
   on iOS Safari, where the code explicitly hides it. */
[hidden] { display: none !important; }
body { overflow-x: hidden; }

body {
  font-family: var(--bn-font);
  font-weight: 300;
  color: var(--bn-ink);
  background: var(--bn-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: var(--color-accent-700); text-decoration: none; }
a:hover { color: var(--color-accent); }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; border-radius: var(--r-pill); }

.shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
/* The same page box as the two consoles: 1240px with a 34px inset, declared
   the same way. The landing used to be 1440/44 from the design canvas, which
   made the site and the console it links to two different shapes — most
   visible on a tablet, where the landing ran wide while the console did not.
   Sergio's call, 2026-09-01.
   Kept as tokens rather than literals so the three surfaces can only diverge
   deliberately. */
:root { --page: 1240px; --inset: var(--s-7); }
.wrap {
  max-width: var(--page);
  margin: 0 auto;
  width: 100%;
  padding-left: var(--inset);
  padding-right: var(--inset);
}

@keyframes bnRise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes bnFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }
/* The chip's dot breathes rather than bounces — a pulse reads as a heartbeat,
   which is the thing the product is about, and it does not drag the eye the
   way vertical movement beside text does. */
@keyframes bnPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } }
@keyframes bnSweep { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ── Nav ────────────────────────────────────────────────────── */
/* The bar is full-bleed so its rule reaches the window edges; the row inside
   carries the page box and the inset, so the brand sits on the same left edge
   as every card below it. Exactly the shape both consoles' topbar uses, and
   the reason is the same: constrain the bar itself and the two boxes drift an
   inset apart past the max-width.
   While the entrance gate is shut this whole bar is lifted to z-index 7 over
   the curtain (see the rule near the curtain below), so the line is there on
   the front door too. */
.navbar { border-bottom: 1px solid var(--line); }

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-7);
  padding-top: var(--s-5);
  padding-bottom: var(--s-5);
}
/* min-width:0 on both sides: a flex item defaults to min-width:auto and
   refuses to shrink below its content, which is how a nav overflows its
   own container. */
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; color: var(--bn-ink); }
.brand:hover { color: var(--bn-ink); }
.brand img { width: 30px; height: 30px; display: block; }
/* Wordmark rule: b in 400, Near in 700, .me in 400, Nunito. Only Near is bold. */
.wordmark { font-family: var(--bn-wordmark); font-size: 20px; font-weight: 400; line-height: 1; }
.wordmark b { font-weight: 700; }

/* Trial (2026-09-06, Sergio): b-Near.me. The hyphen is full size — the same
   as the `b` it follows — so it needs none of the compensations a shrunken
   one did: at 1em the font's own hyphen metrics already place it correctly,
   and a margin would only open a gap the kerning did not ask for. Weight 400
   as well, matching the `b` rather than Near's 700, or the dash reads as
   belonging to the bold half.

   Still its own span, and still one class per stylesheet, so the trial can be
   pulled back out by deleting the rule and the spans — and so the dash can
   stay aria-hidden, which is what makes a screen reader say the name instead
   of spelling it. */
.wm-dash { font-weight: 400; }


.nav-right { display: flex; align-items: center; gap: 10px; min-width: 0; }

.bmc { display: inline-flex; align-items: center; height: 22px; transition: transform .2s ease, opacity .2s ease; }
.bmc:hover { transform: translateY(-2px); opacity: .85; }
/* Both dimensions are stated. Left to `width: auto`, an SVG whose file has no
   width/height attributes takes the default replaced size — Safari does not
   derive it from the viewBox, and renders the cup ~300px wide, which pushes
   the caregiver pill off the right edge and lets the page scroll sideways. */
.bmc img { display: block; }
.bmc-cup { width: 22px; height: 22px; }
.bmc-wordmark { width: 78px; height: 20px; margin-left: 5px; }
/* Buy Me a Coffee's own yellow and ink — their brand, not bNear tokens. */
.bmc-heart {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 8px;
  padding: 3px 9px 3px 7px;
  border-radius: var(--r-pill);
  background: #FFDD00;
  color: #0D0C22;
  font-size: var(--fs-cap);
  font-weight: 700;
  line-height: 1;
}
.bmc-heart svg { width: 12px; height: 12px; display: block; }
/* The heart stands alone until there is a number to put beside it — see the
   note on BMC_SUPPORTERS in landing.js. */
#bmcCount:empty { display: none; }
.bmc-heart:has(#bmcCount:empty) { padding: 3px 7px; }

/* One presentation at every width: a pill trigger showing the current
   language, with the options in a card beneath it. It was a segmented
   control above 700px and a dropdown below, which meant two shapes to keep
   in step and a wide nav paying about 120px for three segments where one
   pill says the same thing. The breakpoint no longer forks this, so
   landing.js no longer watches it. */
.lang-picker { position: relative; display: flex; align-items: center; }
.lang-trigger {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 7px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--bn-line);
  background: var(--bn-card);
  color: var(--color-accent-700);
  font-family: inherit;
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0.04em;
  line-height: 1;
  cursor: pointer;
  transition: border-color .2s ease;
}
.lang-trigger:hover,
.lang-picker[data-open="true"] .lang-trigger { border-color: var(--color-accent-300); }
.lang-caret { width: 10px; height: 10px; transition: transform .2s ease; }
.lang-picker[data-open="true"] .lang-caret { transform: rotate(180deg); }

.lang-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  display: none;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  padding: 4px;
  min-width: 88px;
  /* A stacked list wants the card radius, not the pill one — only the rows
     inside it stay pills. */
  border-radius: var(--r-tile);
  border: 1px solid var(--bn-line);
  background: var(--bn-card);
  box-shadow: var(--shadow-card);
}
.lang-picker[data-open="true"] .lang-menu { display: flex; }
.lang-menu button {
  text-align: left;
  padding: 9px 14px;
  /* A row is a touch target, not a label. */
  min-height: 38px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--bn-muted);
  font-family: inherit;
  font-size: var(--fs-cap);
  font-weight: 500;
  letter-spacing: 0.04em;
  white-space: nowrap;
  cursor: pointer;
  transition: background .2s ease, color .2s ease;
}
.lang-menu button[aria-pressed="true"] { background: var(--color-accent); color: #fff; }

/* The page's one call to action, and it wears the thing at the centre of the
   mark. Coral is the only red here: the landing has nothing destructive to
   confuse it with, unlike the consoles where coral means danger. */
.pill-cta {
  display: inline-flex;
  align-items: center;
  padding: 14px 28px;
  border-radius: var(--r-pill);
  /* Transparent rather than none: the outlined pill beside it in the join
     sheet has a real 1px border, and without this the two sit 2px apart. */
  border: 1px solid transparent;
  background: var(--bn-coral);
  color: #fff;
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow-heart);
  transition: transform .2s ease, background .2s ease, box-shadow .2s ease;
}
.pill-cta:hover {
  background: var(--bn-danger-btn-hi);
  transform: translateY(-2px);
  box-shadow: var(--shadow-heart-hi);
  color: #fff;
}
/* A light travelling round the call to action. The wrapper is a coral ring
   2px wider than the pill; a big conic gradient spins behind it and the pill's
   own coral covers everything but that edge, so what shows is a bright arc
   running around the border. `overflow: hidden` keeps the 320px square inside
   the pill's radius; `isolation: isolate` keeps the pill's z-index local.
   The shadow and the hover lift belong to the wrapper — on the pill they
   would sit inside the ring and move the pill out of it. */
.pill-sheen {
  position: relative;
  display: inline-flex;
  padding: 2px;
  border-radius: var(--r-pill);
  background: var(--bn-coral);
  overflow: hidden;
  isolation: isolate;
  box-shadow: var(--shadow-heart);
  transition: transform .2s ease, box-shadow .2s ease;
}
.pill-sheen::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 320px;
  height: 320px;
  margin: -160px 0 0 -160px;
  background: conic-gradient(from 0deg,
    rgba(255, 255, 255, 0) 0deg,
    rgba(255, 255, 255, 0) 296deg,
    rgba(255, 255, 255, 0.95) 344deg,
    rgba(255, 255, 255, 0) 360deg);
  animation: bnSweep 2.6s linear infinite;
  pointer-events: none;
}
.pill-sheen:hover { transform: translateY(-2px); box-shadow: var(--shadow-heart-hi); }
.pill-sheen .pill-cta { position: relative; z-index: 1; box-shadow: none; }
.pill-sheen .pill-cta:hover { transform: none; box-shadow: none; }
/* Stopped rather than slowed: the global reduced-motion rule cuts every
   animation to .001ms, which would leave the bright arc frozen somewhere on
   the ring instead of removing it. */
@media (prefers-reduced-motion: reduce) {
  .pill-sheen::before { display: none; }
}

/* The second choice beside it: an outline, so there is visibly one primary. */
.pill-quiet {
  display: inline-flex;
  align-items: center;
  padding: 10px 18px;
  border-radius: var(--r-pill);
  border: 1px solid var(--bn-line);
  background: var(--bn-card);
  color: var(--bn-ink);
  font-family: inherit;
  font-size: var(--fs-body-sm);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .2s ease, color .2s ease;
}
.pill-quiet:hover { border-color: var(--color-accent); color: var(--color-accent); }
.pill-quiet-lg { padding: 14px 26px; font-size: var(--fs-body); }

/* ── Hero ───────────────────────────────────────────────────── */
.hero {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(48px, 6vw, 110px);
  padding-top: var(--s-2);
  padding-bottom: 40px;
}
.hero-copy { max-width: 660px; justify-self: start; animation: bnRise .8s var(--ease-lift) both; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 14px 7px 9px;
  border-radius: var(--r-pill);
  background: var(--color-accent-100);
  color: var(--color-accent-800);
  font-size: var(--fs-meta);
  margin-bottom: 26px;
}
.chip .dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--color-accent);
  display: block;
  animation: bnPulse 2.4s ease-in-out infinite;
}

.hero h1 {
  font-size: clamp(40px, 5.4vw, 78px);
  font-weight: 200;
  line-height: 1.02;
  letter-spacing: -0.032em;
  margin-bottom: 22px;
  text-wrap: balance;
  /* Last resort. "verdadeiramente" is 15 characters with nowhere to break;
     better a broken word than a page that scrolls sideways. */
  overflow-wrap: break-word;
}
.hero h1 em { font-style: normal; font-weight: 500; color: var(--color-accent); }

.lede {
  font-size: var(--fs-lede);
  line-height: 1.62;
  color: var(--bn-muted);
  max-width: 47ch;
  margin-bottom: 34px;
  text-wrap: pretty;
  /* The break after the first sentence is deliberate: the group chat, then
     what b-Near.me does instead. Same mechanism as [data-t="card1"] — the
     newline sits in the copy, so it stays one translatable unit and each
     language puts it where its own sentence ends, rather than being two keys
     glued together. pre-line honours it and still collapses the rest, which
     matters because ledeB opens with a space. */
  white-space: pre-line;
}
.lede .wordmark { font-size: inherit; color: var(--bn-ink); }

/* ── Orb ────────────────────────────────────────────────────── */
.orb-slot { position: relative; height: min(76vh, 640px); min-height: 460px; }
.orb-glow {
  position: absolute;
  inset: 6% 8%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 45%, rgba(15, 158, 140, 0.10), rgba(15, 158, 140, 0) 68%);
  pointer-events: none;
}
/* The stage carries the glow once the 3D mark is running, so the hero's own
   copy would sit underneath it and read twice as dense. */
.orb-slot[data-live="true"] > .orb-glow { display: none; }
/* Shown until the 3D mark takes over, and left in place for good if three.js
   never arrives — the hero must never be half empty. */
.orb-still {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}
.orb-still img { width: min(62%, 340px); height: auto; animation: bnFloat 6s ease-in-out infinite; }
.orb-slot[data-live="true"] .orb-still { display: none; }
/* touch-action:none hands the browser's scroll gesture to us, so a finger
   dragged across the mark turns it instead of moving the page. Scoped to the
   custom element, not .orb-slot: if three.js never arrives the element is
   never created, and the still mark keeps scrolling normally. */
bnear-orb { position: absolute; inset: 0; display: block; touch-action: none; }

/* ── The entrance ───────────────────────────────────────────────
   The page opens behind a curtain with the mark filling the window and
   "Be a Caregiver" printed on the heart; pressing the heart fades the
   curtain and flies the mark down into the hero.

   The mark is never re-parented into the hero — this element rebuilds its
   whole scene on reconnect — so it stays fixed on the stage for good and a
   transform maps the stage onto the hero slot. That is also what keeps it
   outside the `inert` subtree while the page behind is closed.

   Nothing here is on by default: `data-gate` is set from JS only once the
   3D mark is actually running, so a reduced-motion visitor, a browser
   without WebGL and a failed three.js all get the ordinary page rather than
   a door they cannot open. */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 5;
  background: var(--bn-bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 1s ease .35s;
}
/* The curtain is the last element in the body, so on a slow connection the
   browser can paint the hero before it exists. These are the same sections
   landing.js makes inert, hidden from the moment they are parsed — the
   guarantee then does not depend on paint timing or DOM order. `visibility`,
   not `display`: the hero slot must keep its box, because that is what the
   mark is measured against when it lands. They come back instantly on entry,
   under a curtain that is still opaque and takes a second to go. */
html[data-gate="closed"] .hero,
html[data-gate="closed"] .cards,
html[data-gate="closed"] .pricing { visibility: hidden; }
/* The foot is no longer hidden with them: the entrance screen carries the
   copyright line, so the door has the same bottom rule as the top one. Only
   the copyright, though — the links beside it go, because the whole footer is
   inert while the page is shut and a link you cannot follow is worse than no
   link at all.

   `display: none` rather than `visibility: hidden`: hidden would still hold
   its place in the column and leave a gap under the copyright. The layout has
   to lose it, not just the paint. */
html[data-gate="closed"] .foot-links { display: none; }

/* Pinned to the viewport rather than left in flow: the hero and the cards
   above it are merely invisible, not absent, so in normal flow the footer
   sits a screen or two below the door.

   It goes back into flow only at `settled`, and fades out during `open` so
   that hand-off is never seen — `position` cannot be transitioned, so a
   pinned bar that simply reverted would drop the width of the page in one
   frame while the curtain was still fading over it. */
html[data-gate="closed"] .foot,
html[data-gate="open"] .foot {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 7;
}
html[data-gate="open"] .foot { opacity: 0; transition: opacity .45s ease; }

/* Instant on the way in, slow on the way out. A transition lives in the rule
   you are transitioning *to*, so declaring it once in the base rule fades the
   curtain in as well — which is the page visibly disappearing over 1.35s
   instead of never having been shown. */
html[data-gate="closed"] .curtain { opacity: 1; pointer-events: auto; transition: none; }

/* The nav is raised over the curtain rather than duplicated behind it. The
   design canvas draws a second brand-plus-controls row on top, because in that
   framework the whole nav is inert while the page is shut; here the real nav
   can simply be lifted, which means one language picker with one set of ids
   and — the part that matters — nothing to crossfade, so nothing can jump as
   the curtain lifts. It stays lifted through the flight so the mark passes
   under it, and drops back once everything has landed.

   What the visitor may touch while shut: the coffee link and the language
   picker, exactly as the canvas has it. The brand link and everything below
   are inert (landing.js), so the only way onward is the heart. */
/* The BAR is raised, not the row inside it — so the rule under the nav is
   lifted over the curtain along with the brand and the controls, and the
   entrance screen carries the same top line as the settled page (Sergio's
   call, 2026-09-06). Raising `.nav` alone left the border underneath, which
   is the earlier behaviour this replaces.
   `.lang-menu` positions against `.lang-picker`, not against the nav, so
   moving the positioned ancestor up one level changes nothing for it. */
html[data-gate]:not([data-gate="settled"]) .navbar { position: relative; z-index: 7; }
/* The call to action belongs to the page, not to the door — it fades in with
   everything else rather than sitting there unpressable. */
.hero-copy .pill-sheen { transition: transform .2s ease, box-shadow .2s ease, opacity .8s ease; }
html[data-gate="closed"] .hero-copy .pill-sheen { opacity: 0; transition: none; }

.orb-stage {
  position: fixed;
  inset: 0;
  z-index: 6;
  transform-origin: 0 0;
  transition: transform 1.25s cubic-bezier(.65, 0, .35, 1);
  /* Empty until the mark mounts, and a transparent fixed sheet would
     otherwise swallow every click on the page underneath. */
  pointer-events: none;
}
.orb-stage bnear-orb { pointer-events: auto; }
/* The stage only owns the glow once it owns the mark. Without this, a visitor
   whose three.js never arrives gets a window-wide teal wash behind the still
   mark — the glow sized for a full-screen stage that never got one. */
.orb-stage > .orb-glow { display: none; }
.orb-stage[data-live="true"] > .orb-glow { display: block; }
/* Once it has landed, the transform tracks scroll and resize — animating
   that would make the mark swim behind the hero. */
html[data-gate="settled"] .orb-stage { transition: none; }

/* ── The join sheet ─────────────────────────────────────────────
   Above everything, the mark included: it is a different question, not a
   layer over this one. Opaque, so the page behind is gone rather than dimmed.
   landing.js makes the page behind inert while it is open. */
.join-sheet {
  position: fixed;
  inset: 0;
  z-index: 9;
  background: var(--bn-bg);
  display: flex;
  flex-direction: column;
  animation: bnRise .5s cubic-bezier(.2, .8, .2, 1) both;
  overflow-y: auto;
}
.join-sheet-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
  padding-top: var(--s-5);
  padding-bottom: var(--s-5);
}
.join-sheet-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-bottom: 60px;
}
.join-sheet-body > div { max-width: 700px; }
.join-sheet h2 {
  font-size: clamp(34px, 4.6vw, 62px);
  font-weight: 200;
  line-height: 1.04;
  letter-spacing: -0.03em;
  margin: 0 0 var(--s-5);
  text-wrap: balance;
}
.join-sheet p {
  font-size: var(--fs-lede);
  line-height: 1.62;
  color: var(--bn-muted);
  max-width: 46ch;
  margin: 0 0 var(--s-7);
  text-wrap: pretty;
}
.join-actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* ── Cards ──────────────────────────────────────────────────── */
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); padding-bottom: 40px; }
.card {
  background: var(--bn-card);
  border: 1px solid var(--bn-line);
  border-radius: var(--r-card-lg);
  padding: 26px 28px;
  transition: transform .25s var(--ease-lift), box-shadow .25s ease;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }
.card h2 { font-size: var(--fs-body); font-weight: 500; margin-bottom: 10px; }
.card p { font-size: var(--fs-body-sm); line-height: 1.65; color: var(--bn-muted); }
/* The line break in this one is deliberate: the claim, then the instruction.
   pre-line honours the newline in the string and still collapses the rest, so
   the copy stays one translatable unit instead of two keys glued together. */
[data-t="card1"] { white-space: pre-line; }
.scale-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.scale-head span:first-child { font-size: var(--fs-body); font-weight: 500; }
.scale-bar {
  height: 6px;
  flex: 1;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--t-365), var(--t-370), var(--t-380), var(--t-400));
}
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.tags span {
  padding: 4px 11px;
  border-radius: var(--r-pill);
  background: var(--color-accent-100);
  color: var(--color-accent-800);
  font-size: var(--fs-cap);
}

/* ── Footer ─────────────────────────────────────────────────── */
/* Centred, and stacked to make that true of the copyright itself rather than
   only of the group: in a centred row the fine print would still sit
   left-of-centre. Stacking it also means the line does not move sideways when
   the entrance door opens — it is centred there and centred here. */
.foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding-top: 20px;
  padding-bottom: 28px;
  border-top: 1px solid var(--bn-line);
  font-size: var(--fs-meta);
  color: var(--bn-muted);
  text-align: center;
}
/* The wordmark sits inline in a 13px copyright line, so it takes that size
   and that colour — the same scoping the hero lede uses. Only the weight
   carries the brand here: this is a copyright line, not a logo. */
.foot-copy { display: inline-flex; align-items: baseline; gap: 5px; }
.foot .wordmark { font-size: inherit; color: inherit; }

.foot-links { display: flex; gap: 20px; }
.foot a { color: var(--bn-muted); }
.foot a:hover { color: var(--color-accent); }


/* ── Plans ──────────────────────────────────────────────────────
   The last band on the page. Four rows repeated in all three cards, on or
   off, because the visitor's real question is what is different between them
   and three unequal lists make that a reading exercise. */
.pricing { padding-top: 8px; padding-bottom: 56px; }

.pricing-head { text-align: center; margin-bottom: var(--s-6); }
.pricing-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  margin-bottom: 10px;
}
.pricing-head h2 {
  font-size: clamp(24px, 3.2vw, 34px);
  font-weight: 400;
  line-height: 1.2;
  color: var(--bn-ink);
  text-wrap: balance;
}
.pricing-lede {
  max-width: 54ch;
  margin: 12px auto 0;
  color: var(--bn-muted);
  line-height: 1.6;
}

.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); align-items: start; }

.tier {
  position: relative;
  background: var(--bn-card);
  border: 1px solid var(--bn-line);
  border-radius: var(--r-card-lg);
  padding: 26px 28px 28px;
  transition: transform .25s var(--ease-lift), box-shadow .25s ease;
}
.tier:hover { transform: translateY(-3px); box-shadow: 0 18px 40px -28px rgba(16, 42, 38, .45); }
.tier h3 { font-size: 15px; font-weight: 600; color: var(--bn-ink); }

/* Private is the one that opens the conversation, which is the product's
   whole argument, so it carries the accent and sits a step forward. */
.tier.featured { border-color: var(--color-accent-300); box-shadow: 0 20px 44px -30px rgba(15, 158, 140, .55); }
.tier-badge {
  position: absolute;
  top: -10px;
  left: 28px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--color-accent);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.tier-price { display: flex; align-items: baseline; gap: 3px; margin: 10px 0 2px; }
.tier-amount {
  font-size: 30px;
  font-weight: 300;
  color: var(--bn-ink);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.tier-per { font-size: 13px; color: var(--bn-muted); }
.tier-sub { font-size: 13px; color: var(--bn-muted); min-height: 2.9em; line-height: 1.5; }

.tier-feats { list-style: none; margin-top: 16px; border-top: 1px solid var(--bn-line); padding-top: 16px; }
.tier-feats li {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 9px;
  align-items: start;
  padding: 7px 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--bn-ink);
}
/* A row that is off stays in place rather than disappearing — that is what
   makes the three cards comparable line for line. */
.tier-feats li[data-on="no"] { color: var(--bn-muted); opacity: .55; }

.tick { width: 16px; height: 16px; margin-top: 1px; border-radius: 50%; position: relative; }
li[data-on="yes"] > .tick { background: var(--color-accent-100); }
li[data-on="yes"] > .tick::after {
  content: "";
  position: absolute;
  left: 5px; top: 3px;
  width: 4px; height: 8px;
  border: solid var(--color-accent-800);
  border-width: 0 1.8px 1.8px 0;
  transform: rotate(45deg);
}
li[data-on="no"] > .tick::after {
  content: "";
  position: absolute;
  left: 3px; top: 7px;
  width: 10px; height: 1.5px;
  background: var(--bn-line);
}

/* Student: a wide strip rather than a fourth column. Its feature rows would
   be Professional's exactly, and a column of identical ticks claims a
   difference that is not there — the difference is who it is for and how you
   get it, which is what this band says instead. Tinted rather than white, so
   it reads as an offer and not as a footnote under the cards. */
.tier-extra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  flex-wrap: wrap;
  margin-top: var(--s-4);
  padding: 20px 28px;
  border: 1px dashed var(--color-accent-300);
  border-radius: var(--r-card-lg);
  background: linear-gradient(180deg, rgba(15, 158, 140, .045), rgba(15, 158, 140, .015));
}
.tier-extra-main { min-width: 0; }
.tier-extra-name {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 15px;
  font-weight: 600;
  color: var(--bn-ink);
}
/* It is never self-serve, and the label says so where the price is read. */
.tier-extra-tag {
  padding: 2px 9px;
  border-radius: var(--r-pill);
  background: var(--color-accent-100);
  color: var(--color-accent-800);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.tier-extra-sub { margin-top: 5px; font-size: 13px; line-height: 1.55; color: var(--bn-muted); max-width: 62ch; }
.tier-extra-price { display: flex; align-items: baseline; gap: 3px; }
.tier-extra-side { display: flex; align-items: center; gap: var(--s-4); flex: none; }
/* Quiet, because it is an ask and not a purchase — every other action on this
   page leads to a form that takes your money, and this one leads to a
   conversation. */
.tier-extra-ask {
  padding: 7px 15px;
  border: 1px solid var(--color-accent-300);
  border-radius: var(--r-pill);
  background: var(--bn-card);
  color: var(--color-accent-800);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  transition: background .18s ease, border-color .18s ease;
}
.tier-extra-ask:hover { background: var(--color-accent-100); border-color: var(--color-accent); color: var(--color-accent-800); }
.pricing-cta { display: inline-flex; margin: var(--s-5) auto 0; }
.pricing .pricing-cta { display: flex; width: fit-content; }

/* The reveal.

   The resting state here is VISIBLE. landing.js sets data-reveal="armed",
   and that is the only thing that hides a tier — so no JavaScript, no
   IntersectionObserver or a script that threw all leave the prices on the
   page. Never write the hidden state as the default. */
.pricing[data-reveal="armed"] .tier,
.pricing[data-reveal="armed"] .tier-extra,
.pricing[data-reveal="armed"] .pricing-cta { opacity: 0; transform: translateY(16px); }
.pricing[data-reveal="in"] .tier,
.pricing[data-reveal="in"] .tier-extra,
.pricing[data-reveal="in"] .pricing-cta {
  opacity: 1;
  transform: none;
  transition: opacity .55s ease, transform .55s var(--ease-lift);
}
.pricing[data-reveal="in"] .tier:nth-child(2) { transition-delay: .08s; }
.pricing[data-reveal="in"] .tier:nth-child(3) { transition-delay: .16s; }
.pricing[data-reveal="in"] .tier-extra { transition-delay: .24s; }
.pricing[data-reveal="in"] .pricing-cta { transition-delay: .30s; }
/* The hover lift and the reveal both write `transform`, so the hover has to
   wait until the tier has landed or it fights the entrance mid-flight. */
.pricing[data-reveal="in"] .tier:hover { transform: translateY(-3px); }


/* ── Signing yourself up ────────────────────────────────────────
   The page behind "Be a Caregiver". It reuses the landing's shell, nav and
   tier vocabulary rather than inventing a second look for the same product. */
.join-main { padding-top: var(--s-6); padding-bottom: var(--s-7); max-width: 760px; }
.join-head { text-align: center; margin-bottom: var(--s-6); }
.join-head h1 {
  font-size: clamp(24px, 3.4vw, 32px);
  font-weight: 400;
  line-height: 1.2;
  color: var(--bn-ink);
  text-wrap: balance;
  margin-top: 8px;
}

.join-plans, .join-form fieldset { border: 0; padding: 0; margin: 0 0 var(--s-6); }
.join-plans legend, .join-form legend {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  margin-bottom: var(--s-3);
  padding: 0;
}

.join-tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-3); }
/* Off-screen, not display:none — a hidden radio is not focusable and the
   keyboard would lose the choice entirely. */
.join-tiers input { position: absolute; opacity: 0; pointer-events: none; }
.join-tier {
  display: flex;
  flex-direction: column;
  gap: 4px;
  height: 100%;
  padding: 16px 18px;
  border: 1px solid var(--bn-line);
  border-radius: var(--r-card-lg);
  background: var(--bn-card);
  cursor: pointer;
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s var(--ease-lift);
}
.join-tier:hover { transform: translateY(-2px); }
.join-tiers input:checked + .join-tier {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 1px var(--color-accent), 0 18px 40px -30px rgba(15, 158, 140, .6);
}
/* The radios are off-screen, so the focus ring has to be put back by hand or
   a keyboard user cannot see where they are. */
.join-tiers input:focus-visible + .join-tier { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.join-tier-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.join-tier-name { font-size: 14px; font-weight: 600; color: var(--bn-ink); }
.join-tier .tier-amount { font-size: 24px; }
.join-tier-sub { font-size: 12px; line-height: 1.45; color: var(--bn-muted); }
.join-tier-feats { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; }
.join-tier-feats span { font-size: 11.5px; line-height: 1.4; color: var(--bn-muted); }
/* The tick is the literal character, not a \2713 escape: this file is edited
   through shells that eat a backslash before the CSS ever sees it, and the
   escape arrived as an octal one instead — it rendered as "¹3". */
.join-tier-feats span::before { content: "✓"; color: var(--color-accent); margin-right: 5px; }

.join-field { display: block; margin-bottom: var(--s-4); }
.join-field > span { display: block; font-size: 13px; font-weight: 500; color: var(--bn-ink); margin-bottom: 5px; }
.join-field input {
  width: 100%;
  font: inherit;
  font-size: 15px;
  color: var(--bn-ink);
  background: var(--bn-card);
  border: 1px solid var(--bn-line);
  /* Near-square, like the conversation composer: these are boxes a person
     types into, and --r-md is a 999px pill. */
  border-radius: var(--r-xs);
  padding: 11px 13px;
}
.join-field input:focus { outline: 2px solid var(--color-accent); outline-offset: 1px; border-color: var(--color-accent); }
.join-field input:user-invalid { border-color: var(--bn-coral); }
.join-note { display: block; margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--bn-muted); }

.join-error {
  margin-bottom: var(--s-4);
  padding: 11px 14px;
  border: 1px solid var(--bn-danger-line);
  border-radius: var(--r-xs);
  background: var(--bn-danger-bg);
  color: var(--bn-danger-head);
  font-size: 13px;
  line-height: 1.5;
}
/* Centred, with the sentence under it centred too — a centred button over a
   left-aligned line reads as two separate things rather than one action and
   its consequence. */
.join-cta { display: flex; width: fit-content; margin-inline: auto; }
.join-small {
  margin: var(--s-3) auto 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--bn-muted);
  max-width: 60ch;
  text-align: center;
}

@media (max-width: 640px) {
  /* One per row rather than three 100px columns. The feature list under each
     price is the part that stops being readable first. */
  .join-tiers { grid-template-columns: 1fr; }
  .join-cta, .join-cta .pill-cta { width: 100%; }
}


/* ── After signing up ───────────────────────────────────────────
   The account exists and the password is on screen for the only time it ever
   will be, so this step exists to be stopped at rather than passed through. */
.join-done { text-align: center; }
.join-done h2 {
  font-size: clamp(22px, 3vw, 28px);
  font-weight: 400;
  line-height: 1.25;
  color: var(--bn-ink);
  margin-top: 8px;
  text-wrap: balance;
}
.join-done-lede { margin-inline: auto; }

.join-creds {
  display: grid;
  gap: var(--s-3);
  margin: var(--s-5) auto;
  max-width: 420px;
  padding: 18px 22px;
  border: 1px solid var(--color-accent-300);
  border-radius: var(--r-card-lg);
  background: var(--bn-card);
  text-align: left;
}
.join-creds > div { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4); }
.join-creds dt { font-size: 12.5px; color: var(--bn-muted); }
/* The password is meant to be read off the screen and typed, so it is set in
   the mono face where l, 1, O and 0 are told apart, and selectable. */
.join-creds dd {
  font-family: var(--bn-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 15px;
  color: var(--bn-ink);
  word-break: break-all;
  text-align: right;
  user-select: all;
}

.join-done-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
}
/* WhatsApp's own green, because this button says which app is about to open.
   It is the quieter of the two: saving the password matters, but Be a
   Caregiver is the one that carries on. */
.btn-wa {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 20px;
  border: 1px solid #25D366;
  border-radius: var(--r-pill);
  background: var(--bn-card);
  color: #128C46;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background .18s ease;
}
.btn-wa:hover { background: #eafaf0; }

@media (max-width: 640px) {
  /* Full width and stacked, in the order they should be pressed. */
  .join-done-actions { flex-direction: column; align-items: stretch; }
  .join-done-actions .pill-sheen, .join-done-actions .pill-cta { width: 100%; }
}

/* ── Narrow ─────────────────────────────────────────────────── */
@media (max-width: 980px) {
  .hero { grid-template-columns: 1fr; gap: var(--s-5); padding-bottom: var(--s-7); }
  /* Sits under the copy once the hero stacks, at a height that leaves the
     headline leading and brings the orb in with a short scroll. */
  .orb-slot { height: 320px; min-height: 0; }
  .cards { grid-template-columns: 1fr; }
  /* Two across before one: three tiers side by side at 900px are too narrow
     for a feature line to sit on one row, and stacking straight to a single
     column wastes a tablet. The featured one takes the full width underneath,
     which keeps it the emphasised card rather than an orphan. */
  .tiers { grid-template-columns: repeat(2, 1fr); }
  .tier.featured { order: -1; grid-column: 1 / -1; }
  .nav { flex-wrap: wrap; gap: var(--s-3); }
}

@media (max-width: 640px) {
  .tiers { grid-template-columns: 1fr; }
  /* Both the span and the reordering are undone. Pulling the featured card
     to the front earns its place in the two-column layout, where it would
     otherwise be an orphan on the second row — stacked, it just breaks the
     ladder: the features accumulate down Free, Private, Professional, and
     leading with the middle one makes that pattern unreadable. */
  .tier.featured { grid-column: auto; order: 0; }
  /* Stacked, the cards set their own height, so the line that reserved room
     for a two-line subtitle only adds a gap. */
  .tier-sub { min-height: 0; }
  /* The badge sits on the card's top edge; with the cards stacked it needs
     the gap above it not to be the previous card's shadow. */
  .tiers { gap: var(--s-5); }
  /* The price goes under the copy rather than squeezing a 62ch paragraph
     into whatever is left beside it. */
  .tier-extra { flex-direction: column; align-items: flex-start; gap: var(--s-3); padding: 20px 22px; }
  /* The price and the ask stay on one row even when the band stacks — they
     belong together, and two stacked lines here reads as two separate
     things. */
  .tier-extra-side { width: 100%; justify-content: space-between; }
}
/* Below this the coffee wordmark drops to its cup — the nav's last piece of
   width that is decoration rather than a control. The language control does
   not change here any more: it is the same dropdown at every width. */
/* The consoles narrow their inset here, so the landing does too. Below this
   the three surfaces would otherwise agree on a desktop and disagree on a
   phone, which is the version nobody notices until it looks wrong. */
@media (max-width: 720px) {
  :root { --inset: var(--s-4); }
}

@media (max-width: 700px) {
  /* The cup and the heart stay; the wordmark is what the nav cannot afford.
     Scoped through .bmc on purpose: `.bmc img { display: block }` above is
     (0,1,1) and would outrank a bare .bmc-wordmark, so the hide would never
     apply. */
  .bmc .bmc-wordmark { display: none; }
}

@media (max-width: 520px) {
  .hero-copy .pill-sheen { width: 100%; }
  .hero-copy .pill-cta { width: 100%; justify-content: center; }
  .nav-right { gap: var(--s-2); }

  /* ── Keeping the nav on one line ──────────────────────────────
     The nav wraps at 980px, so on a phone the brand and this row are free
     to fall onto separate lines — which is what they did once the wordmark
     grew from "bNear" to "b-Near.me". Nothing here is a new shape: the cup,
     the heart and the language pill just stop paying for width they do not
     need at this size. Measured against 390px (iPhone Pro), the narrowest
     of the current iPhones. The join button reads "Join Circle" in all
     three languages, so the nav is the same width in each — translate it
     and this budget has to be redone. */
  .bmc { height: 18px; }
  .bmc-cup { width: 18px; height: 18px; }
  .bmc-heart { margin-left: 5px; padding: 3px 7px 3px 5px; gap: 3px; }
  .bmc-heart:has(#bmcCount:empty) { padding: 3px 5px; }
  .bmc-heart svg { width: 11px; height: 11px; }

  .lang-trigger { padding: 6px 9px; gap: 4px; }
  .lang-caret { width: 9px; height: 9px; }
  .orb-slot { height: 280px; }
  .orb-still img { width: min(78%, 240px); }
  /* The clamp above floors at 40px, which the longest headline word cannot
     fit under ~360px. Desktop is untouched; this only lowers the floor. */
  .hero h1 { font-size: clamp(30px, 8.6vw, 40px); }
}

/* Every phone, not just the small ones. 440px is the widest iPhone (16 Pro
   Max); below it the nav has to hold "Join a Circle" — the longest label the
   button has carried — beside the brand on one row. Measured at 402px it had
   2.4px to spare under the 520px rules alone, which is inside the margin
   Safari and Chrome disagree by, so the whole phone range gets this instead
   of only the narrow end of it. Everything here is the same shape a size
   smaller. */
@media (max-width: 440px) {
  .nav { gap: var(--s-2); }
  .nav-right { gap: 6px; }
  .nav .brand { gap: 8px; }
  .nav .brand img { width: 27px; height: 27px; }
  .nav .wordmark { font-size: 18px; }
  .lang-trigger { padding: 6px 8px; }
  .bmc-heart { margin-left: 4px; }
}

/* The narrow end: a 360px Android overran the block above by ~9px, and a
   375px SE or mini sat 6px from the edge. 380px catches both. */
@media (max-width: 380px) {
  .nav-right { gap: 5px; }
  .nav .brand { gap: 6px; }
  .nav .brand img { width: 25px; height: 25px; }
  .nav .wordmark { font-size: 17px; }
}
