/* coach.css — loaded by coach.html ONLY.
 *
 * The Coach page. base.css loads first and supplies the tokens, the reset, the
 * nav and the footer; everything below is this page's own.
 *
 * SELF-CONTAINED BY DECISION. Nothing this page needs gets promoted into
 * base.css, even where another page happens to have a rule that looks the
 * same. If this file ends up duplicating something from home.css, that is the
 * intended trade: the landing page and this page are free to move
 * independently, and neither can break the other by accident.
 */


/* Visually hidden, still read aloud and still counted by search engines.
   Defined here rather than borrowing home.css's .sr-only — see the header. */
.coach-a11y {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}


/* ──────────────────── STAGE ────────────────────
   The band the card sits on. Top padding clears the fixed nav. */
.coach-stage {
  padding: calc(150px + env(safe-area-inset-top)) 0 96px;
}


/* ──────────────────── INTRO ────────────────────
   The copy above the card. Centred as a column: the text is short enough that
   a centred block still scans in one pass, and it keeps the eye travelling
   straight down into the card rather than back to a left margin.

   Everything here sets its own max-width and centres with `margin-inline:
   auto`. base.css caps every <p> at 60ch, which centres the BOX but not the
   line breaks — a paragraph left at that cap sits flush left inside a wider
   container and quietly breaks the alignment. */
.coach-intro {
  max-width: 760px;
  margin: 0 auto 84px;
  text-align: center;
}

/* Sans, not the serif every other h1 on the site uses. This page's headline
   sits directly above a chat UI that is entirely sans, and the serif read as a
   marketing banner pasted on top of a product — the exact "designer section"
   problem this page exists to fix.

   Smaller than base.css's h1 scale on purpose: Manrope at 700 has far more ink
   per character than Newsreader at 500, so matching the serif's point size
   would out-shout the card below it. */
.coach-intro h1 {
  margin: 0 auto;
  font-family: var(--sans);
  font-weight: 700;
  font-size: clamp(40px, 5.2vw, 68px);
  line-height: 1.12;
  /* Display-size sans needs more negative tracking than base.css's -0.02em,
     which is tuned for the serif. */
  letter-spacing: -0.035em;
}

/* base.css marks h1 em with italic + weight 400. Both have to go here: there is
   no italic Manrope face on the site, so `font-style: italic` would be
   synthesised as a mechanical skew, and 400 next to 700 reads as a mistake
   rather than as emphasis. The green underline base.css draws carries the
   emphasis on its own — it is the only cue this em needs.

   nowrap keeps the underlined phrase on one line. An em broken across two lines
   renders the underline as two disconnected stubs. Done this way rather than by
   capping the h1's width, because a width cap is tuned to one exact headline and
   silently breaks the next time the copy changes. */
.coach-intro h1 em {
  font-style: normal;
  font-weight: inherit;
  white-space: nowrap;
}

.coach-lede {
  max-width: 52ch;
  margin: 28px auto 0;
  color: var(--ink-fg2);
  font-size: 18px;
  line-height: 1.7;
}


/* ──────────────────── THE CARD ────────────────────
   Reads as an object resting above the page rather than a section of it.
   Three things do that together, and removing any one flattens it:

     1. It is lighter than the page. #1C1C1E on the site's #0F1714 ground.
        That specific value is the app's own screen colour, so the chat that
        goes in here later matches the native product exactly.
     2. A lit top edge and a darker bottom one — the inset highlight and the
        hairline border. This is what sells "physical" at close range.
     3. Cast shadow in two parts: a tight contact shadow that anchors it, and
        a wide diffuse one that puts air underneath. On a ground this dark a
        single black shadow is invisible, which is why there is also a faint
        moss-tinted bloom behind the card (.coach-card-wrap::before).

   The brand otherwise uses no shadows. This is the deliberate exception. */
.coach-card-wrap {
  position: relative;
  /* Room for the bloom to spread into without being clipped by the section. */
  isolation: isolate;
}

/* The ambient bloom. Sits behind the card, tinted rather than neutral so the
   lift reads on a near-black page instead of disappearing into it.

   The inset is NEGATIVE on every side on purpose: the card is opaque, so a
   bloom inside its footprint is simply covered up and the whole effect is
   wasted. It has to spill past the edges to be seen at all. */
