/* ============================================================
   Refresh Health — platform.css
   Only what is specific to /platform/. Tokens, typography and the
   header / partner-cta / footer come from base.css + components.css.

   The product page is a walkthrough: hero, then one .pshot section per step
   of a single visit — booking, arrival, documentation, the signed record —
   each pairing copy with a framed screen of the real software.

   The Secure / Simple / Intelligent pillars this file used to serve were
   removed on 2026-08-19 on direction from the team; see the note at the head
   of src/pages/platform/index.astro. `git log -- public/assets/css/platform.css`
   still holds the pillar rules, and the outline rings, .spec-list, .ai-card
   grid and posture blocks from the page before that, if a section being
   written now wants one back.

   Everything the shots themselves need is in src/styles/ehr.css, which is
   Tailwind and is deliberately not part of this pipeline.
   ============================================================ */

/* ---------- Hero ---------- */

/* The band that continues above the document when the page is overscrolled
   (see the `html` rule in base.css) — this hero's own base colour. */
:root { --band-top: var(--haze); }

.hero {
  position: relative;
  overflow: hidden;
  background: var(--haze);
  /* Same soft-blob recipe as home/contact — two radial washes layered in
     background-image instead of separate elements, so every hero on the
     site builds its glow the same way. */
  background-image:
    radial-gradient(34% 46% at 20% 10%, var(--panel) 0%, color-mix(in srgb, var(--panel) 0%, transparent) 70%),
    radial-gradient(26% 35% at 78% 34%, var(--panel-alt) 0%, color-mix(in srgb, var(--panel-alt) 0%, transparent) 70%);
  padding-bottom: clamp(56px, 8vw, 112px);
}

.hero__inner {
  position: relative;
  z-index: 1;
  padding-top: clamp(56px, 9vw, 130px);
  text-align: center;
}

/* Shared canonical artwork, at a position/rotation the other two heroes
   haven't used — see the same convention in contact.css. Both pieces bleed
   off the side edges and pass behind the glass panel, which blurs them. */
.hero__gears,
.hero__circuit { opacity: var(--decor-ink); }

