/* moloqo.com
   One stylesheet, no framework. Values are lifted from the original design, not
   re-invented: the colours, type sizes and spacing below are what the site
   already looked like. Tokens on :root are the things worth changing. */

/* Latin only, at the two weights the site uses. The original shipped ten faces
   covering Cyrillic and Vietnamese, base64'd inline at +33% each. The mono is
   used only for small uppercase labels, so `swap` reflows nothing above the
   fold — the display type is a system stack and needs no webfont at all. */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --paper: #f2f3f9;
  --paper-alt: #eef0f8;
  --card-hover: #e9ebf6;

  --ink: #15161d;
  --ink-soft: #22242f;
  --body: #44485c;
  --body-alt: #4d5265;
  --faint: #6a6e84;
  --faintest: #666c85;
  --num: #666c85;

  --line: #dfe1ee;
  --line-soft: #dbdeec;
  --line-btn: #c9cddf;

  --accent: #3b46f0;
  --accent-hover: #7b3ff2;

  --wrap: 1080px;
  --pad: 40px;

  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --sans: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; background: var(--paper); }

body {
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }
::selection { background: #d8dbfb; }

img { max-width: 100%; }

h1, h2, h3 { margin: 0; font-weight: 500; }
p { margin: 0; }

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}

/* ---------------------------------------------------------------- eyebrows */

.eyebrow {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---------------------------------------------------------------- buttons */

.btn, .btn-ghost, .btn-quiet {
  display: inline-block;
  border-radius: 999px;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}

.btn {
  background: var(--ink);
  color: var(--paper);
  font-size: 15px;
  padding: 14px 26px;
}
.btn:hover { background: var(--accent); color: var(--paper); }

.btn-ghost {
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid var(--ink);
  color: var(--ink);
  padding: 10px 18px;
}
.btn-ghost:hover { background: var(--ink); color: var(--paper); }

.btn-quiet {
  font-size: 15px;
  padding: 14px 22px;
  color: var(--body);
}
.btn-quiet:hover { color: var(--ink); }

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* ---------------------------------------------------------------- header */

.site-header {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 28px var(--pad);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ink);
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.brand:hover { color: var(--ink); }
/* The mark is a raster with a baked-in light background; multiply drops it out
   against the page. Replace with an SVG and this rule goes away. */
.brand img { border-radius: 8px; display: block; mix-blend-mode: multiply; }

/* ---------------------------------------------------------------- hero */

.hero {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 80px var(--pad) 96px;
  display: grid;
  gap: 36px;
  justify-items: start;
}

.hero h1 {
  font-size: clamp(40px, 6.2vw, 76px);
  line-height: 1.02;
  letter-spacing: -0.035em;
  max-width: 20ch;
  text-wrap: balance;
}

.hero .lede {
  font-size: 20px;
  line-height: 1.55;
  color: var(--body);
  max-width: 58ch;
  text-wrap: pretty;
}

.hero .actions { margin-top: 8px; }

/* ---------------------------------------------------------------- clients */

.clients {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.clients .wrap { padding-top: var(--pad); padding-bottom: var(--pad); }
.clients .eyebrow { margin-bottom: 24px; }

/* Real brand SVGs, each linking to the company. Sizes come from site.json and
   are tuned per mark rather than set uniformly — see clientsHtml() for why. The
   row wraps rather than scrolls, so a narrow screen stacks it into two or three
   lines instead of hiding logos off the edge. */
.client-logos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 24px 44px;
}

.client-logos a {
  display: block;
  cursor: pointer;
  /* Resting slightly back so the row reads as a supporting band rather than
     competing with the copy; full strength on hover. */
  opacity: 0.8;
  transition: opacity .2s ease;
}
.client-logos a:hover,
.client-logos a:focus-visible { opacity: 1; }

.client-logos img {
  display: block;
  /* The intrinsic width/height attributes carry the tuned size, so the image
     needs no per-brand CSS — but height must be pinned or a wrapped flex line
     would stretch it. */
  height: auto;
}

/* A placeholder until Charlie supplies a real quote. Styled so it reads as part
   of the proof band with the logos, not as a pull-quote competing with the h1. */
.testimonial {
  margin: 36px 0 0;
  max-width: 62ch;
  display: grid;
  gap: 12px;
}
.testimonial blockquote { margin: 0; }
.testimonial blockquote p {
  font-size: 18px;
  line-height: 1.55;
  color: var(--ink-soft);
  text-wrap: pretty;
}
.testimonial figcaption {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--faintest);
}
.testimonial .cite-name { color: var(--body); }

/* Press and venture links inside the stat cards. Quieter than a body link, but
   underlined so they read as verifiable sources rather than decoration. */
.stats dd a {
  color: var(--body);
  border-bottom: 1px solid var(--line-btn);
}
.stats dd a:hover { color: var(--accent); border-color: var(--accent); }

/* ---------------------------------------------------------------- thesis */

.thesis {
  padding-top: 96px;
  padding-bottom: 96px;
  display: grid;
  gap: 28px;
}

.thesis h2 {
  font-size: clamp(26px, 3.4vw, 40px);
  line-height: 1.2;
  letter-spacing: -0.025em;
  max-width: 34ch;
  text-wrap: balance;
}

.prose {
  display: grid;
  gap: 14px;
  max-width: 70ch;
}
.prose p {
  font-size: 18px;
  line-height: 1.6;
  color: var(--body);
  text-wrap: pretty;
}
.prose .emphasis { color: var(--ink-soft); }

/* ---------------------------------------------------------------- services */