.coach-card-wrap::before {
  content: '';
  position: absolute;
  inset: -5% -6% -9%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(
    ellipse at 50% 55%,
    rgba(95,149,105,0.22) 0%,
    rgba(95,149,105,0.10) 45%,
    rgba(95,149,105,0) 74%
  );
  filter: blur(58px);
  pointer-events: none;
}

.coach-card {
  position: relative;
  display: flex; flex-direction: column;
  border-radius: 30px;
  background: #1C1C1E;
  border: 1px solid rgba(244,237,227,0.10);
  /* The log scrolls edge to edge inside the card, so it has to be clipped by
     the same radius or messages ride over the rounded corners. */
  overflow: hidden;
  box-shadow:
    /* contact — anchors the card to the page */
    0 2px 6px rgba(0,0,0,0.45),
    /* lift — the air underneath */
    0 34px 70px -24px rgba(0,0,0,0.85),
    /* spread — keeps the falloff from banding on the dark ground */
    0 60px 130px -50px rgba(0,0,0,0.7),
    /* lit top edge */
    inset 0 1px 0 rgba(244,237,227,0.07);

  height: min(640px, calc(100svh - 250px));
}


/* ──────────────────── THE CHAT INSIDE THE CARD ────────────────────
   Wired to chat.js through #ai-chat-widget and the data-chat-* hooks. The
   markup and the interaction are the landing page's, unchanged: the log is
   bottom-anchored, the chips disappear after the first message, the dock
   floats over the conversation and the messages fade out behind it.

   What differs is measure. The card is ~1116px wide and a paragraph set to
   that is unreadable, so the conversation is centred in a fixed column and
   the card's width becomes margin. Both the log and the dock use the same
   column so the input lines up under the text.

   READ BEFORE DELETING ANY .msg-* RULE: chat.js builds every bubble in
   JavaScript — .msg-user and .msg-coach are even concatenated ('msg msg-' +
   role) — so none of these class names appear in the HTML and a search of the
   JS won't find those two either. Every dead-CSS tool will call this whole
   family unused and every one of them is wrong. Delete them and the page
   still looks perfect while the coach's replies render unstyled. */
.coach-card {
  /* The readable column the conversation is centred in — roughly 70
     characters at this size. The log and the dock both use it, so the input
     lines up exactly under the text. */
  --coach-measure: 660px;
}

/* base.css caps every <p> at 60ch. Inside the log that fights the measure
   above: the text stops wrapping well before the column ends and the input
   sits wider than the paragraphs it belongs to. One authority, not two —
   width here is the measure's job, and the bubble's own max-width for the
   visitor's messages. */
.chat-log p { max-width: none; }

.chat { position: relative; flex: 1 1 auto; min-height: 0; }

.chat-log {
  position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 24px;
  padding-block: 44px 168px;
  padding-inline: max(24px, calc((100% - var(--coach-measure)) / 2));
  scrollbar-width: none;
}

/* Once the chips are gone the dock is shorter, so the log gets its space back. */
.chat:has(.chat-chips[hidden]) .chat-log { padding-bottom: 132px; }

.chat-log::-webkit-scrollbar { width: 0; height: 0; }

/* The app's list is inverted — the conversation sits on the bottom edge. */
.chat-log > *:first-child { margin-top: auto; }


/* Decorative: messages fade out behind the floating dock instead of being
   hard-clipped by it. Both gradients are #1C1C1E — the card's own background.
   Change the card colour and these have to change with it or the fade shows
   as a visible band. */
.chat-scrim-top, .chat-scrim-bottom {
  position: absolute; left: 0; right: 0; pointer-events: none; z-index: 2;
}

.chat-scrim-top {
  top: 0; height: 52px;
  background: linear-gradient(180deg, rgba(28,28,30,1) 0%, rgba(28,28,30,0) 100%);
}

.chat-scrim-bottom {
  bottom: 0; height: 150px;
  background: linear-gradient(0deg, rgba(28,28,30,1) 0%, rgba(28,28,30,0.92) 46%, rgba(28,28,30,0) 100%);
}


.chat-dock {
  position: absolute; bottom: 0; left: 0; right: 0; z-index: 3;
  padding-block: 30px 20px;
  padding-inline: max(24px, calc((100% - var(--coach-measure)) / 2));
}

.chat:has(.chat-chips[hidden]) .chat-dock { padding-top: 0; }


/* ---- messages: the coach's replies are plain text, not bubbles ---- */
.msg-coach {
  display: flex; flex-direction: column; gap: 8px;
  font-size: 16px; line-height: 23px; color: #fff;
}