.hero__decor {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* --reveal-rest and --reveal-opacity are what the arrival lands on. Both
   pieces are rotated as drawn and both are held under full strength, and
   an entrance ending on the primitive's defaults — `transform: none`,
   `opacity: 1` — would unrotate them and print them at full ink. See the
   .reveal primitive in components.css. */
.hero__gears {
  position: absolute;
  right: -1%;
  top: 8%;
  width: clamp(120px, 15vw, 216px);
  --reveal-rest: rotate(90deg);
  --reveal-opacity: 0.85;
  transform: rotate(90deg);
  transform-origin: center;
  opacity: 0.85;
}

.hero__circuit {
  position: absolute;
  left: -4%;
  bottom: -18%;
  width: clamp(180px, 23vw, 330px);
  --reveal-rest: rotate(90deg);
  --reveal-opacity: var(--decor-ink);
  transform: rotate(90deg);
  transform-origin: center;
  opacity: 0.9;
}

@media (max-width: 599.98px) {
  .hero__decor { display: none; }
}

/* Same frosted-glass recipe as .button-bar / .site-header .logo /
   .pill-button / the home hero panel, so this bubble reads as the
   same material. */
.hero__panel {
  max-width: 960px;
  margin-inline: auto;
  padding: clamp(32px, 4.5vw, 56px) clamp(24px, 5vw, 64px);
  border-radius: var(--radius-lg);
}

.hero__title {
  font-family: var(--font-heading);
  font-size: clamp(36px, 4.4vw, 60px);
  line-height: 0.96;
  letter-spacing: 0.02em;
  color: var(--ink);
}

.hero__lead {
  max-width: 700px;
  margin: clamp(24px, 3.2vw, 44px) auto 0;
  text-align: center;
  font-size: clamp(18px, 1.6vw, 22px);
  line-height: 1.5;
}

/* ---------- The haze band ---------- */

.band {
  position: relative;
  overflow: hidden;
  background: var(--surface);
}

.band__glow {
  position: absolute;
  top: 21%;
  left: 50%;
  transform: translateX(-50%);
  width: min(826px, 57vw);
  height: min(1605px, 71vh);
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(50% 50% at 50% 50%,
    var(--glow-core) 19.23%,
    var(--glow-edge) 100%);
}

.band > .container,
.band > section {
  position: relative;
  z-index: 1;
}

.band__display { padding-top: clamp(56px, 8vw, 128px); }

/* shared heading treatment for the band sections */
.platform-heading {
  font-family: var(--font-heading);
  font-size: clamp(28px, 3.6vw, 48px);
  line-height: 1.1;
  letter-spacing: 0.03em;
  color: var(--blue-accent);
}

/* ---------- The band's lead-in ----------
   A statement, a short lead, and an index of the five steps below it. The
   index is the emphatic part: it is the only place on the page where the whole
   visit is visible at once, and it carries the same 01-05 numerals the steps
   do, so a reader meets the sequence here and recognises it on arrival.

   It borrows the page's own devices rather than introducing any: the numeral
   is .pshot__step verbatim, and the hairlines are the same 1px --line
   rule that separates one step from the next. */

.band__intro { padding-top: clamp(48px, 7vw, 104px); }

.band__title {
  max-width: 20ch;
  font-family: var(--font-heading);
  font-size: clamp(34px, 4.4vw, 56px);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: 0.01em;
  color: var(--ink);
  text-wrap: balance;
}

/* The one word the sentence turns on. Colour and slope together, on a single
   word, rather than a second type size competing with the heading. */
.band__title em {
  font-style: italic;
  color: var(--blue-accent);
}

.band__lead {
  max-width: 54ch;
  margin-top: clamp(18px, 2.2vw, 28px);
  font-size: clamp(18px, 1.6vw, 22px);
  line-height: 1.5;
}

/* ---------- The visit index ---------- */

.visit-index {
  /* Short of the 1240px column on purpose. At full width the arrow ends up
     600px from the end of the label it belongs to and reads as page furniture
     rather than as part of the row. */
  position: relative;
  max-width: 1040px;
  margin-top: clamp(32px, 4.4vw, 56px);
  padding: 0;
  list-style: none;
}

/* The six hairlines are pseudo-elements rather than borders so the index can
   be ruled on arrival, line by line, the way the page's other rules draw —
   see the reveal block at the foot of this file. Same 1px, same colour, same
   place. They sit on top of the row's own generous padding, so nothing they
   overlap is ever ink. */
.visit-index::before,
.visit-index__item::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}

.visit-index::before { top: 0; }

.visit-index__item {
  position: relative;
}

.visit-index__item::after { bottom: 0; }

/* The negative inline margin cancels the link's own padding, so the numerals
   stay flush with the heading above while the hover fill still has room to
   breathe either side of the text. */
.visit-index__link {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr) auto;
  /* First baseline, not centre: a label that wraps to two lines on a narrow
     screen would otherwise leave the numeral floating between them. */
  align-items: baseline;
  gap: var(--space-sm);
  margin-inline: calc(-1 * clamp(12px, 1.6vw, 20px));
  padding: clamp(16px, 2.1vw, 26px) clamp(12px, 1.6vw, 20px);
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: background-color var(--transition), color var(--transition);
}

/* Verbatim .pshot__step, so the numeral a reader meets here is the same object
   they meet again at the top of the step it points to. */
.visit-index__step {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--blue-accent);
}

.visit-index__label {
  font-family: var(--font-heading);
  font-size: clamp(19px, 1.9vw, 27px);
  font-weight: 400;
  line-height: 1.18;
  letter-spacing: 0.01em;
  color: var(--ink);
  text-wrap: pretty;
  transition: color var(--transition);
}

/* Visible at rest — the rows have to read as links before anyone hovers one —
   and only then does it brighten and travel. */
.visit-index__arrow {
  flex: none;
  width: clamp(20px, 1.8vw, 24px);
  height: auto;
  /* Its bottom edge is its baseline, which lands it on the cap height of the
     label's first line — level with the text on one line and on two. */
  align-self: baseline;
  color: var(--ink-muted);
  opacity: 0.7;
  transition: opacity var(--transition), transform var(--transition), color var(--transition);
}

.visit-index__link:hover,
.visit-index__link:focus-visible {
  background: var(--panel);
}

