/* Pulse Studio — front-door styles. TEAM-OWNED (see CLAUDE.md).
   Loaded ONLY by app/index.html; product pages never load this file, so
   nothing here can restyle a product. Every selector is scoped under
   body.home for the same reason in reverse — if a product page ever loads
   it by mistake, nothing matches.

   The two laws this file lives under:
   1. Backgrounds are black or white only — every surface sits on var(--bg).
      The four accents appear as solid control fills, borders, underlines,
      and low-opacity decorative glows over that ground — never as a tinted
      surface fill. (The glows are a front-door reading of the law that
      CLAUDE.md does not spell out; it is flagged on the PR for the team.
      If the team says no, delete the ::before/::after glow blocks below
      and nothing else changes.)
   2. Every product's section, button, and marker carries its developer's
      color via the same .product-a|b|c|d scoping the products use.
      The four accents together are the whole palette — no fifth color. */

body.home { overflow-x: hidden; }

/* ---------- top bar ---------- */

.home .topnav {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 14px 24px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.home .brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--fg);
  text-decoration: none;
  margin-right: auto;
}
.home .brand svg { display: block; }
.home .topnav .nav-links {
  display: flex;
  gap: 4px;
}
.home .topnav .nav-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.95rem;
  padding: 8px 12px;
  border-radius: 8px;
}
.home .topnav .nav-links a:hover,
.home .topnav .nav-links a:focus-visible { color: var(--fg); text-decoration: underline; text-underline-offset: 4px; }

/* ---------- hero ---------- */

.home .hero {
  position: relative;
  max-width: 960px;
  margin: 0 auto;
  padding: 88px 24px 40px;
  text-align: left;
}
/* the four glows — light, decorative, on top of the black/white ground.
   They bleed well past the hero box so their tails fade to nothing before
   any container edge can print a seam. */
.home .hero::before,
.home .hero::after {
  content: "";
  position: absolute;
  inset: -160px -260px;
  pointer-events: none;
  background:
    radial-gradient(30% 34% at 18% 22%, color-mix(in srgb, var(--kerrian) 14%, transparent), transparent 62%),
    radial-gradient(26% 30% at 82% 18%, color-mix(in srgb, var(--manny) 13%, transparent), transparent 62%);
}
.home .hero::after {
  background:
    radial-gradient(28% 32% at 20% 82%, color-mix(in srgb, var(--dennis) 12%, transparent), transparent 62%),
    radial-gradient(30% 36% at 80% 80%, color-mix(in srgb, var(--rensley) 15%, transparent), transparent 62%);
}
.home .hero > * { position: relative; z-index: 1; }

/* The shared .eyebrow carries the voice (theme.css); this only spaces it. */
.home .eyebrow { margin: 0 0 16px; }
.home .hero h1 {
  margin: 0 0 22px;
  /* Big, and tight enough that the four promises stack like a wall of
     text in a studio rather than four separate sentences. */
  font-size: clamp(1.9rem, 5.5vw, 4rem);
  /* Anton has a tall x-height and almost no descender, so a 1.0 leading
     that suits most faces makes its lines touch — and the colour bar under
     one promise lands on the cap of the next. This is the room it needs. */
  line-height: 1.16;
  max-width: none;
}
/* each clause is underlined in its builder's color — the text itself stays
   var(--fg) so it reads on both black and white */
.home .hero h1 .clause {
  /* Own line, but only as wide as its own words — so each color bar
     belongs to its promise instead of running off across the page. */
  display: block;
  width: fit-content;
  background-image: linear-gradient(var(--clause), var(--clause));
  background-repeat: no-repeat;
  background-size: max(100%, 0px) 0.1em;
  background-position: 0 96%;
}
.home .hero h1 .clause-a { --clause: var(--kerrian); }
.home .hero h1 .clause-b { --clause: var(--manny); }
.home .hero h1 .clause-c { --clause: var(--dennis); }
.home .hero h1 .clause-d { --clause: var(--rensley); }