.msg-label { display: flex; align-items: center; gap: 8px; }

.msg-label i { font-size: 14px; color: var(--moss); }

.msg-label span { font-size: 12px; font-weight: 600; color: rgba(235,235,245,0.6); }


.msg-body { display: flex; flex-direction: column; }

.msg-body > * { margin: 0; }

/* 12px between blocks; a heading takes 24 above and gives 8 to whatever
   follows it — headings belong with their content. */
.msg-body > * + * { margin-top: 12px; }

.msg-body > .msg-h + * { margin-top: 8px; }

.msg-body > .msg-h { margin-top: 24px; font-size: 20px; line-height: 26px; font-weight: 600; }

.msg-body > .msg-h:first-child { margin-top: 0; }

.msg-body p { white-space: pre-wrap; }

.msg-list { display: flex; flex-direction: column; gap: 8px; }

.msg-li { display: flex; gap: 10px; }

.msg-li > .bullet { flex-shrink: 0; color: rgba(235,235,245,0.6); }

.msg-li.pending > .bullet { color: transparent; }

.msg-li > .t { flex: 1 1 auto; min-width: 0; }

/* The not-yet-typed tail: still occupies space, so nothing reflows as the
   reply types itself out. */
.pending { color: transparent; }

/* chat.js emits this for ==highlighted== spans. There is no rule for it
   anywhere in home.css, so on the landing page a highlight currently renders
   as plain text — this is the first place it actually gets styled. */
.msg-mark {
  background: rgba(95,149,105,0.22);
  border-radius: 4px;
  padding: 0 3px;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}


.msg-user {
  align-self: flex-end; max-width: 85%; padding: 12px 16px; border-radius: 20px;
  background: linear-gradient(to bottom, var(--moss), var(--moss-dark));
  font-size: 16px; line-height: 22px; color: #fff;
}

.msg-user p { margin: 0; }

.msg-user p + p { margin-top: 8px; }


.msg-note { font-size: 14px; line-height: 20px; color: rgba(235,235,245,0.6); }

.msg-note p { margin: 0; }


/* "Coach is thinking…" — the app's quiet tempo, dots cycling 1→2→3. */
.msg-typing { font-size: 14px; font-style: italic; line-height: 20px; color: rgba(235,235,245,0.6); }


/* ---- the dock: suggested topics, then the input ---- */
.chat-chips { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 10px; scrollbar-width: none; }

.chat-chips::-webkit-scrollbar { display: none; }

.chat-chips[hidden] { display: none; }

