/* /hub - the RIPPLES Hub download page.
   Page-scoped, so nocturne.css does not need a cache-buster bump across
   50-odd pages for a single new page. */

.hub-head { padding-bottom: clamp(18px, 3vw, 34px); border-bottom: none; }

.hub-hero {
  display: grid;
  /* The shot carries the product; the text column is short since the lede came
     out (2026-08-23, Aviv: "way too much text"). Desktop only - under 900px this
     collapses to one column below, so phones are untouched. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  gap: clamp(24px, 4vw, 56px);
  /* Top-aligned, not centred: the shot's top edge sits on the kicker's line so
     the two columns read as one composition (Aviv, 2026-09-06: "align the
     text with the picture"). Centring floated the shot against whatever
     happened to be stacked under the buttons. */
  align-items: start;
}
.hub-hero-text .kicker { margin-bottom: 10px; }
.hub-hero-text h1 {
  margin: 0 0 14px;
  /* The text column narrowed when the shot grew, and the headline started
     breaking as "Every plugin. One / app." - balance puts the break at the
     sentence instead. Ignored by older browsers, which just wrap as before. */
  text-wrap: balance;
}
/* The headline is two sentences and the second one is the accent half, so it
   has to own its own line. Balance alone could not do it once the first
   sentence grew to "Plugins, samples and books." - it left "books. One app."
   sharing a line and split the colour mid-line. Making the <em> a block puts
   the break at the full stop without a hand-written <br>, which would be wrong
   at phone widths. */
.hub-hero-text h1 em { display: block; }
.hub-hero-text .lede { max-width: 34rem; margin: 0 0 clamp(20px, 3vw, 28px); }

/* ---- the trial line ----
   Twice wrong before this. First it sat at the tail of the lede and read as a
   footnote. Then it got a bordered box with an icon — which is the visual
   language of a system warning, not an offer (Aviv: "why did you make it look
   like an error"). A lot of people are on this page BECAUSE they clicked "Try
   free for 7 days" somewhere else, so this is the thing to make appealing.

   No box, no icon, no rule. It uses the house idiom for a headline that sells:
   the display face with the payload in <em>, which nocturne.css already paints
   accent-bright. Sized between the lede and the h1 so it reads as a second
   headline rather than another paragraph, and it sits directly above the
   download buttons — read the offer, then hit Download. */

.hub-trial {
  display: flex;
  flex-direction: column;
  gap: 5px;
  max-width: 34rem;
  margin: 0 0 clamp(20px, 3vw, 28px);
}
.hub-trial-line {
  font-family: var(--display);
  font-size: clamp(1.9rem, 3.1vw, 2.7rem);
  line-height: 0.98;
  letter-spacing: 0.005em;
  color: var(--cream);
}
/* em is already accent-bright and un-italicised inside headings; this is a <p>,
   so it needs saying here too. */
/* nowrap so the offer never breaks as "free for 7 / days" - the number and its
   unit are one phrase and reading them apart costs the line its punch. */
.hub-trial-line em { font-style: normal; color: var(--accent-bright); white-space: nowrap; }
.hub-trial-sub {
  font-size: 14px;
  letter-spacing: 0.01em;
  color: var(--cream-dim);
}

/* ---- download buttons ----
   Mac and Windows are equal twins (Aviv, 2026-08-12) - same face, same
   weight, the visitor's platform merely ordered first by js/hub.js. Both
   flex to the same width so neither reads as the afterthought. */

.hub-dl { display: flex; flex-wrap: wrap; gap: 12px; max-width: 620px; }

.hub-btn {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  flex: 1 1 240px;
  padding: 14px 22px 13px;
  line-height: 1.3;
}
.hub-btn-main {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 15px;
}
.hub-btn-main svg { width: 16px; height: 16px; flex: none; }
/* The Apple mark is the real logo, inlined - lucide's `apple` is a FRUIT
   (stem and two lobes), which at 16px just reads as a broken circle. It is a
   solid glyph sitting next to stroked lucide icons, so it needs to be a shade
   smaller and lifted a hair: a filled mark carries more optical weight than an
   outline at the same box, and the logo's bitten top sits high in its viewBox.

   The colour is ALSO set as a fill attribute on the svg itself, not only
   here. An svg with no fill defaults to BLACK, so if this sheet is ever
   missing or stale - a poisoned edge cache did exactly that on 2026-08-13 -
   the mark renders black on the brick button. The attribute makes the icon
   correct with no CSS at all; this rule still owns size and position. */
