/* ==========================================================================
   Folgo — single-viewport holding page
   One composition, no scroll, dark by default.

   BRAND
   Values here are lifted from the Folgo Design System (claude.ai/design,
   "Folgo Design System", updated 17 Aug 2026) — tokens/colors.css,
   typography.css, radius.css, motion.css, and components/core/Button.
   Only the tokens this page actually uses are carried across; anything the
   page had to invent is derived from them and marked where it appears.

   Two deliberate departures, both toward the brand rather than away from it:
     · the design system ships General Sans as a stand-in because no licensed
       binaries came with the brand kit — this page has the real Neue Montreal
       files in assets/, so it uses the actual brand face;
     · the line art is drawn in Warm Ivory rather than white, so the drawing
       reads as ink on warm stock while UI text stays on --text-primary.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Neue Montreal — only the four weights the page actually uses.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Neue Montreal";
  src: url("assets/neue-montreal-free-demo-pangram-pangram-030418/NeueMontreal-Light.otf") format("opentype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Neue Montreal";
  src: url("assets/neue-montreal-free-demo-pangram-pangram-030418/NeueMontreal-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Neue Montreal";
  src: url("assets/neue-montreal-free-demo-pangram-pangram-030418/NeueMontreal-Medium.otf") format("opentype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Neue Montreal";
  src: url("assets/neue-montreal-free-demo-pangram-pangram-030418/NeueMontreal-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Recreated animation: 9 cels over a 766ms loop (~85ms per cel),
     measured from the reference across 8 consecutive cycles. */
  --cycle: 766ms;

  /* Aspect of the animation's viewBox (160 / 77) — cropped close around the pair. */
  --anim-ar: 2.0779;

  /* ---- Brand palette — tokens/colors.css ------------------------------- */
  --folgo-burnt-orange: #eb5e29;
  --folgo-warm-ivory:   #f0ece3;
  --folgo-dark-espresso:#2d2324;
  --folgo-charcoal:     #222222;   /* the brand's dark surface  */
  --folgo-pure-black:   #000000;
  --folgo-white:        #ffffff;
  --folgo-grey-400:     #a6aab7;   /* secondary text on dark    */
  --folgo-grey-500:     #70737a;   /* secondary text on light   */
  --orange-500:         #d24e1d;   /* hover / pressed           */

  /* Semantic layer. Dark is the design system's default surface, so it lives on
     :root exactly as tokens/colors.css has it — but this page ships the system's
     sanctioned ivory alternative, .folgo-light, which is set on <html>. Remove
     that class and the whole page returns to the dark surface intact. */
  --surface-page:   var(--folgo-charcoal);
  --text-primary:   var(--folgo-white);
  --text-secondary: var(--folgo-grey-400);
  --text-on-accent: var(--folgo-white);
  --focus-ring:     var(--folgo-burnt-orange);

  /* ---- Type — tokens/typography.css ------------------------------------ */
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;
  --leading-display: 0.98;
  --leading-body: 1.55;
  --tracking-display: -0.035em;

  /* ---- Radius — tokens/radius.css -------------------------------------- */
  --radius-pill: 999px;

  /* ---- Motion — tokens/motion.css -------------------------------------- */
  --ease-standard: cubic-bezier(0.2, 0.7, 0.3, 1);
  --duration-instant: 80ms;
  --duration-fast: 140ms;
  --press-scale: 0.975;
  --hover-lift: -2px;

  /* ---- The drawing ------------------------------------------------------
     Not in the design system — derived from it. Depth is carried by tone: the
     further back something sits in the room, the closer it falls to the page.
     Every value is one brand ink at a decreasing alpha, so the scene stays on
     the brand's warm axis instead of drifting to neutral grey. On dark that ink
     is Warm Ivory; the light scope below mirrors it in Dark Espresso. */
  --ink:   var(--folgo-warm-ivory);         /* the two fighters   */
  --smear: rgba(240, 236, 227, 0.42);       /* the impact smear   */
  --room:  rgba(240, 236, 227, 0.12);       /* walls              */
  --floor: rgba(240, 236, 227, 0.055);      /* planks and seams   */

  --logo-invert: invert(1);                 /* black artwork -> white lockup */

  --muted: var(--text-secondary);

  --pad-y: clamp(12px, 2.9vh, 40px);
  --pad-x: clamp(20px, 5vw, 48px);

  /* ---- Vertical rhythm --------------------------------------------------
     Measured off latelogic.com at a 1440x785 viewport — supplied as the layout
     reference — and held as a share of viewport height, so the proportions
     survive any screen. That page runs a single-line headline where Folgo's is
     two; every gap is therefore carried at 85% of the measured value, which
     buys that second line back without touching the type sizes.

       reference   here      between
       61px        52px      logo -> art
       59px        50px      art -> headline
       34px        29px      headline -> (rule)   ) the reference's rule is gone;
       48px        41px      (rule) -> paragraph  ) .headline keeps only the second
       49px        42px      paragraph -> CTA
       80px        68px      CTA -> colophon                                  */
  --gap-art:      clamp(18px, 6.6vh, 52px);
  --gap-headline: clamp(16px, 6.4vh, 50px);
  --gap-rule:     clamp(10px, 3.7vh, 29px);
  --gap-lede:     clamp(14px, 5.2vh, 41px);
  --gap-cta:      clamp(14px, 5.4vh, 42px);
  --gap-colophon: clamp(24px, 8.7vh, 68px);

  --font: "Neue Montreal", -apple-system, BlinkMacSystemFont, "Segoe UI",
          Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* --------------------------------------------------------------------------
   Light scope — the surface this page ships on.

   The first block is tokens/colors.css's own .folgo-light, unchanged. The rest
   extends the same idea to the drawing: the art is mirrored into Dark Espresso
   on Warm Ivory stock at the identical alphas, so the room keeps exactly the
   weight it had on charcoal, while UI text sits on --text-primary (pure black).
   -------------------------------------------------------------------------- */