.visit-index__link:hover .visit-index__label,
.visit-index__link:focus-visible .visit-index__label {
  color: var(--blue-accent);
}

.visit-index__link:hover .visit-index__arrow,
.visit-index__link:focus-visible .visit-index__arrow {
  opacity: 1;
  color: var(--blue-accent);
  transform: translateX(4px);
}

@media (max-width: 599.98px) {
  .visit-index__link { grid-template-columns: 2.5rem minmax(0, 1fr) auto; }
}

/* ---------- Walkthrough sections ----------
   One .pshot per step. Copy in a narrow column, a framed screen of the product
   beside it, sides alternating down the page. A hairline between steps does the
   separating that a full band's worth of space otherwise would.

   The two-column split is 38/62 with a fixed 56px gap, and those three numbers
   are load-bearing: ProductShot.astro computes each screen's `zoom` from the
   column width they produce (734px at the 1240px container, 570px at 1024px).
   Change the split or the gap here and the COL constants there have to move
   with it, or every screen will be scaled to the wrong size. */

/* The visit index links to these sections. A jump lands on the hairline above
   the step with a little air over it, rather than on the step's heading — which
   sits below both the padding here and the eyebrow, a screenful in. */
.pshot {
  padding-block: clamp(44px, 5.5vw, 80px);
  scroll-margin-top: clamp(12px, 1.5vw, 24px);
}

.pshot + .pshot { border-top: 1px solid var(--line); }

.pshot__inner {
  display: grid;
  gap: clamp(28px, 4vw, 44px);
  align-items: center;
}

@media (min-width: 1024px) {
  .pshot__inner {
    grid-template-columns: 38fr 62fr;
    gap: 56px;
  }

  /* A portrait panel at native size — the Maya panels are 320px — would sit in
     a 734px frame with 200px of nothing either side. Evening the columns gives
     it a frame roughly its own shape, and hands the copy a 62ch measure. */
  .pshot--narrow .pshot__inner { grid-template-columns: 50fr 50fr; }

  /* Alternating sides. Only the order swaps — the copy stays the first child in
     the DOM, so reading order and tab order are the same on every step.

     The track widths have to swap with it. `order` moves the figure into the
     FIRST track, so a flipped step left on `38fr 62fr` would hand the screen
     the narrow column and the copy the wide one — which clips every shot at
     the frame edge rather than making it obvious something is wrong. */
  .pshot--flip.pshot--wide .pshot__inner { grid-template-columns: 62fr 38fr; }
  .pshot--flip .pshot__copy { order: 2; }
  .pshot--flip .pshot__figure { order: 1; }
}

.pshot__eyebrow {
  display: flex;
  align-items: baseline;
  gap: var(--space-xs);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.pshot__step {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--blue-accent);
}

.pshot__title {
  margin-top: var(--space-sm);
  font-family: var(--font-heading);
  font-size: clamp(26px, 2.7vw, 38px);
  line-height: 1.12;
  letter-spacing: 0.02em;
  color: var(--blue-accent);
}

.pshot__lead { margin-top: clamp(14px, 1.8vw, 20px); }
.pshot__lead p + p { margin-top: 0.85em; }

/* ---------- The frame around a product screen ----------
   Quiet on purpose. The app UI inside it is the busy thing; a heavy chrome
   treatment would compete with the software it is supposed to be showing. */

.pshot__figure {
  margin: 0;
  min-width: 0;   /* let the frame shrink inside the grid track */
}

.pshot__frame {
  overflow: hidden;
  /* The product screen inside is light, because the product is light.
     The frame keeps the app's own canvas colour so the shot reads as a
     lit screen in an unlit room rather than as a hole in the page. */
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--product-canvas);
  box-shadow: var(--shadow-lg);
}

/* Below the two-column breakpoint the stage is released to full width and each
   component uses its own responsive layout rather than being a shrunken
   desktop screen. Where one has a hard minimum anyway — the two Maya panels
   are 320px each and do not reflow — the frame scrolls, not the page. */
/* Centred, because a component narrower than the column it sits in — the two
   Maya panels are 640px against 734px of frame — should not be pinned left
   with the slack all on one side. Anything wider is scaled to fit exactly, so
   the auto margins collapse to nothing and this is a no-op. */