.hub-btn-main .icon-apple {
  width: 15px; height: 15px;
  fill: currentColor; stroke: none;
  position: relative; top: -1px;
}
/* Facts in the body face, not mono - a sentence set in monospace reads as a
   terminal, and this is a shop front. */
.hub-btn-sub {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.82);
}

/* Waiting state: the build is not published yet, so the button must not look
   like it will do something. Kept as an <a> so the layout never shifts when a
   real href arrives. */
.hub-btn.is-waiting {
  opacity: 0.5;
  pointer-events: none;
  cursor: default;
}

/* The three objections a first-time downloader actually has. Stacked one per
   row, NOT a wrapping flex row: three items of uneven width put two on the
   first line and orphaned the third on the second, which read as a mistake.
   The fixed icon column is what makes it scan as a list - it lines up all
   three text edges no matter how wide the icon glyph is. */
.hub-trust {
  list-style: none;
  margin: 20px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.hub-trust li {
  display: grid;
  grid-template-columns: 16px 1fr;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--cream-dim);
}
/* Lucide REPLACES the <i data-lucide> with an <svg>, so an `i` selector never
   matches once the script has run - the icons were falling back to lucide's
   own 24px and overflowing the column. Target the svg. */
.hub-trust i,
.hub-trust svg { width: 16px; height: 16px; color: var(--accent-bright); opacity: .9; }

.hub-hero-shot {
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface);
  box-shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.8);
}
.hub-hero-shot img { width: 100%; height: auto; display: block; }

/* ---- steps ---- */

.hub-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 3vw, 34px);
  margin-top: clamp(18px, 3vw, 30px);
}
.hub-step h3 { margin: 12px 0 7px; }
.hub-step p { margin: 0; color: var(--cream-dim); }
.hub-step-num {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  font-family: "Bebas Neue", sans-serif;
  font-size: 1.3rem;
  color: var(--accent-bright);
}

/* ---- product shots ----
   Alternating copy/shot rows, the same rhythm as the Noodle page: the eye
   crosses the page instead of scrolling past four identical stacks. */

.hub-shots .wrap { display: flex; flex-direction: column; gap: clamp(44px, 5vw, 74px); }

.hub-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 4vw, 60px);
  align-items: center;
}
.hub-split.flip .hub-split-copy { order: 2; }

.hub-split-copy .kicker { margin-bottom: 10px; }
/* These are section headlines, so they take the site's h2 scale rather than
   the smaller h3 default - they sit next to a full-height screenshot and were
   reading as captions. Body matches .lede for the same reason. */
.hub-split-copy h3 {
  font-size: clamp(2rem, 3.8vw, 3.2rem);
  line-height: 1.1;
  margin: 0 0 18px;
  max-width: 22ch;
  text-wrap: balance;
}
.hub-split-copy p {
  margin: 0;
  color: var(--cream-dim);
  max-width: 40ch;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  line-height: 1.62;
}

/* The shots are zoomed crops of the interface, not whole windows - a whole
   window shrunk into half a column makes its own text unreadable, which is
   what these sections are trying to show. Each one bleeds past the wrap on its
   outer edge so it reads as a window onto something larger. */
.hub-split-shot { margin: 0; }

/* The splits show REGIONS of the interface at near-full scale, so they get a
   plain frame with a faint top-light - the mac titlebar (traffic lights) is
   reserved for the hero, which is the one true whole window. A titlebar on a
   crop of the middle of a window would be claiming to be something it is not. */
.shot-frame {
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface);
  box-shadow: 0 30px 64px -28px rgba(0, 0, 0, .9), inset 0 1px 0 rgba(241, 235, 222, .06);
}

/* The demos shot is the detail panel - a tall column, not a wide region. Let
   it stand at readable width instead of stretching to fill the half-column. */
.hub-split-shot.tall { display: flex; justify-content: center; }
.hub-split-shot.tall .shot-frame { max-width: min(400px, 100%); }
.shot-frame img,
.hub-split-shot img {
  width: 100%; height: auto; display: block;
  border: 0; border-radius: 0; box-shadow: none;
}
.shot-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 13px;
  background: linear-gradient(180deg, #1b1613, #14100f);
  border-bottom: 1px solid var(--line);
}
.shot-bar span {
  width: 9px; height: 9px; border-radius: 50%;
  background: #2f2723;
}

