@import url("/assets/fonts.css");

/* fhg-premium.css — shared visual primitives for every FHG surface.
 *
 * WHY THIS EXISTS. Centering, the gold reveal and the card treatment were being
 * applied page by page, which meant they were applied inconsistently and had to
 * be remembered every time a card was added. The standing rule — titles AND
 * body content centered, no exception for long-form — should be what a card
 * DOES, not an instruction to follow.
 *
 * USAGE. One link, one script, both palettes:
 *   <link rel="stylesheet" href="/assets/fhg-premium.css">
 *   <script src="/assets/fhg-premium.js" defer></script>
 *
 * The script needs no configuration. It finds cards by class and by common
 * legacy names, so existing pages inherit the behavior without markup edits.
 *
 * PALETTE. Variables resolve from the host page. Each has a fallback so this
 * file renders correctly dropped into a page that scopes its own tokens
 * differently — University dark, Compass light, corporate dark.
 */

:root {
  --fhg-ease: cubic-bezier(.22, .61, .36, 1);
  /* 29 Oct 2026, the design audit's motion spec: 8-12px over 250-400ms,
     stagger capped near 150ms (fhg-premium.js: 50ms x 3). */
  --fhg-reveal-shift: 10px;
  --fhg-reveal-dur: .38s;
  --fhg-stagger: 50ms;
}

/* ─── Centering ────────────────────────────────────────────────────
   Applied to the card classes in use across the three sites. Adding a
   class here is how a new card joins, rather than copying rules. */

.fhg-card, .fhg-card *,
.inst-card, .inst-card *,
.inst-cert-card, .inst-cert-card *,
.seat-card, .seat-card *,
.pay-card, .pay-card *,
.fund-card, .fund-card *,
.card, .card * {
  text-align: center;
}

/* Lists lose bullets and indent, or centered text reads ragged. */
.fhg-card ul, .inst-card ul, .inst-cert-card ul,
.seat-card ul, .pay-card ul, .fund-card ul, .card ul {
  list-style: none;
  padding-left: 0;
  margin-left: auto;
  margin-right: auto;
}
.fhg-card li::before, .inst-card li::before, .seat-card li::before,
.pay-card li::before, .fund-card li::before, .card li::before {
  content: none;
}

/* ─── Price rows ──────────────────────────────────────────────────
   text-align centers INLINE content. A price row is almost always a
   flex container, and flex children are positioned by justify-content,
   which text-align does not touch. This is why centering the card did
   not center the price. */