.pshot__stage {
  width: 100%;
  margin-inline: auto;
}

@media (max-width: 1023.98px) {
  .pshot__frame {
    overflow-x: auto;
    overflow-y: hidden;
  }
}

/* The fallbacks are what make `stage` optional: a component that already fits
   its column emits no custom properties and simply stays at 100% / no zoom. */
@media (min-width: 1024px) {
  .pshot__stage {
    width: var(--stage, 100%);
    zoom: var(--zoom-md, 1);
  }
}

@media (min-width: 1240px) {
  .pshot__stage { zoom: var(--zoom-lg, 1); }
}

/* A single docked panel, shown on the app's own canvas colour so the space
   around it reads as the shell it sits in rather than as an empty frame. */
.pshot__panel {
  display: flex;
  justify-content: center;
  padding: clamp(16px, 2.5vw, 32px);
}

/* A full screen shown with room around it, on the app's own canvas colour —
   for components whose own chrome runs to their edges (the note editor's
   action bar, the chart's print buttons) and would otherwise butt straight
   into the frame's hairline.

   The padding sits INSIDE .pshot__stage, so `zoom` scales it along with the
   screen and the inset stays proportional at every width. It is therefore paid
   for out of the stage's own width: a step using this adds 40px to its `stage`
   prop so the component still renders at its native size. Fixed px rather than
   a clamp for the same reason — a vw-based pad would be zoomed twice over. */
.pshot__inset {
  padding: 20px;
}

/* Step 02 stacks two things in one frame: the arrival animation above the
   queue it drives. The hairline is what makes them read as cause and effect
   rather than as two unrelated pictures. It sits on the WRAPPER (below), so it
   stays full-width even though the drawing inside has shrunk. */
.pshot__pair > :first-child {
  border-bottom: 1px solid var(--line);
}

/* The arrival animation is a diagram explaining the beat, not a second screen
   competing with the queue for attention — the queue is what this step is
   actually about. Shrunk and centred so it reads as an inset, with room
   around it instead of butting straight into the frame edges. */
.pshot__arrival {
  display: flex;
  justify-content: center;
  padding: clamp(20px, 3vw, 32px) clamp(16px, 4vw, 40px);
}

.pshot__arrival .ca {
  width: 52%;
  min-width: 220px;
}

/* ---------- The beacon dropdown's glow ----------
   Marketing-site-only, added 2026-08-19 — NOT extracted from the product, and
   deliberately kept out of ehr.css over that: ehr.css's own header promises it
   mirrors the product's token file 1:1 and re-authors nothing, and this glow
   has no product equivalent to mirror. It lives here instead, as a page
   affordance rather than a product fact.

   What it is for: step 01's copy calls this dropdown "the one control on this
   page that does anything." Nothing else about the field says so — it now
   reads identically to the inert Provider / Location / Room fields beside it
   (same border, same static chevron) since those were made non-interactive.
   The glow is what tells a visitor this one is different and worth a click.

   Applied by BeaconPicker.tsx as `.beacon-glow`, only until the trigger is
   opened for the first time — see the `hasOpened` state there. It is a prompt
   for a first interaction, not ambient decoration that runs forever; a
   visitor who has already found the control does not need it argued twice.

   Blue, matching blue-600 — the trigger's own focus ring and the sheet's
   un-rebranded palette (see AppointmentModal.astro's header note on why this
   sheet stays off brand navy) — not the site's teal or the app's brand token,
   neither of which appears anywhere else on this control. */

@keyframes beacon-glow-pulse {
  0%, 100% { box-shadow: 0 0 6px 1px color-mix(in srgb, var(--product-blue) 18%, transparent); }
  50%      { box-shadow: 0 0 18px 5px color-mix(in srgb, var(--product-blue) 42%, transparent); }
}

.beacon-glow {
  animation: beacon-glow-pulse 2.4s ease-in-out infinite;
}

/* Stopped, not just visually overridden, the instant the control takes
   keyboard focus — a running box-shadow animation wins the cascade over
   Tailwind's `focus:ring-2` for the same property, which would otherwise hide
   the focus ring from a keyboard user tabbing to the field before ever
   clicking it. */