.folgo-light {
  --surface-page: var(--folgo-warm-ivory);
  --text-primary: var(--folgo-pure-black);
  --text-secondary: var(--folgo-grey-500);

  --ink:   var(--folgo-dark-espresso);
  --smear: rgba(45, 35, 36, 0.40);
  --room:  rgba(45, 35, 36, 0.12);          /* = the kit's --border-subtle */
  --floor: rgba(45, 35, 36, 0.055);

  --logo-invert: none;                      /* the artwork is already black */
}

/* --------------------------------------------------------------------------
   Reset / lock the viewport
   -------------------------------------------------------------------------- */

html { color-scheme: dark only; }
html.folgo-light { color-scheme: light only; }

html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--surface-page);
  color: var(--text-primary);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
}

/* --------------------------------------------------------------------------
   Composition
   -------------------------------------------------------------------------- */

.stage {
  box-sizing: border-box;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* The reference balances the space above the logo against the space under the
     CTA (84 / 80). Both are therefore --gap-colophon here: the top padding is
     that gap outright, and the bottom reserves the same gap plus the colophon's
     own line and offset, so whatever slack is left gets split evenly by
     justify-content and the composition sits where the reference's does. */
  padding:
    calc(var(--gap-colophon) + env(safe-area-inset-top))
    calc(var(--pad-x) + env(safe-area-inset-right))
    calc(var(--gap-colophon) + 1.4em + var(--pad-y) + env(safe-area-inset-bottom))
    calc(var(--pad-x) + env(safe-area-inset-left));
}

/* The room is painted by the animation's SVG but escapes its box on every side
   except the bottom (see .anim__svg and the room's own clip-path in index.html), so
   the walls read as the page's own walls while the floor stops at the pair's feet
   rather than continuing on toward the viewer. Everything else is lifted above it. */
.logo,
.headline,
.lede,
.cta {
  position: relative;
  z-index: 1;
}

/* --------------------------------------------------------------------------
   Logo
   -------------------------------------------------------------------------- */

/* The wordmark ships as black artwork, which is already the light-surface lockup.
   On the dark surface --logo-invert flips it to the brand's white lockup exactly,
   rather than swapping in a differently-cropped asset and shifting the
   composition the rest of the page is measured against. */