.chat-chip {
  appearance: none; -webkit-appearance: none; font: inherit; cursor: pointer;
  flex-shrink: 0; white-space: nowrap;
  font-size: 13px; font-weight: 700; padding: 9px 16px; border-radius: 9999px;
  border: 2px solid transparent;
  /* The padding-box layer must match the card background, or the pill shows a
     dark rectangle behind its rounded gradient border. */
  background: linear-gradient(#1C1C1E, #1C1C1E) padding-box,
              linear-gradient(135deg, var(--moss-bright), var(--moss)) border-box;
  color: var(--moss-bright); transition: background-color .15s, filter .15s;
}

.chat-chip:hover {
  background: linear-gradient(rgba(95,149,105,0.18), rgba(95,149,105,0.18)) padding-box,
              linear-gradient(135deg, var(--moss-bright), var(--moss)) border-box;
}


.chat-form { display: flex; gap: 10px; align-items: flex-end; }

.chat-form textarea {
  flex: 1; resize: none; font-family: var(--sans);
  /* 16px keeps iOS from zooming the page on focus — do not lower */
  font-size: 16px; line-height: 22px; min-height: 48px; max-height: 110px;
  padding: 12px 16px; border-radius: var(--radius-lg);
  background: rgba(0,0,0,0.28); color: var(--ink-fg);
  border: 1px solid rgba(255,255,255,0.12); outline: none;
  transition: border-color .15s;
}

.chat-form textarea::placeholder { color: rgba(244,237,227,0.42); }

.chat-form textarea:focus { border-color: rgba(95,149,105,0.6); }

.chat-form textarea:disabled { opacity: .5; }


.chat-send {
  flex-shrink: 0; width: 44px; height: 44px; border-radius: 9999px;
  display: grid; place-items: center; cursor: pointer; font-size: 19px;
  color: #fff; border: 1px solid transparent;
  background: linear-gradient(to bottom, var(--moss), var(--moss-dark));
  transition: opacity .15s;
}

.chat-send:disabled { opacity: .4; cursor: not-allowed; }


/* ──────────────────── CHAT DISCLOSURE ────────────────────
   Framed as its own quiet card rather than left as loose text under the
   widget. Same grammar the rest of the page already uses for a "held"
   element — a translucent fill, a hairline gradient border built the same
   two-layer way as .chat-chip (padding-box fill, border-box gradient), and a
   soft moss-tinted lift — just calmer, since this is a disclosure, not a CTA.
   Deliberately quiet but never hidden — see the comment on the markup in
   coach.html. */
.chat-note {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 28px auto 0; max-width: 600px;
  padding: 16px 18px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background:
    linear-gradient(160deg, rgba(95,149,105,0.10), rgba(28,28,30,0.6) 60%) padding-box,
    linear-gradient(160deg, rgba(169,205,175,0.30), rgba(95,149,105,0.08)) border-box;
  box-shadow: 0 14px 32px -22px rgba(0,0,0,0.65);
  font-size: 12.5px; line-height: 1.6; color: var(--ink-fg2);
  text-align: left;
}

.chat-note i {
  flex-shrink: 0; display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  font-size: 13px; color: var(--moss-bright);
  background: rgba(95,149,105,0.16);
}

.chat-note strong { color: var(--ink-fg); font-weight: 600; }

.chat-note a { color: var(--moss-bright); text-decoration: underline; text-underline-offset: 2px; }


/* ──────────────────── WAITLIST ────────────────────
   Copied from home.css rather than extracted to base.css — see the file
   header. The two are byte-identical today and are allowed to diverge.

   Wired to signup.js through #waitlist-form and the data-signup-* hooks.
   .notify-hp is the honeypot and .notify-input.invalid is applied by signup.js
   only after a failed submit; neither appears in a normal page state, and both
   look unused to any dead-CSS tool. */
.notify-sec { padding: 150px 0; }

/* Full-bleed art section. base.css already gives every <section> position:
   relative, which is what .band-bg's inset: 0 resolves against. */
.art-sec { overflow: hidden; }

.band-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  /* Overscaled because index.html parallaxes this in site.js. That script is
     not loaded here, so it simply sits still — the scale keeps the crop
     matching the landing page's. */
  transform: scale(1.15);
}

.band-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(15,23,20,0.60) 0%, rgba(15,23,20,0.86) 100%);
}

.band-scrim.soft { background: linear-gradient(180deg, rgba(15,23,20,0.35) 0%, rgba(15,23,20,0.75) 100%); }

.art-sec > .container { position: relative; z-index: 2; }

/* Softens both seams so the photograph bleeds into the flat page above and the
   footer below instead of reading as a pasted-in slab. Above the art, under
   the content. */
.art-sec::before, .art-sec::after {
  content: ''; position: absolute; left: 0; right: 0; height: 110px;
  pointer-events: none; z-index: 1;
}

.art-sec::before { top: -1px; background: linear-gradient(180deg, rgba(15,23,20,1) 0%, rgba(15,23,20,0) 100%); }

.art-sec::after { bottom: -1px; background: linear-gradient(0deg, rgba(15,23,20,1) 0%, rgba(15,23,20,0) 100%); }


.notify-card { max-width: 620px; margin: 0 auto; text-align: center; }

.notify-card p { margin: 20px auto 0; font-size: 18px; }

.notify-form {
  margin-top: 34px; display: flex; gap: 10px; align-items: stretch;
  justify-content: center; flex-wrap: wrap;
}

.notify-input {
  flex: 1 1 280px; min-width: 0; font-family: var(--sans);
  /* 16px keeps iOS from zooming the page on focus — do not lower */
  font-size: 16px; padding: 14px 20px; border-radius: 9999px;
  background: rgba(255,255,255,0.09); color: var(--ink-fg);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255,255,255,0.18); outline: none;
  transition: border-color .15s, box-shadow .15s;
}

.notify-input::placeholder { color: rgba(244,237,227,0.45); }

.notify-input:focus { border-color: var(--moss); box-shadow: 0 0 0 3px rgba(95,149,105,0.28); }

.notify-input:disabled { opacity: .55; }