.beacon-glow:focus-visible {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .beacon-glow {
    animation: none;
    box-shadow: 0 0 14px 3px color-mix(in srgb, var(--product-blue) 30%, transparent);
  }
}


/* ============================================================
   Arrival — what lands, and in what order

   The primitive is .reveal in components.css; this is the walkthrough's
   own choreography.

   The page has one focal sequence and it is the visit index. It is the
   only place where the whole visit is visible at once, so it is ruled
   the way a ledger is ruled: the top line is drawn, then each row's
   numeral and label rise as the hairline under it is drawn, down the
   five steps in the order the visit happens. The five sections below
   are then variations on that same beat — copy first, screen behind it
   — rather than five more entrances.

   The product screens' own animations are untouched. ClinicArrival and
   QueuePage are two CSS timelines locked to each other by starting in
   the same style resolution (see the header of ClinicArrival.astro);
   nothing here gates, pauses or restarts them, and an opacity on an
   ancestor cannot. Note for later: keep content-visibility away from
   .pshot for exactly that reason.
   ============================================================ */

/* ---------- Hero ---------- */

.reveals-armed .hero__title { --reveal-delay: 140ms; }
.reveals-armed .hero__lead  { --reveal-delay: 220ms; }

/* Both pieces are rotated a quarter turn as drawn, so their entrances are
   authored in that same rotated frame: a few degrees of turn and a hair of
   scale, which reads on a gear and a circuit trace without either of them
   sliding in from anywhere. */
.reveals-armed .hero__gears,
.reveals-armed .hero__circuit {
  --reveal-duration: var(--reveal-long);
}

.reveals-armed .hero__gears {
  --reveal-from: rotate(-10deg) scale(0.94);
  --reveal-delay: 300ms;
}

.reveals-armed .hero__circuit {
  --reveal-from: rotate(6deg) scale(0.96);
  --reveal-delay: 400ms;
}

/* ---------- The band's lead-in and the visit index ---------- */

.reveals-armed .band__lead { --reveal-delay: 90ms; }

/* The list itself only carries the trigger — its arrival is the top rule
   being drawn, and then the rows. */
.reveals-armed .visit-index::before,
.reveals-armed .visit-index__item::after {
  clip-path: inset(0 100% 0 0);
  transition: clip-path var(--reveal-quick) var(--reveal-ease) var(--reveal-delay, 0ms);
}

.reveals-armed .visit-index.is-revealed::before,
.reveals-armed .visit-index__item.is-revealed::after {
  clip-path: inset(0 0 0 0);
}

/* The pseudo-element rules need the same release the primitive gives the
   elements themselves — see the foot of components.css. */
@media (prefers-reduced-motion: reduce), print {
  .reveals-armed .visit-index::before,
  .reveals-armed .visit-index__item::after {
    clip-path: none;
  }
}

/* 65ms a row: five steps land inside four hundred milliseconds, which is
   a sequence being laid out rather than a list being dealt. */
.reveals-armed .visit-index__item {
  --reveal-shift: 10px;
  --reveal-duration: var(--reveal-quick);
}

.reveals-armed .visit-index__item:nth-child(1) { --reveal-delay: 90ms; }
.reveals-armed .visit-index__item:nth-child(2) { --reveal-delay: 155ms; }
.reveals-armed .visit-index__item:nth-child(3) { --reveal-delay: 220ms; }
.reveals-armed .visit-index__item:nth-child(4) { --reveal-delay: 285ms; }
.reveals-armed .visit-index__item:nth-child(5) { --reveal-delay: 350ms; }

/* ---------- The five steps ----------
   Copy leads by a beat, then the screen. The frame is the heaviest object
   on the page and the only one whose contents move on their own, so it
   arrives on the longest, softest curve of anything here: it settles up
   into place rather than being handed in from a side. */

.reveals-armed .pshot__title { --reveal-delay: 80ms; }
.reveals-armed .pshot__lead  { --reveal-delay: 160ms; }

.reveals-armed .pshot__figure {
  --reveal-from: translateY(26px) scale(0.99);
  --reveal-duration: var(--reveal-long);
  --reveal-delay: 100ms;
}