.seat-price, .price, .price-row, .fhg-price,
.seat-card .seat-price, .seat-card .price,
.card .price {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Anything that sits on its own line under the price. */
.seat-equiv, .price-note, .fhg-price-note,
.seat-card .seat-equiv, .card .price span {
  display: block;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* A pill centers as a block only once it stops filling the row. */
.seat-save, .save-pill, .fhg-pill, .badge {
  display: block;
  width: fit-content;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

/* ─── Reveal on scroll ────────────────────────────────────────────
   Cards start hidden ONLY when the script has confirmed it will run.
   Without .fhg-js on <html>, everything renders visible — a stylesheet
   that hides content while its script fails is a blank page. */

.fhg-js .fhg-reveal {
  opacity: 0;
  transform: translateY(var(--fhg-reveal-shift));
  transition:
    opacity var(--fhg-reveal-dur) var(--fhg-ease),
    transform var(--fhg-reveal-dur) var(--fhg-ease),
    box-shadow .35s ease;
}

.fhg-js .fhg-reveal.fhg-in {
  opacity: 1;
  transform: none;
}

/* ─── Gold outline ────────────────────────────────────────────────
   A masked gradient border that traces in behind the card once it has
   settled. Diagonal, so it reads as light catching an edge rather than
   as a highlighted box. */

.fhg-reveal { position: relative; }

.fhg-reveal::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    135deg,
    var(--gold, #c9a86a),
    rgba(201, 168, 106, 0) 42%,
    rgba(201, 168, 106, 0) 58%,
    var(--gold, #c9a86a)
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 1.1s ease .25s;
  pointer-events: none;
}

.fhg-js .fhg-reveal.fhg-in::after { opacity: .8; }
/* Only a card that does something answers the pointer (fhg-premium.js marks
   it .fhg-action: it is a link or button, or holds one). A card that is only
   information stays still, so hover never promises a click that isn't there. */
.fhg-reveal.fhg-action:hover::after,
.fhg-reveal.fhg-action:focus-within::after { opacity: 1; transition-delay: 0s; }

/* ─── Lift ────────────────────────────────────────────────────────
   Shadow tinted toward the brand rather than neutral gray, so it reads
   as warm on cream and does not muddy on near-black. */

/* After the entrance settles, hover uses its own short timing (0.18s) so a
   lift never inherits the 0.38s entrance. Lift only where a fine pointer can
   hover; keyboard focus gets the same highlight, so neither input is second. */
.fhg-reveal.fhg-settled {
  transition:
    opacity var(--fhg-reveal-dur) var(--fhg-ease),
    transform .18s ease,
    box-shadow .18s ease;
}
@media (hover: hover) and (pointer: fine) {
  .fhg-reveal.fhg-in.fhg-action:hover {
    transform: translateY(-3px);
    box-shadow: 0 14px 34px -18px rgba(74, 58, 22, .38);
  }
}
.fhg-reveal.fhg-action:focus-within {
  box-shadow: 0 0 0 2px var(--gold, #c9a86a);
}

/* ─── Equal-height cards ──────────────────────────────────────────
   A CTA at the bottom of one card and mid-way up its neighbor is the
   tell that a grid was never checked at width. */

.fhg-card, .seat-card, .card, .fund-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.fhg-card ul, .seat-card ul, .card ul, .fund-card ul { flex: 1 0 auto; }

/* ─── Reduced motion ──────────────────────────────────────────────
   Everything visible, nothing animates. Not a degraded view — the same
   page without the movement. */

@media (prefers-reduced-motion: reduce) {
  .fhg-js .fhg-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .fhg-js .fhg-reveal::after { opacity: .8; transition: none; }
  .fhg-reveal.fhg-in.fhg-action:hover { transform: none; }
}

/* Printing never waits on a scroll that will not happen. */
@media print {
  .fhg-js .fhg-reveal { opacity: 1 !important; transform: none !important; }
}

/* ─── Centered body copy on public surfaces ────────────────────────
   Added Aug 28, 2026. The standing rule is that titles AND body copy
   center on every public FHG page. It was being applied page by page,
   so it was applied unevenly — this makes it what a public page DOES.

   Scoped to [data-surface="public"] deliberately. Dashboards and member
   surfaces link this same stylesheet and are under separate review, so a
   bare `p { text-align: center }` would reach them too.

   Tables, code and form fields keep their own alignment: centering tabular
   data or a code block makes it harder to read, which is the opposite of
   the point. */

[data-surface="public"] p,
[data-surface="public"] h1,
[data-surface="public"] h2,
[data-surface="public"] h3,
[data-surface="public"] h4,
[data-surface="public"] li,
[data-surface="public"] blockquote,
[data-surface="public"] figcaption,
[data-surface="public"] dd,
[data-surface="public"] dt {
  text-align: center;
}

[data-surface="public"] table,
[data-surface="public"] th,
[data-surface="public"] td,
[data-surface="public"] pre,
[data-surface="public"] code,
[data-surface="public"] label,
[data-surface="public"] input,
[data-surface="public"] textarea,
[data-surface="public"] select {
  text-align: initial;
}

/* No list markers on centered public copy. 4 Oct 2026 (owner): a centered
   list item leaves its bullet or number at the left edge of the column, far
   from the text it belongs to, which reads as broken. On public surfaces a
   list is a stack of centered lines; the order, where it matters, is carried
   by the words ("1." in a heading, "first", "then"), not by a marker.
   list-marker-guard.py fails the build if a public page brings markers back. */
[data-surface="public"] ul,
[data-surface="public"] ol {
  list-style: none;
  padding-left: 0;
}

/* Inside a lesson, step order is content: a numbered procedure or a set of
   self-check questions keeps its numbers, drawn INSIDE the centered line so
   each number sits beside its own text rather than at the column's edge. */
[data-surface="public"] .lesson-shell ol,
[data-surface="public"] .sm-body ol {
  list-style: decimal inside;
}

/* Centered text needs a measure, or a wide viewport turns a paragraph into
   a ragged ribbon that is genuinely harder to read than left-aligned. */
[data-surface="public"] p {
  max-width: 68ch;
  margin-left: auto;
  margin-right: auto;
}