.services { border-top: 1px solid var(--line); }
.services .wrap { padding-top: 80px; padding-bottom: 96px; }
.services .eyebrow { margin-bottom: 44px; }

/* 1px gap over a background is the hairline rule between cards — one border
   rather than one per edge, so interior lines never double up. */
.services .grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}

.services .grid li {
  background: var(--paper);
  padding: 32px 30px;
  display: grid;
  gap: 12px;
  align-content: start;
  transition: background-color .25s ease;
}
.services .grid li:hover { background: var(--card-hover); }

.card-top {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--accent);
}
.card-top .num {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--num);
}

.services h3 { font-size: 20px; letter-spacing: -0.015em; }
.services .grid p:not(.card-top) {
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--body-alt);
}

.services .note {
  margin-top: 28px;
  font-size: 15.5px;
  color: var(--faint);
}

/* ---------------------------------------------------------------- background */

.background {
  border-top: 1px solid var(--line);
  background: var(--paper-alt);
}

.background .split {
  padding-top: 80px;
  padding-bottom: 80px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 56px;
}

.background .split > div:first-child {
  display: grid;
  gap: 20px;
  align-content: start;
}

.background h2 {
  font-size: clamp(24px, 2.6vw, 32px);
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.background .prose { font-size: 16px; line-height: 1.6; color: var(--body); text-wrap: pretty; }

.stats {
  margin: 0;
  display: grid;
  align-content: start;
}
.stats > div {
  display: grid;
  gap: 6px;
  padding: 20px 0;
  border-top: 1px solid var(--line-soft);
}
.stats > div:last-child { border-bottom: 1px solid var(--line-soft); }

.stats dt {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--faintest);
}
.stats dd {
  margin: 0;
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- cta */

.cta { border-top: 1px solid var(--line); }
.cta .wrap {
  padding-top: 110px;
  padding-bottom: 110px;
  display: grid;
  gap: 28px;
  justify-items: start;
}
.cta h2 {
  font-size: clamp(30px, 4.4vw, 54px);
  line-height: 1.08;
  letter-spacing: -0.03em;
  max-width: 26ch;
  text-wrap: balance;
}

/* The closing line carries both calls to action as inline links rather than
   buttons, so the section reads as a sentence instead of a toolbar. */
.cta-line {
  font-size: 20px;
  line-height: 1.55;
  color: var(--body);
}
.cta-line a {
  color: var(--ink);
  border-bottom: 1px solid var(--line-btn);
  padding-bottom: 1px;
  transition: color .18s ease, border-color .18s ease;
}
.cta-line a:hover { color: var(--accent); border-color: var(--accent); }

/* ---------------------------------------------------------------- footer */

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--paper-alt);
}
.site-footer .wrap {
  padding-top: 32px;
  padding-bottom: 32px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.08em;
  color: var(--faintest);
}
.footer-links { display: flex; flex-wrap: wrap; gap: 20px; }

/* The statutory trading disclosure. Quiet, but it has to be readable — it is
   there for a reader, not only to satisfy the regulation. */
.legal {
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  letter-spacing: 0.04em;
  color: var(--faintest);
  padding-bottom: 28px;
  margin-top: -8px;
}
.footer-links a { color: var(--faintest); }
.footer-links a:hover { color: var(--ink); }

/* ---------------------------------------------------------------- reveal

   Scroll-linked reveal in CSS. The original did this in ~90 lines of JavaScript
   with three watchdog timers and a real failure mode where content stayed at
   opacity 0 if the sweep never ran. Here the animation only exists inside the
   @supports block, so anything that does not support view timelines — Firefox
   today — renders the page fully visible, which is the correct failure. */

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    /* Longhands, not the `animation` shorthand: the shorthand would set
       animation-duration to 0s, and a scroll-driven animation needs `auto` for
       its progress to be driven by the timeline rather than by time. With 0s it
       pins at the first keyframe and the content never becomes visible. */
    /* `forwards`, never `both`. A backwards fill would pin every element at the
       first keyframe — opacity 0 — for as long as the timeline has not resolved,
       which is how the JavaScript version this replaces used to lose content.
       With `forwards` the unresolved state is the element's natural one, so the
       worst failure is a missing fade rather than missing copy. */
    [data-reveal] {
      animation-name: reveal;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: forwards;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }

    /* The hero deliberately has no entrance animation. Anything above the fold
       that starts at opacity 0 depends on a timeline that is frozen while the
       document is hidden — a background tab, a session restore, a headless
       renderer — and this is the page's h1 and LCP element. It is not worth
       risking the most important text on the site rendering blank to save a
       fade, and painting it immediately is faster besides. */
  }

  @keyframes reveal {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
  }
}

/* ---------------------------------------------------------------- narrow */

@media (max-width: 640px) {
  :root { --pad: 24px; }

  .hero { padding-top: 48px; padding-bottom: 64px; gap: 28px; }
  .hero .lede { font-size: 18px; }

  .thesis { padding-top: 64px; padding-bottom: 64px; }
  .services .wrap { padding-top: 56px; padding-bottom: 64px; }
  .services .eyebrow { margin-bottom: 28px; }
  .services .grid { grid-template-columns: 1fr; }
  .background .split { padding-top: 56px; padding-bottom: 56px; gap: 36px; }
  .cta .wrap { padding-top: 72px; padding-bottom: 72px; }

  .site-header { padding-top: 20px; padding-bottom: 20px; }
  .actions { gap: 10px; }
  .btn, .btn-quiet, .btn-outline { font-size: 14.5px; }
}