.home .hero .lede {
  margin: 0 0 30px;
  max-width: 56ch;
  font-size: 1.12rem;
  color: var(--muted);
}
.home .cta-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
/* CTA buttons are large text (>=18.66px bold) so white ink on the blue and
   violet accents clears the WCAG large-text contrast threshold */
.home .btn-lg { padding: 15px 30px; font-size: 1.15rem; font-weight: 900; letter-spacing: 0.05em; border-radius: 10px; text-decoration: none; display: inline-block; }
.home .btn-ghost-lg {
  display: inline-block;
  padding: 15px 30px;
  font-family: var(--font-display);
  font-size: 1.15rem;
  border-radius: 10px;
  border: 2px solid var(--line);
  color: var(--fg);
  text-decoration: none;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.home .btn-ghost-lg:hover, .home .btn-ghost-lg:focus-visible { border-color: var(--fg); }

/* the pulse line — one stroke through all four colors */
/* Tucked closer under the photo (was 46px): the line reads as the photo's
   heartbeat, and the hero stops 20px sooner. */
.home .pulse-art { margin: 26px auto 0; display: block; width: 100%; max-width: 960px; height: auto; }

/* ---------- truth strip ---------- */

.home .truths {
  max-width: 960px;
  margin: 26px auto 0;
  padding: 0 24px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.home .truths > div {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px 16px;
}
.home .truths strong { display: block; font-family: var(--font-display); font-size: 0.98rem; font-weight: 800; letter-spacing: 0.01em; text-transform: uppercase; margin-bottom: 6px; }
.home .truths span { color: var(--muted); font-size: 0.88rem; }

/* ---------- product sections ---------- */

.home .products-head { max-width: 960px; margin: 68px auto 0; padding: 0 24px; scroll-margin-top: 84px; }
.home .products-head h2 { font-size: clamp(1.6rem, 3.4vw, 2.4rem); margin: 0 0 10px; }
.home .products-head p { color: var(--muted); max-width: 60ch; margin: 0; }

.home .home-product {
  position: relative;
  max-width: 960px;
  margin: 34px auto 0;
  padding: 34px 24px;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 40px;
  align-items: center;
  scroll-margin-top: 84px;
}
.home .home-product.flip { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); }
.home .home-product.flip .home-copy { order: 2; }
.home .home-product.flip .home-panel { order: 1; }

.home .home-product::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(52% 60% at 72% 50%, color-mix(in srgb, var(--accent) 10%, transparent), transparent 72%);
}
.home .home-product.flip::before {
  background: radial-gradient(52% 60% at 28% 50%, color-mix(in srgb, var(--accent) 10%, transparent), transparent 72%);
}
.home .home-product > * { position: relative; }

.home .chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--line));
  border-radius: 999px;
  padding: 5px 14px 5px 8px;
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg);
  margin-bottom: 16px;
}
.home .chip::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
}
.home .home-product h3 { margin: 0 0 12px; font-size: clamp(1.45rem, 2.9vw, 2rem); }
.home .home-product .lede { color: var(--muted); margin: 0 0 18px; max-width: 52ch; }
.home .feature-list { list-style: none; margin: 0 0 22px; padding: 0; }
.home .feature-list li {
  position: relative;
  padding: 5px 0 5px 26px;
  color: var(--muted);
}
.home .feature-list li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 0.85em;
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--accent);
}

/* the panel: an abstract picture of the product drawn from its accent plus
   the neutrals — shapes only, no words, no fictional people */
.home .home-panel {
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 22px;
  background: var(--bg);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 24%, transparent),
              0 18px 50px -18px color-mix(in srgb, var(--accent) 38%, transparent);
}

/* A — a week of classes, some spots reserved */
.home .panel-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; }
.home .panel-week i {
  display: block;
  height: 22px;
  border-radius: 6px;
  border: 1px solid var(--line);
}
.home .panel-week i.on { background: var(--accent); border-color: var(--accent); }
.home .panel-week i.half { border: 2px solid var(--accent); }