/* Only after signup.js has flagged it — never scold someone mid-typing */
.notify-input.invalid { border-color: #973C50; box-shadow: 0 0 0 3px rgba(151,60,80,0.15); }

.notify-btn { flex: 0 0 auto; padding-inline: 32px; }

.notify-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }

/* Honeypot: off-screen rather than display:none, because some bots skip
   hidden inputs. Real people never see or tab into it. */
.notify-hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0; pointer-events: none;
}

.notify-msg {
  margin: 18px auto 0; min-height: 0; font-size: 15px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
}

/* Success is already conveyed by the button label — only errors need the line. */
.notify-msg.ok { display: none; }

.notify-msg.err { color: #E2879A; }

.notify-msg i { font-size: 18px; }

@media (max-width: 520px) {
  .notify-form { flex-direction: column; }
  .notify-input { flex: 0 1 auto; width: 100%; }
  .notify-btn { width: 100%; }
}

@media (max-width: 720px) {
  .notify-sec { padding: 96px 0; }
}


/* ──────────────────── ICON GLYPHS ────────────────────
   The @font-face rules are in base.css, but every .ph-*:before glyph rule
   lives in home.css, which this page does not load — so the two icons here
   are declared again rather than promoted. Only these two are needed:
   ph-arrow-right on the send button, and ph-sparkle, which chat.js writes
   into every coach message label itself.

   The fonts are SUBSETTED. A ph- class with no rule renders as a blank box. */
.ph, .ph-fill {
  font-style: normal; font-weight: normal; font-variant: normal;
  text-transform: none; line-height: 1; letter-spacing: 0;
  font-feature-settings: "liga";
  font-variant-ligatures: discretionary-ligatures;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
}

/* !important guards against browser extensions that override page fonts. */
.ph { font-family: "Phosphor" !important; }

.ph-fill { font-family: "Phosphor-Fill" !important; }

.ph.ph-arrow-right:before { content: "\e06c"; }

.ph-fill.ph-sparkle:before { content: "\e6a2"; }

/* signup.js writes this one into the status line itself. */
.ph-fill.ph-check-circle:before { content: "\e184"; }

.ph-fill.ph-shield-check:before { content: "\e40c"; }


/* ──────────────────── MOBILE ────────────────────
   Almost full bleed: the card keeps a small margin so the shadow and the lit
   edge still have somewhere to land. Full bleed would clip both and the card
   would stop reading as an object. */
@media (max-width: 640px) {
  .coach-stage {
    padding: calc(118px + env(safe-area-inset-top)) 0 64px;
  }

  .coach-stage > .container {
    padding-inline: 12px;
  }

  .coach-card {
    border-radius: 22px;
    height: min(600px, calc(100svh - 190px));
    /* Tighter and darker: less room to cast into at this size. */
    box-shadow:
      0 2px 5px rgba(0,0,0,0.45),
      0 22px 44px -18px rgba(0,0,0,0.85),
      inset 0 1px 0 rgba(244,237,227,0.07);
  }

  .coach-card-wrap::before {
    inset: -3% -5% -6%;
    filter: blur(40px);
  }

  /* The card is nearly the viewport width here, so the measure stops mattering
     and the gutters do. */
  .chat-log { padding-block: 34px 160px; padding-inline: 16px; }

  .chat:has(.chat-chips[hidden]) .chat-log { padding-bottom: 126px; }

  .chat-dock { padding-block: 26px 16px; padding-inline: 16px; }

  .chat-scrim-top { height: 40px; }

  .msg-coach { font-size: 15px; line-height: 22px; }

  .msg-user { font-size: 15px; line-height: 21px; }

  .msg-body > .msg-h { font-size: 18px; line-height: 24px; }

  .chat-chip { padding: 8px 15px; }

  .chat-form textarea {
    /* Must stay 16px: anything smaller makes iOS zoom the page on focus.
       Only the height shrinks. */
    font-size: 16px; line-height: 21px; min-height: 46px;
  }

  .chat-send { width: 42px; height: 42px; }

  /* The container drops to a 12px gutter so the CARD can be near-full-bleed.
     Text at that gutter reads as if it is falling off the screen, so the intro
     buys its own margin back. */
  .coach-intro { margin-bottom: 52px; padding-inline: 12px; }

  .chat-note { padding: 14px 14px; margin-top: 18px; }

  .coach-intro h1 { font-size: 39px; letter-spacing: -0.03em; }

  .coach-lede { font-size: 16px; margin-top: 30px; line-height: 1.65; }
}