@media (min-width: 901px) {
  .hub-split { align-items: center; }
  /* copy left, shot right: bleed right. flip: shot left, bleed left. */
  .hub-split:not(.flip) .hub-split-shot { margin-right: calc(var(--pad) * -1); }
  .hub-split.flip .hub-split-shot { margin-left: calc(var(--pad) * -1); }
  .hub-split:not(.flip) .hub-split-copy { padding-right: clamp(8px, 1.5vw, 28px); }
  .hub-split.flip .hub-split-copy { padding-left: clamp(8px, 1.5vw, 28px); }
}

/* ---- at a glance ----
   The pre-download hesitation answered as facts, before the FAQ answers it as
   prose. Native Access does this as an "At a Glance" table and it reads as
   confidence. Values stay in the body face - mono is for keys, orders, prices
   and version strings, and "macOS 11 or newer" is none of those. */

.hub-specs {
  margin-top: clamp(14px, 2.5vw, 22px);
  max-width: 46rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  padding: 6px 20px;
}
.hub-spec {
  display: flex;
  gap: 18px;
  align-items: baseline;
  padding: 11px 0;
  font-size: 13.5px;
}
.hub-spec + .hub-spec { border-top: 1px solid var(--line); }
.hub-spec-k { flex: 0 0 9.5em; color: var(--cream-faint); }
.hub-spec-v { color: var(--cream-dim); }

/* ---- faq ---- */

.hub-faq { margin-top: clamp(18px, 3vw, 28px); max-width: 46rem; }
.hub-faq .win-setup { margin: 0 0 10px; }
/* One plain line replaces the "Something went wrong" accordion: a single
   sentence does not need a disclosure to hide behind. */
.hub-faq-foot { margin: 16px 0 0; font-size: 14px; color: var(--cream-dim); }
.hub-faq-foot a { color: var(--accent-bright); }

/* ---- closing download ----
   Whoever read all the way through Keys and the FAQ is convinced or gone -
   convinced deserves the button here, not a newsletter form. Same manifest
   contract as the hero: js/hub.js arms every .js-dl-primary identically. */

.hub-close-inner { text-align: center; }
.hub-close-inner .kicker.center { display: inline-block; }
.hub-close-inner h2 { margin: 0 0 clamp(20px, 3vw, 28px); }
.hub-dl-center { justify-content: center; margin-left: auto; margin-right: auto; }
.hub-close-note {
  margin: 16px 0 0;
  font-size: 12.5px;
  color: var(--cream-faint);
}

/* ---- phone ----
   Two-column grids collapse explicitly. The .pillars.cols2 bug on /sync-music
   came from assuming a grid would wrap on its own; it does not. */

@media (max-width: 900px) {
  .hub-split { grid-template-columns: 1fr; gap: 20px; }
  .hub-split.flip .hub-split-copy { order: 0; }
  .hub-hero { grid-template-columns: 1fr; }
  .hub-hero-shot { order: -1; }
  .hub-steps { grid-template-columns: 1fr; gap: 22px; }
}

@media (max-width: 560px) {
  .hub-dl { flex-direction: column; align-items: stretch; }
  /* `flex: 1 1 240px` on .hub-btn is a WIDTH basis for the desktop row. Once
     this container flips to a column, flex-basis addresses the MAIN axis =
     HEIGHT, so both buttons rendered 240px tall - a pair of orange slabs
     filling the phone. Reset the basis here; the width:100% below is what
     makes them equal twins on a phone. (Found in the mobile audit, 2026-08-19.) */
  .hub-btn { flex: 0 0 auto; }
  .shot-bar { padding: 7px 10px; }
  .shot-bar span { width: 7px; height: 7px; }
  .hub-btn { width: 100%; align-items: center; }
  .shot-frame { border-radius: 8px; }
}

/* ---- after the click (2026-08-23) ----
   The page used to go silent the moment a download started, and the numbers
   said so: 17 download clicks in 3.5 days, ~3 machines ever opened the app,
   Windows 9 -> 1. The panel appears under whichever .hub-dl was pressed and
   stays; it never replaces the buttons. One pane per platform, js/hub.js
   picks. */