/* B — capacity meters */
.home .panel-meters { display: grid; gap: 12px; }
.home .panel-meters i { display: block; height: 14px; border-radius: 999px; border: 1px solid var(--line); overflow: hidden; position: relative; }
.home .panel-meters i::after { content: ""; position: absolute; inset: 0; width: var(--w); border-radius: 999px; background: var(--accent); }

/* C — a conversation */
.home .panel-chat { display: grid; gap: 10px; }
.home .panel-chat i { display: block; height: 30px; border-radius: 12px; border: 1px solid var(--line); width: 62%; }
.home .panel-chat i.reply { width: 74%; justify-self: end; border: 2px solid var(--accent); }

/* D — attendance fading out, then flagged */
.home .panel-quiet { display: grid; gap: 12px; }
.home .panel-quiet .beats { display: flex; gap: 7px; align-items: center; }
.home .panel-quiet .beats i { width: 14px; height: 14px; border-radius: 50%; background: var(--accent); }
.home .panel-quiet .beats i.fade1 { opacity: 0.55; }
.home .panel-quiet .beats i.fade2 { opacity: 0.3; }
.home .panel-quiet .beats i.off { background: transparent; border: 1px dashed var(--line); }
.home .panel-quiet .flagline { height: 14px; border-radius: 999px; border: 1px solid var(--line); position: relative; overflow: hidden; }
.home .panel-quiet .flagline::after { content: ""; position: absolute; inset: 0; width: 34%; border-radius: 999px; background: var(--accent); }

/* ---------- how it holds together ---------- */

.home .vocab {
  max-width: 960px;
  margin: 64px auto 0;
  padding: 34px 24px;
  border-top: 1px solid var(--line);
}
.home .vocab h2 { font-size: clamp(1.5rem, 3vw, 2.1rem); margin: 0 0 10px; }
.home .vocab p { color: var(--muted); max-width: 64ch; }
.home .builders { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 22px; }
.home .builders a {
  display: block;
  border: 1px solid var(--line);
  border-top: 4px solid var(--accent);
  border-radius: 12px;
  padding: 14px 16px;
  color: var(--fg);
  text-decoration: none;
}
.home .builders a:hover, .home .builders a:focus-visible {
  border-color: color-mix(in srgb, var(--accent) 60%, var(--line));
  border-top-color: var(--accent);
}
.home .builders strong { display: block; margin-bottom: 2px; }
.home .builders span { color: var(--muted); font-size: 0.88rem; }

/* ---------- footer ----------
   Deleted 2026-08-23, and the deletion is the point: `.home footer` beat
   `.site-footer` on specificity, so leaving these rules here would have
   let the front door quietly restyle the shared footer for itself — the
   exact drift scripts/check-styles.mjs was written to stop, one level up
   from where it looks. The footer for every page, this one included, is
   shared/theme.css. */

/* ---------- responsive ---------- */