.logo {
  display: block;
  width: auto;
  filter: var(--logo-invert);
  height: clamp(20px, 4.2vh, 33px);     /* reference: 33px */
  margin-bottom: var(--gap-art);
  flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   Recreated animation
   Two characters at the near edge of a wide-angle room. The impact burst
   overflows the top of the box.
   -------------------------------------------------------------------------- */

.anim {
  width: min(92vw, calc(28vh * var(--anim-ar)), 1000px);
  aspect-ratio: var(--anim-ar);
  margin-bottom: var(--gap-headline);
  flex: 0 1 auto;
}

/* overflow:visible lets the room's walls run past the box in every direction — up to
   the top of the screen, out to both side edges — the same bleed the composition always
   used. Only the floor is bounded, and that happens in index.html (a clip-path on
   <g class="room"> cut at y=101, just past the pair's feet), not here: the SVG itself
   stays open on every side so the walls keep reaching the screen edges. */
.anim__svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.ink   { fill: var(--ink);   fill-rule: evenodd; }
.smear { fill: var(--smear); fill-rule: evenodd; }

/* Annotation, not part of the drawing — so it takes the UI's secondary text
   colour rather than the ink, and reads as a caption pointing at the character.
   Sized in user units, so it scales with the scene and stays in proportion to
   the figure it labels at every viewport. */
.label {
  fill: var(--text-secondary);
  font-family: var(--font);
  font-weight: var(--weight-regular);
  font-size: 7.5px;         /* user units: ~13px where the scene draws at 1.8px/unit */
  letter-spacing: 0.01em;
  text-anchor: middle;
}

/* Silhouette matte: a shape traced from each cel's own artwork and painted under
   it in the page's own colour, so the room's lines stop at the characters'
   outlines instead of running straight through their hollow interiors. It is
   invisible by definition — all you ever see of it is the room correctly
   disappearing behind them. It must track --surface-page: hard-code it and the
   silhouettes show up as solid blocks the moment the surface changes.

   Regenerating: tools/trace-mattes.js rasterises each cel, flood-fills the page
   from the border, and traces the boundary of everything the flood cannot reach. */
.matte {
  fill: var(--surface-page);
  stroke: var(--surface-page);
  stroke-width: 0.5;      /* a hair of clearance so no line kisses an outline */
  stroke-linejoin: round;
}

/* --------------------------------------------------------------------------
   The room — one-point perspective, vanishing point (80,46), running off every
   edge of the screen. All strokes are non-scaling hairlines, so the architecture
   stays a crisp 1px however large the drawing is scaled, and the floor's grid
   never thickens into a cage on a big display.
   -------------------------------------------------------------------------- */

.room__line   { fill: none; stroke: var(--room);  stroke-width: 1; }
.floor__plank,
.floor__seam  { fill: none; stroke: var(--floor); stroke-width: 1; }

/* Each cel is visible for exactly one slice of the loop, then hard-cuts to the
   next — the same discrete frame-by-frame cadence as the reference.
   A negative delay of -(cels - i)/cels shifts cel i into its own slice. */
.cel {
  opacity: 0;
  animation: cel-flip var(--cycle) steps(1, end) infinite;
  will-change: opacity;
}

@keyframes cel-flip {
  0%       { opacity: 1; }
  11.1111% { opacity: 0; }
  100%     { opacity: 0; }
}

.cel[data-cel="1"] { animation-delay: calc(var(--cycle) * -9 / 9); }
.cel[data-cel="2"] { animation-delay: calc(var(--cycle) * -8 / 9); }
.cel[data-cel="3"] { animation-delay: calc(var(--cycle) * -7 / 9); }
.cel[data-cel="4"] { animation-delay: calc(var(--cycle) * -6 / 9); }
.cel[data-cel="5"] { animation-delay: calc(var(--cycle) * -5 / 9); }
.cel[data-cel="6"] { animation-delay: calc(var(--cycle) * -4 / 9); }
.cel[data-cel="7"] { animation-delay: calc(var(--cycle) * -3 / 9); }
.cel[data-cel="8"] { animation-delay: calc(var(--cycle) * -2 / 9); }
.cel[data-cel="9"] { animation-delay: calc(var(--cycle) * -1 / 9); }

/* --------------------------------------------------------------------------
   Type
   -------------------------------------------------------------------------- */

/* Headline runs at display scale, so it takes the display voice: --leading-display
   and --tracking-display.

   The licensed family here is Light / Regular / Medium / Bold — 300 / 400 / 500 /
   700, with nothing in between. Those four are the whole ladder, so a step means a
   face, not a number: the headline runs on Regular, one rung down from the Medium it
   started at. Every face named below is loaded for real, so none is synthesised.

   Note the ladder is also why the token scale's --weight-semibold (600) is unusable
   here: with no 600 face, CSS font matching resolves it upwards to 700.

   The margin used to carry both of the removed rule's spans plus the rule itself
   (--gap-rule + 2px + --gap-lede, ~72px), which held the paragraph where it sat when
   there was still a rule to clear. With no rule there, that span is now a single rung
   — --gap-lede, the same ~41px the reference puts between a rule and its paragraph.
   Everything below rises by the ~31px the phantom rule was reserving. */
.headline {
  margin: 0 0 var(--gap-lede);
  max-width: 18ch;
  font-size: clamp(1.6rem, min(4.6vw, 7.6vh), 3.75rem);     /* reference: 60px */
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--weight-regular);
  color: var(--text-primary);
  text-wrap: balance;
  flex: 0 0 auto;
}

