
/* ==========================================================================
   GET STARTED — homepage band, replaces the "How PULSAR works" flip cards.
   Sits after Why PULSAR, before the footer CTA.

   THE JOB

   The architecture band earlier on the page ("PULSAR turns the data your
   system already produces into structured system knowledge") shows the
   thing as a STATIC OBJECT: data outside the boundary at the bottom, the
   engine, the modules on top. This band shows the SAME OBJECT AS A SEQUENCE
   — what you do, in what order, to end up with it. Nothing new is claimed
   here. It is the diagram, walked.

   That is why the tier labels above the steps are the diagram's own words,
   verbatim: PULSAR ENGINE over steps 2 and 3, PULSAR MODULES over step 4. A
   reader who scrolled past the diagram does not have to be told the two are
   related; the same words in the same left-to-right order does the work that
   a sentence of explanation would do worse.

   STEP 1 IS LEFT UNLABELLED. A "YOUR DATA" bracket over it was three words
   spent saying what "Ingest your data" already says, and worse, it implied a
   symmetry that is not there: the other two brackets name parts of PULSAR,
   which is the thing being sold. Leaving the column bare also lets the two
   teal brackets read as one continuous object — the platform — beginning
   after the step the customer performs.

   THE MISSING STEP

   The flip-card section had three steps: topology, behaviour, agents. It
   opened mid-story — "Upload your runtime records" was a subordinate clause
   inside step 1. Ingest is not a detail of mapping the topology; it is the
   only step the CUSTOMER performs, and the only one with an objection
   attached to it ("our data is in a format nobody supports"). It gets its
   own step, first, and answers the objection in its subhead.

   Steps 2 and 3 are therefore bracketed together under PULSAR ENGINE — they
   are one purchase, not two, and grouping them is what stops the section
   reading as "four things you must do".

   WHY THE CAUSELY PATTERN (tab strip + one panel)

   Four steps shown at once is four columns of text, which is the overloaded
   screen the brief rules out. Causely's answer, adopted in variant A: the
   four steps are always visible AS A STRIP — so the reader sees the whole
   shape and where they are in it — but only ONE step's content is on screen.
   The strip is the map; the panel is the page.

   THE RULES

   1. ONE HEADLINE, ONE LINE OF BODY, ONE LINK PER STEP. No step gets a
      paragraph. If a step needs a paragraph it belongs on the platform page.
   2. THE VISUAL CARRIES THE MECHANISM, THE TEXT CARRIES THE CLAIM. Never
      both. The topology step does not describe a graph; it shows one. The
      four canvases are the homepage flip cards' own animations, ported
      whole — see the head of /dev/home-get-started.js.

   2b. THE ANALOGY IS A LINE, NOT A CARD FACE. The flip backs carried a city
      metaphor worth keeping; it now runs as one italic line per step, set
      off by a teal hairline. Four steps, one city, no interaction needed.
   3. ACCENT IS TEAL AND IS SPENT ON ONE PHRASE PER HEADLINE — the phrase
      that is the actual news, not the whole second line.
   4. THE ENGINE STEPS ARE THINGS PULSAR DOES; STEPS 1 AND 4 ARE THINGS YOU
      DO. The headline voice switches accordingly ("Send us…" / "PULSAR
      maps…" / "…" / "Point a module…"), which is a quieter way of saying
      "you only do the first step" than a sentence claiming it.

   THREE VARIANTS BELOW — A is the chosen one; B and C are kept for reference.

   DEV AID: append #still to the URL to freeze variant A on one step instead
   of letting it auto-advance; #still:2 freezes it on the third step.
   ========================================================================== */



