/* ==========================================================================
   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 three weights the page actually uses.
   -------------------------------------------------------------------------- */

@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-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 carries both spans
       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 in every
   direction (see .anim__svg), so it is the page's floor and walls, not a picture
   hanging on them. Everything else therefore has to be 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 is what makes the room the whole screen: the box below only sets
   the drawing's scale and centring, while the architecture inside runs hundreds of
   units past it in every direction and is cropped by the viewport instead. It also
   lets the impact burst break out of the top. */
.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.

   Weight is --weight-medium (500), one step down from bold. Note it cannot be the
   token scale's --weight-semibold (600): the licensed family here is Light /
   Regular / Medium / Bold, and with no 600 face CSS font matching resolves 600
   upwards to 700 — so asking for semibold would render identically to bold.
   Medium is the next weight that actually exists.

   The margin carries what the rule and its two gaps used to occupy, so removing
   the rule leaves the paragraph, CTA and colophon exactly where they were. */
.headline {
  margin: 0 0 calc(var(--gap-rule) + 2px + 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-medium);
  color: var(--text-primary);
  text-wrap: balance;
  flex: 0 0 auto;
}

/* 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)));
  }
}

/* --------------------------------------------------------------------------
   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; }
}