/* The two stressed words, one rung above the headline — Regular/Medium, the quietest
   contrast the ladder offers, which is the point: the words carry the stress without
   the line going heavy. Nothing else moves: same size, colour and tracking, so the
   line keeps its measure. */
.headline strong {
  font-weight: var(--weight-medium);
}

/* balance rather than pretty: the copy is two sentences of near-equal length, so
   evening out the lines lands the break on the full stop instead of splitting a
   clause. Falls back to normal wrapping where balance is unsupported. */
.lede {
  margin: 0 0 var(--gap-cta);
  max-width: 44ch;
  font-size: clamp(0.85rem, min(1.45vw, 2.42vh), 1.19rem);  /* reference: 19px */
  line-height: var(--leading-body);
  color: var(--text-secondary);
  text-wrap: balance;
  flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   CTA
   -------------------------------------------------------------------------- */

/* Button/primary: pill, burnt orange, one per view — which this page is. Sizing
   stays fluid rather than the kit's fixed lg (16px/32px, 18px label), but the
   proportions, weight, tracking, states and timings are the component's. */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: clamp(9px, 1.53vh, 12px) clamp(18px, 2.6vw, 24px);   /* kit md: 41px tall */
  border-radius: var(--radius-pill);
  background: var(--folgo-burnt-orange);
  border: 1px solid var(--folgo-burnt-orange);
  color: var(--text-on-accent);
  font-size: clamp(0.78rem, min(1.2vw, 2vh), 1rem);
  font-weight: var(--weight-medium);
  letter-spacing: -0.005em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  flex: 0 0 auto;
  transition: background-color var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard),
              transform var(--duration-instant) var(--ease-standard);
}

.cta__arrow {
  width: 1.05em;
  height: 1.05em;
  transition: transform var(--duration-fast) var(--ease-standard);
}

.cta:hover {
  background: var(--orange-500);
  border-color: var(--orange-500);
  transform: translateY(var(--hover-lift));
}

/* The mark is arrow-up-right, so it leaves the way it points. */
.cta:hover .cta__arrow { transform: translate(2px, -2px); }
.cta:active { transform: scale(var(--press-scale)); }

.cta:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Colophon — pinned to the foot of the viewport, as in the reference, rather
   than riding at the end of the centred stack. .stage reserves its strip in
   padding-bottom so the composition centres in what is left.
   -------------------------------------------------------------------------- */

.colophon {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(var(--pad-y) + env(safe-area-inset-bottom));
  z-index: 1;
  text-align: center;
  font-size: clamp(0.625rem, min(0.88vw, 1.52vh), 0.75rem); /* 15px -> two steps down
                                                              the UI ramp: --text-caption
                                                              12px, floor --text-micro 10px */
  line-height: 1.4;
  color: var(--text-secondary);
  padding-inline: var(--pad-x);
  pointer-events: none;    /* it is a static line: never eat a click on the room */
}

/* --------------------------------------------------------------------------
   Short / landscape viewports — tighten the composition further
   -------------------------------------------------------------------------- */

@media (max-height: 460px) {
  .anim { width: min(74vw, calc(20vh * var(--anim-ar)), 420px); }
  .logo { margin-bottom: clamp(12px, 4.5vh, 22px); }
  .headline { max-width: 24ch; }
  .lede { max-width: 52ch; line-height: 1.45; }
}

/* Narrow portrait screens: the frame is wide, so let it run edge to edge rather
   than shrink the characters to nothing. The room's fade does the framing. */
@media (max-width: 620px) {
  .anim {
    width: 100vw;
    margin-left: calc(-1 * (var(--pad-x) + env(safe-area-inset-left)));
    margin-right: calc(-1 * (var(--pad-x) + env(safe-area-inset-right)));
  }

  /* The room's walls and floor read as hairlines at --room/--floor's low alpha
     (0.12 / 0.055) — fine on a desktop display, but on mobile's pixel density
     a 1px non-scaling-stroke anti-aliases down to almost nothing. Widen the
     stroke rather than raise the alpha, so the room becomes legible without
     the ink itself reading any darker/closer to black than it already is. */
  .room__line { stroke-width: 1.75; }
  .floor__plank,
  .floor__seam { stroke-width: 1.4; }
}

/* --------------------------------------------------------------------------
   Reduced motion — hold a single cel, no flicker
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .cel { animation: none; }
  .cel[data-cel="1"] { opacity: 1; }

  .cta,
  .cta__arrow { transition: none; }
  .cta:hover { transform: none; }
}