.hub-after {
  margin-top: 14px;
  max-width: 620px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  padding: 14px 16px 12px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--cream-dim);
}
.hub-after-head {
  margin: 0 0 6px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--cream);
}
.hub-after-head i,
.hub-after-head svg { width: 16px; height: 16px; color: var(--accent-bright); flex: none; }
.hub-after ol { margin: 0 0 6px; padding-left: 20px; }
.hub-after li { margin: 4px 0; }
.hub-after strong { color: var(--cream); }
.hub-after-foot { margin: 6px 0 0; font-size: 12.5px; }
.hub-after a { color: var(--accent-bright); text-decoration: underline; text-underline-offset: 2px; }
/* Centred closing block: keep the panel's text left-aligned and its box
   centred, or the numbered list floats. */
.hub-dl-center + .hub-after { margin-left: auto; margin-right: auto; text-align: left; }
.hub-win-setup { max-width: 620px; }

/* Tap is a desktop app. 15 of the last 90 visitors to this page were on a
   phone and the page offered them two download buttons and nothing else. */
.hub-phone-note { display: none; margin: 14px 0 0; font-size: 13px; color: var(--cream-dim); }
.hub-phone-note strong { color: var(--cream); }
@media (max-width: 560px) {
  .hub-phone-note { display: block; }
}

/* 2026-09-03 trust pass: press lines + phone copy button */

/* ---- press quotes ----
   These shipped as a second <ul> in the same muted grey at nearly the same size
   as .hub-trust directly above, so two outside publications read as two more of
   our own bullet points - the one thing a press quote must never look like. The
   fix is separation and attribution, not decoration:

   - a hairline and a label above, so the eye knows the voice changed
   - the quote in --cream, brighter than the bullets, on the accent rule the
     house already uses for a pull quote (.pull in nocturne.css)
   - the publication on its OWN line, since the credential is the name; inline
     at the tail of the sentence it read as a stray link

   The old .testimonial idiom (from css/site.css, the pre-Nocturne stylesheet,
   deleted 2026-09-07) put its attribution in mono uppercase. Not copied:
   mono is a data font here (licence keys, prices, versions) and uppercase labels
   are the AI tell Aviv has killed three times. Inter, sentence case. */
.hub-press {
  margin: 22px 0 0;
  padding: 20px 0 0;
  border-top: 1px solid var(--line);
  max-width: 56ch;
  display: grid;
  gap: 16px;
}
.hub-press-label {
  margin: 0;
  font-size: 12px;
  letter-spacing: .01em;
  /* --cream-faint measured 3.39:1 on this background, under the 4.5:1 floor for
     text this size. --cream-dim is 8.23:1 and still reads as a quiet label,
     because the quotes below it are brighter (--cream) and larger. */
  color: var(--cream-dim);
}
.hub-press-item { margin: 0; padding: 13px 16px; background: rgba(241,235,222,.05); border-radius: 4px; }
.hub-press-item blockquote {
  margin: 0;
  font-size: .97rem;
  line-height: 1.5;
  color: var(--cream);
}
/* Real typographic quotes, added in CSS so the marks never end up inside the
   text a screen reader or a copy-paste picks up. */
.hub-press-item blockquote::before { content: "\201C"; }
.hub-press-item blockquote::after  { content: "\201D"; }
.hub-press-item figcaption { margin-top: 5px; font-size: .8rem; }
.hub-press-item figcaption a { color: var(--accent-bright); text-decoration: none; }
.hub-press-item figcaption a:hover { text-decoration: underline; }
.hub-copy-link { font: inherit; color: var(--accent-bright); background: none; border: 0; padding: 0; text-decoration: underline; cursor: pointer; }
.hub-copy-link:focus-visible { outline: 2px solid var(--accent-bright); outline-offset: 2px; }

/* ---- press row (moved out of the hero 2026-09-06) ---- */
.hub-press-row { padding-top: 0; }
.hub-press-f { border-top: 0; padding-top: 0; margin: 0; max-width: none; display: grid; grid-template-columns: 1fr 1fr; gap: 28px; }
.hub-press-f .hub-press-label { grid-column: 1 / -1; }
@media (max-width: 760px) { .hub-press-f { grid-template-columns: 1fr; } }