@media (max-width: 860px) {
  .home .home-product, .home .home-product.flip { grid-template-columns: 1fr; gap: 24px; }
  .home .home-product.flip .home-copy { order: 1; }
  .home .home-product.flip .home-panel { order: 2; }
  .home .truths { grid-template-columns: repeat(2, 1fr); }
  .home .builders { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 700px) {
  /* THE FRONT DOOR'S HEADER IS THE ONE THAT DOES NOT WRAP.
     `.page-head` has wrapped since its own 860px rule and `.topbar` since
     its owner's 800px one; this bar was flex with nowrap and simply ran off
     the side. Measured at 375px on 2026-08-23: 392px of content in a 371px
     viewport, with the light/dark switch the part hanging over the edge —
     which is the control a person on a phone most wants to reach.
     It got worse when settings left the header (one 42px button became
     two), and it was already over by 21px before that. */
  .home .topnav { flex-wrap: wrap; gap: 10px 14px; }
  .home .topnav .nav-links { display: none; }
  .home .hero { padding-top: 56px; }
}
@media (max-width: 480px) {
  .home .truths { grid-template-columns: 1fr; }
  .home .builders { grid-template-columns: 1fr; }
}

/* ---------- motion: the pictures are alive ----------
   Every animation sits behind prefers-reduced-motion: no-preference — anyone
   who prefers stillness gets the finished, static picture, which is why the
   hero's runner overlay is invisible by default and only ever shown by the
   animation. Motion recolors only within each product's accent and the
   neutrals: solid fills, borders, and opacity. No tinted surfaces, no fifth
   color, backgrounds untouched. */

.home .pulse-art .runner { opacity: 0; }

@media (prefers-reduced-motion: no-preference) {

  /* the hero line draws itself once, settles dim — and then the pulse never
     stops: the full-brightness beat sweeps the whole line on a loop, like a
     monitor that stays on. The numbers are the path's MEASURED length
     (getTotalLength() = 1279, read in the browser, not guessed): the first
     version tuned the sweep to a guessed 1600, so part of every cycle swept
     past the end of the line and the beat was the same gradient at nearly
     the same width — invisible. Dimming the settled trace is what makes the
     full-brightness beat readable in both themes. Anyone who prefers
     stillness sees the finished full-brightness line and no dimming at all:
     every rule here lives inside this motion block. */
  .home .pulse-art .trace {
    stroke-dasharray: 1279;
    stroke-dashoffset: 1279;
    animation:
      home-pulse-draw 2.4s ease-out forwards,
      home-pulse-settle 0.9s linear 2.5s forwards;
  }
  @keyframes home-pulse-draw { to { stroke-dashoffset: 0; } }
  @keyframes home-pulse-settle { to { opacity: 0.34; } }
  .home .pulse-art .runner {
    stroke-dasharray: 80 1199; /* one 80px beat per 1279px period */
    stroke-dashoffset: 1359;   /* the beat starts just before the line begins */
    animation: home-pulse-run 3.6s linear 2.9s infinite;
  }
  @keyframes home-pulse-run {
    0%   { stroke-dashoffset: 1359; opacity: 0; }
    5%   { opacity: 1; }
    92%  { opacity: 1; }
    100% { stroke-dashoffset: 0; opacity: 0; }
  }

  /* A — the week is being booked: reserved spots pulse with activity and
     the outlined cells fill as a booking lands, then free up again */
  .home .panel-week i.on { animation: week-pulse 3.6s ease-in-out infinite; }
  .home .panel-week i.on:nth-child(3n)   { animation-delay: 0.6s; }
  .home .panel-week i.on:nth-child(3n+1) { animation-delay: 1.4s; }
  .home .panel-week i.on:nth-child(4n)   { animation-delay: 2.2s; }
  @keyframes week-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.55; }
  }
  .home .panel-week i.half { animation: week-book 7.2s ease-in-out infinite; }
  .home .panel-week i.half:nth-child(2n) { animation-delay: 3.6s; }
  @keyframes week-book {
    0%, 45%   { background: transparent; }
    55%, 88%  { background: var(--accent); }
    100%      { background: transparent; }
  }

  /* B — capacity moving as members book: each meter breathes toward full
     at its own pace */
  .home .panel-meters i::after { animation: meter-fill 5.6s ease-in-out infinite alternate both; }
  .home .panel-meters i:nth-child(1)::after { animation-duration: 4.8s; }
  .home .panel-meters i:nth-child(2)::after { animation-duration: 6.4s; animation-delay: 0.6s; }
  .home .panel-meters i:nth-child(3)::after { animation-duration: 5.2s; animation-delay: 1.1s; }
  .home .panel-meters i:nth-child(4)::after { animation-duration: 7s;   animation-delay: 0.3s; }
  @keyframes meter-fill {
    from { width: calc(var(--w) * 0.45); }
    to   { width: var(--w); }
  }

  /* C — the conversation plays out: question, answer, question, answer,
     each bubble arriving, holding, and making room */
  .home .panel-chat i { animation: chat-bubble 8s ease infinite both; }
  .home .panel-chat i:nth-child(1) { animation-delay: 0s; }
  .home .panel-chat i:nth-child(2) { animation-delay: 1.1s; }
  .home .panel-chat i:nth-child(3) { animation-delay: 2.2s; }
  .home .panel-chat i:nth-child(4) { animation-delay: 3.3s; }
  @keyframes chat-bubble {
    0%       { opacity: 0; transform: translateY(8px); }
    6%, 52%  { opacity: 1; transform: translateY(0); }
    58%, 100%{ opacity: 0; transform: translateY(0); }
  }

  /* D — the whole story on a loop: attendance fades to nothing, the note
     goes out (the line fills), and the empty visits come back solid —
     we got them back */
  .home .panel-quiet .flagline::after { animation: d-note 10s ease-in-out infinite; }
  @keyframes d-note {
    0%, 28%  { width: 0; }
    38%, 92% { width: 34%; }
    100%     { width: 0; }
  }
  .home .panel-quiet .beats i.off { animation: d-return 10s ease-in-out infinite; }
  .home .panel-quiet .beats i.off:nth-child(7) { animation-delay: 0.5s; }
  .home .panel-quiet .beats i.off:nth-child(8) { animation-delay: 1s; }
  @keyframes d-return {
    0%, 52%   { background: transparent; border-color: var(--line); }
    58%, 88%  { background: var(--accent); border-color: var(--accent); }
    96%, 100% { background: transparent; border-color: var(--line); }
  }
}