/* ── shared shell ───────────────────────────────────────────────────── */
.gs {
  /* One number governs both how long a step holds and how fast the tab's
     progress hairline fills. It is mirrored by DWELL in the JS; change both. */
  --gs-dwell: 14s;
  --gs-line: rgba(255,255,255,.13);
  --gs-line-soft: rgba(255,255,255,.07);
  padding: clamp(72px, 9vw, 128px) 24px clamp(88px, 10vw, 148px);
  /* THE SEAM WITH THE FOOTER. Every other page on this site hands the footer a
     LIGHT band, so the footer's own 1px hairline has always been enough of a
     break. This one hands it a dark band five values away from the footer's
     own top colour, and unaided the footer does not arrive — it just
     continues. Rather than lighten the band (which would cost the canvases
     their contrast), the band DARKENS as it ends, below the footer's top
     tone, so the footer reads as a step UP out of it. The eye is already
     travelling down by the time it reaches the edge, and the edge itself is
     then drawn at a weight that survives on night. */
  background: linear-gradient(to bottom,
    var(--surface-night) 0%, var(--surface-night) 58%, #0a1120 100%);
}
.gs + .site-footer { border-top-color: rgba(255, 255, 255, 0.16); }
.gs__inner { max-width: 1180px; margin: 0 auto; }

.gs__eyebrow {
  font: 500 11px/1 var(--mono); letter-spacing: .18em; text-transform: uppercase;
  color: var(--teal); margin: 0 0 20px;
}
.gs__title {
  font: 500 clamp(30px, 4vw, 50px)/1.12 var(--font);
  letter-spacing: -.02em; margin: 0 0 14px; max-width: 30ch;
}
/* The break before "and" is set, not left to the measure: the headline is a
   claim and a condition on it, and the condition has to start its own line
   for the pause to land. Making the first half a block does that at every
   width, where a <br> would only be right at one. */
.gs__title-a { display: block; }
.gs__title em { font-style: normal; color: var(--teal); }
.gs__sub {
  font: 400 clamp(15px, 1.3vw, 17px)/1.55 var(--font);
  color: rgba(244,245,247,.62); margin: 0 0 28px; max-width: 52ch;
}
/* The two sentences are a matched pair — same verb, same shape — and the pair
   only reads as one if they start at the same x. Left to the measure the line
   breaks mid-second-sentence and the rhyme is lost, so the break is set, the
   same way the headline's is. */
.gs__sub-a { display: block; }
.gs__actions { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: clamp(30px, 3.6vw, 46px); }

/* ── the tier bracket + tab strip (variant A) ───────────────────────── */
.gs__tiers {
  display: grid; grid-template-columns: 1fr 2fr 1fr; gap: 0;
  margin-bottom: 10px;
}
.gs__tier {
  font: 500 10px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: rgba(244,245,247,.42); padding: 0 0 8px; position: relative; text-align: center;
}
/* A BRACKET IS LIT ONLY WHILE THE STEP UNDER IT IS RUNNING. Teal on this page
   means "this is the part you are looking at" — it is what the active tab
   uses. A permanently teal PULSAR ENGINE label spent that meaning on a label
   that was not describing the current step, so during step 1 the eye was
   pulled to a heading about something two steps away. Both brackets now sit
   in the muted grey until their own step is selected. */
.gs__tiers[data-on="engine"] .gs__tier--engine,
.gs__tiers[data-on="modules"] .gs__tier--modules,
.gs__tiers[data-on="all"] .gs__tier { color: var(--teal); }
/* the bracket: a hairline under the label, ticked down at both ends */
.gs__tier::after {
  content: ""; position: absolute; left: 6px; right: 6px; bottom: 0; height: 6px;
  border: 1px solid var(--gs-line); border-bottom: 0; border-radius: 3px 3px 0 0;
}
.gs__tiers[data-on="engine"] .gs__tier--engine::after,
.gs__tiers[data-on="modules"] .gs__tier--modules::after,
.gs__tiers[data-on="all"] .gs__tier::after { border-color: rgba(78,205,196,.42); }
.gs__tier, .gs__tier::after { transition: color .3s ease, border-color .3s ease; }

.gs__strip {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--gs-line); border-radius: 10px;
  overflow: hidden;
}
.gs__tab {
  display: flex; align-items: center; gap: 12px;
  padding: 21px 22px; background-color: transparent; border: 0; border-right: 1px solid var(--gs-line);
  color: rgba(244,245,247,.6); font: 400 clamp(14px, 1.12vw, 15.5px)/1.3 var(--font); text-align: left;
  cursor: pointer; transition: background-color .25s ease, color .25s ease;
}
.gs__tab:last-child { border-right: 0; }
.gs__tab:hover { color: #f4f5f7; background-color: rgba(255,255,255,.03); }
.gs__tab[aria-selected="true"] { color: #f4f5f7; background-color: rgba(78,205,196,.09); }
.gs__tabnum {
  flex: none; width: 22px; height: 22px; display: grid; place-items: center;
  border: 1px solid var(--gs-line); border-radius: 4px;
  font: 500 11px/1 var(--mono); color: rgba(244,245,247,.55);
}
.gs__tab[aria-selected="true"] .gs__tabnum {
  border-color: var(--teal); color: var(--teal);
}
/* the progress hairline that fills while a step is on screen */
.gs__tab { position: relative; }
.gs__tab::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: var(--teal); transform: scaleX(0); transform-origin: left;
}
/* The bar fills only once the section has been scrolled to. .is-running is
   added by js/blocks/home-get-started.js on first intersection; without it
   the bar sat filling while the reader was still three sections above. */
.gs.is-running .gs__tab[aria-selected="true"]::after { animation: gsfill var(--gs-dwell) linear forwards; }
@keyframes gsfill { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ── the panel ──────────────────────────────────────────────────────── */
.gs__panel {
  display: grid; grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(32px, 4.4vw, 64px); align-items: center;
  padding: clamp(44px, 5.6vw, 76px) 0 0;
}
.gs__panel[hidden] { display: none; }
/* The stage is locked to its tallest step (see lockHeight() in the script).
   The slack that buys the shorter steps is given to the VISUAL, not to
   whitespace: the panel fills the stage and the canvas stretches to whatever
   height is left beside the copy. A centred panel in a locked stage read as a
   gap under the tab strip; a taller canvas reads as the point of the section. */
.gs__stage { display: flex; flex-direction: column; }
.gs__stage > .gs__panel { flex: 1 1 auto; }
/* The diagram step is the one panel that is not a two-column split: copy
   above, diagram across the full band. See the rationale at the head of
   the step-4 block in /dev/home-get-started.js. */
.gs__panel--wide { display: block; }
.gs__panel--wide .gs__copy { max-width: 62ch; margin-bottom: clamp(26px, 3.4vw, 40px); }
.gs__panel--wide .gs__h { max-width: 22ch; }
.gs__panel--wide .gs__body { max-width: 56ch; }
.gs__copy { animation: gsin .5s cubic-bezier(.2,.7,.3,1) both; }
@keyframes gsin { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.gs__h {
  font: 500 clamp(27px, 3.35vw, 44px)/1.14 var(--font);
  letter-spacing: -.02em; margin: 0 0 14px;
}
.gs__h em { font-style: normal; color: var(--teal); }
.gs__body {
  font: 400 clamp(15.5px, 1.35vw, 17.5px)/1.6 var(--font);
  color: rgba(244,245,247,.68); margin: 0 0 20px; max-width: 40ch;
}
/* SCOPE, LIFTED OUT OF THE PARAGRAPH. "A full vehicle, one domain, or a single
   component" is the one clause in step 1 that decides whether a supplier keeps
   reading: it says the product does not require you to own a whole car. At the
   paragraph's own weight it reads as a list of examples; at full strength it
   reads as an answer. Brighter rather than coloured — teal is the panel's
   accent for headings, and a second teal here would compete with .gs__h em. */
.gs__body b { font-weight: 600; color: rgba(244,245,247,.95); }
/* THE ANALOGY. The deck's folded-map glyph and the deck's sentence, laid out
   the deck's way: icon left, one line right. The glyph replaces the label a
   line like this would otherwise need — it says "this is an aside about a
   city" in a mark, where the words "THE ANALOGY" would be a fifth thing to
   read on a panel meant to hold four. Not italic: the icon already sets the
   line apart, and italic on top of it was two devices doing one job. */
.gs__analogy {
  display: flex; gap: 11px; align-items: flex-start;
  font: 400 clamp(14px, 1.2vw, 15.5px)/1.6 var(--font);
  color: rgba(244,245,247,.5); margin: 0 0 24px; max-width: 42ch;
}
.gs__analogy-icon {
  flex: none; width: 22px; height: 18px; margin-top: 3px;
  color: rgba(78,205,196,.7);
}
.gs__link {
  font: 500 clamp(14px, 1.15vw, 15.5px)/1 var(--font); color: var(--teal); text-decoration: none;
  display: inline-flex; gap: 7px; align-items: center;
}
.gs__link:hover { text-decoration: underline; text-underline-offset: 4px; }

.gs__vis {
  /* No aspect-ratio and no tall floor: the visual takes whatever height the
     stage has left, so steps 1-3 come out exactly as deep as step 4 rather
     than setting a new, taller maximum of their own. The floor only matters
     once the panel stacks on narrow screens. */
  align-self: stretch; min-height: 240px;
  border: 1px solid var(--gs-line-soft);
  border-radius: 12px; background:
    radial-gradient(120% 90% at 50% 0%, rgba(78,205,196,.07), transparent 62%),
    rgba(255,255,255,.02);
  overflow: hidden;
}
.gs__vis canvas { width: 100%; height: 100%; display: block; }

/* ── STEP 4: the architecture diagram's top half, on a dark ground ─────
   Ported from dev/home-platform-vision.html — .pv__actors, .pv__wire--straight
   and the module row — with two changes and no others, so it still reads as
   the same diagram the reader met earlier on the page:

     a. DARK, not light. The light band's ink/soft/wire values become the
        band--dark ones; the teal node colour is unchanged, which is what
        keeps the wires recognisably the same wires.
     b. NO ENGINE BOX AND NO INPUT TIER. Those are steps 1 to 3. This panel is
        only the part of the diagram the last step is about: what comes OUT of
        the platform, and who it goes to.

   Flow is upward, as in the original: every arrowhead points at the person
   where the answer arrives, never at the module that produced it. */
/* The diagram panel is taller than the canvas ones: five columns of role,
   question and module need the height, and letterboxing it to 16:10 would
   shrink the type below reading size. */
.gs__vis--dia { display: grid; place-items: center; padding: clamp(22px, 3vw, 36px); aspect-ratio: auto; }
.gsr { width: 100%; --g: clamp(6px, 1.1vw, 12px); }
.gsr__row {
  display: grid; gap: var(--g);
  grid-template-columns: repeat(var(--n), minmax(0, 1fr));
}
/* The people are the QUIETEST tier here too. They are who the answers are
   for, not the subject; the subject is what the platform hands them. */
/* min-height keeps the five columns the same depth however many lines a
   question takes, so every wire starts on the same line. */
.gsr__actor {
  display: flex; flex-direction: column; align-items: center; gap: 6px; margin: 0;
  text-align: center; min-height: 6.2em;
  animation: gsrise .5s ease both; animation-delay: var(--d);
}
.gsr__actor b {
  font: 600 clamp(11.5px, 1vw, 13.5px)/1.3 var(--font); color: rgba(244,245,247,.78);
}
/* The question is the loudest thing a person says and the quietest thing on
   the panel — set smaller than the name it belongs to, because the reader
   should find the role first and only then what that role asks. */
.gsr__ask {
  font: 400 clamp(11px, .92vw, 12.5px)/1.45 var(--font);
  color: rgba(244,245,247,.52); max-width: 21ch;
}
.gsr__who { flex: none; width: 15px; height: 16px; fill: rgba(244,245,247,.42); }

/* The arrowheads sit ON the wire's top edge, not above it: the role labels
   run to two lines at this width, and a head hung over the wire lands in
   their descenders. */
.gsr__wire {
  position: relative; display: grid; gap: var(--g);
  grid-template-columns: repeat(var(--n), minmax(0, 1fr));
  height: clamp(30px, 4.4vh, 44px); margin-top: 8px; opacity: .85;
}
.gsr__cell { position: relative; animation: gsrise .5s ease both; animation-delay: var(--d); }
.gsr__cell::before {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 0;
  border-left: 1.5px dotted rgba(78,205,196,.45); transform: translateX(-50%);
}
/* arrowhead at the top of each drop — the answer arriving at the person */
.gsr__cell::after {
  content: ""; position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  width: 0; height: 0;
  border-left: 3.5px solid transparent; border-right: 3.5px solid transparent;
  border-bottom: 5px solid var(--teal);
}

.gsr__mod {
  display: grid; place-items: center; text-align: center; min-height: 3.5em;
  padding: 8px 6px; border: 1px solid rgba(78,205,196,.4); border-radius: 6px;
  background: rgba(78,205,196,.06);
  font: 600 clamp(12px, 1.05vw, 14px)/1.28 var(--font); letter-spacing: -.015em;
  color: #f4f5f7;
}
/* The dashed boundary, with its name straddling the top edge, exactly as in
   the architecture band. The modules live INSIDE it — they are the platform's
   surface, not something stacked on the platform — and the people stay
   outside, with their own data on the far side of the same line. */
.gsr__boundary {
  position: relative; margin-top: 2px;
  border: 1.5px dashed rgba(78,205,196,.42); border-radius: 14px;
  padding: clamp(22px, 3.2vw, 32px) clamp(12px, 2vw, 20px) clamp(14px, 2vw, 20px);
  background:
    radial-gradient(ellipse 74% 100% at 50% 0%, rgba(78,205,196,.13) 0%, transparent 72%),
    rgba(78,205,196,.05);
}
.gsr__nametag {
  position: absolute; top: 0; left: 50%; transform: translate(-50%, -50%); z-index: 2;
  padding: 5px 12px; border-radius: 7px;
  border: 1.5px solid rgba(78,205,196,.42); background: var(--surface-night);
  font: 600 clamp(10.5px, .9vw, 12px)/1 var(--mono); letter-spacing: .16em;
  color: var(--teal); white-space: nowrap;
}
@keyframes gsrise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

@media (max-width: 900px) {
  .gs__panel { grid-template-columns: 1fr; }
  .gs__strip { grid-template-columns: 1fr 1fr; }
  .gs__tab:nth-child(2) { border-right: 0; }
  .gs__tab:nth-child(-n+2) { border-bottom: 1px solid var(--gs-line); }
  .gs__tiers { display: none; }
  /* The roles diagram does not collapse: its whole meaning is that each team
     stands over the module that answers it, and any reflow to two columns or
     one breaks that pairing silently. It scrolls sideways instead, inside its
     own container, which is the one case the no-horizontal-scroll rule allows. */
  /* Sideways scroll only works if it announces itself. Cut flat at the frame
     edge, the diagram reads as a layout that broke mid-word rather than as a
     row that continues. The mask fades the cut edge so the content clearly
     runs past it, and the hint below says so in words for anyone who does not
     read the fade. The mask sits on the scroll container's own box, so it
     stays at the edge instead of travelling with the content. */
  .gs__vis--dia {
    overflow-x: auto; justify-items: start; padding: 22px 18px;
    scroll-padding-inline: 18px;
    -webkit-mask-image: linear-gradient(90deg, #000 0 72%, transparent 98%);
            mask-image: linear-gradient(90deg, #000 0 72%, transparent 98%);
  }
  .gsr { min-width: 700px; }

  /* --wide is step 4 and only step 4. At this width the panel is one column,
     so this lands as a row under the diagram. */
  .gs__panel--wide::after {
    content: "swipe to see all five \2192";
    justify-self: center;
    width: max-content;
    max-width: 100%;
    margin: 2px auto 0;
    font: 400 11.5px/1 var(--mono, ui-monospace, monospace);
    letter-spacing: .12em; text-transform: uppercase;
    color: rgba(244, 245, 247, .42);
  }

  @media (prefers-reduced-motion: no-preference) {
    .gs__vis--dia { scroll-behavior: smooth; }
  }
}