/* ---------- the audience law on this page ---------- */

/* the member greeting under the lede — filled by home.ts, empty when
   nobody (or staff) is signed in */
.home .member-hello { margin: -16px 0 22px; font-weight: 600; color: var(--fg); min-height: 0; }
.home .member-hello:empty { display: none; }

/* the staff door: plainly named, never hidden — the session only changes
   the words (home.ts) and the emphasis below */
.home .staff-head { margin-top: 84px; }
.home .staff-head .staff-note { color: var(--muted); max-width: 60ch; margin: 0; }
body[data-view="staff"] .staff-note { color: var(--fg); font-weight: 600; }
/* The one door. Shown only while the staff cards are folded — when they are
   open, each card is its own door and a third would be the clutter this
   exists to remove. */
/* `hidden` LOSES TO A DISPLAY RULE. The attribute is a UA stylesheet
   `display: none`, and `.home .home-product { display: grid }` is more
   specific, so a card with hidden="" was marked hidden and drawn anyway —
   941px of staff dashboard, on a page that had just folded it. Measured in
   a browser, not reasoned about. This rule outranks the card's own. */
.home .home-product[hidden] { display: none; }
.home .staff-door { display: none; margin: 14px 0 0; }
.home .staff-head[data-folded="true"] .staff-door { display: block; }
.home .staff-door a { color: var(--fg); font-weight: 600; }

/* ---------- photography on the front door ---------- */

/* The hero's room: wide and short, so the headline still leads and the
   photograph confirms it rather than competing. */
.home .hero-photo {
  margin: 30px 0 0;
  /* A touch wider than the file's 1600x660 (so slightly shorter): the img
     cover-crops a sliver from top and bottom of a photo that is pure
     atmosphere — measured, this returns ~56px of the hero's height and
     keeps everything above the fold at 1280x800. */
  aspect-ratio: 1600 / 560;
}
.home .hero-photo img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 700px) { .home .hero-photo { aspect-ratio: 16 / 10; } }

/* A section's photograph sits above its abstract panel: the real room
   first, then the shape that explains what the product does with it. */
.home .section-photo {
  margin: 0 0 14px;
  aspect-ratio: 3 / 2;
}
.home .home-panel { display: block; }


/* ---------- scroll reveal (the Pudding touch) ----------
   Sections below the fold ease up 14px as they enter. The .reveal class is
   added ONLY by home.js after checking prefers-reduced-motion — with JS off
   or motion reduced, nothing is ever hidden, because a page that needs a
   script to become visible is a page that can fail closed. */
.home .reveal-ready :is(.home-product, .products-head, .truths) {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.55s ease, transform 0.55s ease;
}
.home .reveal-ready :is(.home-product, .products-head, .truths).revealed {
  opacity: 1;
  transform: none;
}
