/* RanexisAR - light editorial.
   Layout and motion patterns follow the reference (cream ground, serif
   display, marquee, numbered accordion, bento). Every asset is either ours
   or free-licensed; nothing is lifted from that site. */

/* Self-hosted faces, latin subset only.
   These used to come from fonts.googleapis.com, which meant a DNS lookup,
   TLS handshake and stylesheet round trip to a third party before the first
   heading could paint. Same-origin, they arrive on the connection the page
   is already using.
   Inter ships as ONE variable file covering 100-900. Google's API hands
   back a separate @font-face per weight, but all three responses were the
   same bytes - three requests for one file. */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  /* swap, not optional: the hero h1 in this face is the most recognisable
     thing on the page, so it is worth drawing whenever it lands rather than
     falling back to Georgia for the whole visit on a slow connection. It is
     preloaded, so the window where a swap is visible is small. */
  font-display: swap;
  src: url('/fonts/instrument-serif-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/instrument-serif-400-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  /* optional for body text: the system-ui fallback is close enough in
     metrics that never swapping costs almost nothing visually, and it
     removes the layout shift entirely. */
  font-display: optional;
  src: url('/fonts/inter-var.woff2') format('woff2');
}

:root {
  --paper: #f7f6f3;
  --paper-2: #efeee9;
  --ink: #0e0e0c;
  --ink-soft: #6b6a64;
  --line: #dedcd4;
  --accent: #ff5c2b;
  --card: #ffffff;
  --radius: 18px;
  --maxw: 1240px;
  --ease: cubic-bezier(.22,.61,.36,1);
}

* { box-sizing: border-box; }

/* An author rule setting `display` (e.g. .btn's `display:inline-flex`)
   always beats the browser's default `[hidden]{display:none}`, since
   author styles outrank user-agent styles regardless of specificity or
   source order. Without this, `el.hidden = true` on a styled element is
   silently a no-op - it stays fully visible and clickable. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 16px/1.62 Inter, ui-sans-serif, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 28px; }

.serif {
  font-family: "Instrument Serif", Georgia, "Times New Roman", serif;
  font-weight: 400;
  letter-spacing: -.015em;
}

.eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-soft);
}

/* ---------- reveal on scroll ---------- */
.reveal {
  opacity: 0; transform: translateY(22px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.in { opacity: 1; transform: none; }

/* ---------- side tab ---------- */
.sidetab {
  position: fixed; left: 0; top: 34vh; z-index: 40;
  background: var(--ink); color: var(--paper);
  writing-mode: vertical-rl; text-orientation: mixed;
  padding: 18px 9px; border-radius: 0 10px 10px 0;
  font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  font-weight: 600;
}
@media (max-width: 900px) { .sidetab { display: none; } }

/* ---------- header ---------- */
header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(247,246,243,.86);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease);
}
header.stuck { border-bottom-color: var(--line); }
.nav { display: flex; align-items: center; gap: 30px; height: 74px; }
.brand { display: flex; align-items: center; gap: 9px; font-weight: 600; font-size: 17px; }
.brand-mark { width: 26px; height: 26px; border-radius: 22%; display: block; object-fit: cover; }
.nav .spacer { flex: 1; }
.nav a.link { color: var(--ink-soft); font-size: 15px; transition: color .2s; }
.nav a.link:hover { color: var(--ink); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  border: 0; cursor: pointer; font: inherit; font-weight: 500; font-size: 15px;
  padding: 13px 24px; border-radius: 999px;
  background: var(--ink); color: var(--paper);
  transition: transform .18s var(--ease), background .18s;
}
.btn:hover { transform: translateY(-2px); background: #23231f; }
.btn.accent { background: var(--accent); color: #fff; }
.btn.accent:hover { background: #f04a18; }
.btn.ghost { background: transparent; color: var(--ink); border: 1px solid var(--line); }
.btn.ghost:hover { border-color: var(--ink); background: transparent; }
.btn[disabled] { opacity: .5; cursor: not-allowed; transform: none; }

/* ---------- hero ---------- */
.hero { padding: 86px 0 34px; position: relative; }
.hero-grid {
  display: grid; grid-template-columns: 1.15fr .85fr; gap: 40px; align-items: center;
}
.hero h1 {
  margin: 0 0 26px;
  font-size: clamp(40px, 6.4vw, 88px);
  line-height: .98; letter-spacing: -.03em;
}
.hero h1 em { font-style: italic; color: var(--accent); }
.hero .sub {
  max-width: 46ch; margin: 0 0 32px;
  font-size: clamp(16px, 1.4vw, 18px); color: var(--ink-soft);
}
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; }

/* ---------- hero phone mockup ---------- */
.hero-ar { text-align: center; }
.phone {
  position: relative; width: min(240px, 62vw); aspect-ratio: 9 / 19.5;
  margin: 0 auto; border-radius: 34px; border: 9px solid var(--ink);
  background: var(--ink); overflow: hidden;
  box-shadow: 0 26px 60px rgba(14,14,12,.16);
}
.phone-vid { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.phone-cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 14px 16px 16px;
  background: linear-gradient(to top, rgba(0,0,0,.68), transparent);
  color: #fff; display: flex; flex-direction: column; gap: 2px; text-align: left;
}
.phone-cap-name { font-weight: 600; font-size: 13.5px; }
.phone-cap-cat { font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; opacity: .8; }
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero h1, .hero .sub { text-align: center; margin-left: auto; margin-right: auto; }
  .hero-cta { justify-content: center; }
  .hero-ar { margin-top: 8px; }
}
.hero-foot {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 52px; padding-top: 20px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--ink-soft); letter-spacing: .06em;
  text-transform: uppercase; flex-wrap: wrap; gap: 12px;
}
.clock { font-variant-numeric: tabular-nums; }

/* ---------- marquee ---------- */
.marquee {
  overflow: hidden; white-space: nowrap;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  padding: 15px 0; margin: 44px 0 0; background: var(--paper-2);
}
.marquee .track { display: inline-flex; gap: 34px; animation: slide 34s linear infinite; }
.marquee span {
  font-size: 13px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--ink-soft); font-weight: 500;
}
.marquee .sep { color: var(--accent); }
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee .track { animation: none; } }

/* ---------- sections ---------- */
section { padding: 96px 0; }
.sec-head { margin-bottom: 38px; }
.sec-head h2 {
  margin: 12px 0 12px; font-size: clamp(32px, 4.6vw, 58px);
  line-height: 1.02; letter-spacing: -.025em; max-width: 18ch;
}
.sec-head p { margin: 0; color: var(--ink-soft); max-width: 56ch; font-size: 17px; }

/* ---------- filters ---------- */
.filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 22px; }
.chip {
  border: 1px solid var(--line); background: transparent; color: var(--ink-soft);
  border-radius: 999px; padding: 9px 17px; font: inherit; font-size: 14px;
  cursor: pointer; transition: all .2s var(--ease);
}
.chip:hover { border-color: var(--ink); color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.chip .n { opacity: .5; margin-left: 7px; font-variant-numeric: tabular-nums; }

/* ---------- bento ---------- */
.bento {
  display: grid; gap: 14px;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 210px;
  grid-auto-flow: dense;
}
.tile {
  position: relative; overflow: hidden; border-radius: var(--radius);
  background: var(--card); border: 1px solid var(--line);
  grid-column: span 1; grid-row: span 2;
  transition: transform .4s var(--ease), box-shadow .4s var(--ease);
}
.tile:hover { transform: translateY(-4px); box-shadow: 0 18px 44px rgba(14,14,12,.13); }
.tile.wide { grid-column: span 2; grid-row: span 2; }
.tile.tall { grid-column: span 1; grid-row: span 3; }
.tile.big  { grid-column: span 2; grid-row: span 3; }

.tile video, .tile img.poster {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Explicit stacking, not DOM order. The video is inserted as the tile's
   FIRST child (see mount()), which without an explicit z-index leaves the
   poster <img> - later in the DOM - painting on top of it in some browsers'
   compositing paths. That means a fully loaded, actively playing video can
   sit invisibly behind its own poster forever, on some devices and not
   others, regardless of opacity. z-index removes the ambiguity outright. */
.tile video { z-index: 1; }
.tile img.poster { z-index: 0; }
/* Default to visible. A video that has loaded and is already playing must
   never be sitting invisibly behind its own poster because one JS event
   didn't fire - that is exactly the bug this replaced. The "ready" class is
   now a pure cosmetic head-start: a quick fade up from slightly-dim, not a
   gate that can fail closed. */
.tile video { opacity: .92; transition: opacity .3s var(--ease); }
.tile video.ready { opacity: 1; }
.tile { cursor: pointer; }

/* Shown only when autoplay was actually refused by the browser (data saver,
   low power mode, some in-app browsers all do this even when muted) - a
   visible way to start it, instead of a silent static poster forever. */
.tile.needs-tap::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 54px; height: 54px; border-radius: 50%;
  background: rgba(14,14,12,.55) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E") no-repeat center / 22px;
  pointer-events: none;
}
.tile .cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 34px 15px 14px;
  z-index: 2;
  background: linear-gradient(to top, rgba(0,0,0,.78), transparent);
  color: #fff; display: flex; justify-content: space-between; align-items: flex-end;
  gap: 10px; font-size: 13.5px; font-weight: 500;
}
.tile .cat {
  font-size: 10px; letter-spacing: .13em; text-transform: uppercase;
  font-weight: 700; color: #fff; background: rgba(255,255,255,.22);
  padding: 3px 8px; border-radius: 999px; backdrop-filter: blur(6px);
  white-space: nowrap;
}
.more-row { display: flex; justify-content: center; margin-top: 28px; }
.empty { color: var(--ink-soft); padding: 40px 0; }

@media (max-width: 1000px) { .bento { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) {
  .bento { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 168px; }
  .tile.big, .tile.wide { grid-column: span 2; }
  .tile.tall { grid-row: span 2; }
}

/* ---------- process accordion ---------- */
.acc { border-top: 1px solid var(--line); }
.acc .row {
  border-bottom: 1px solid var(--line); padding: 26px 0; cursor: pointer;
  display: grid; grid-template-columns: 62px 1fr auto; gap: 18px; align-items: start;
  transition: opacity .3s;
}
.acc .row .idx { font-size: 13px; color: var(--ink-soft); padding-top: 6px; font-variant-numeric: tabular-nums; }
.acc .row h3 { margin: 0; font-size: clamp(21px, 2.6vw, 30px); letter-spacing: -.02em; }
.acc .row .body {
  max-height: 0; overflow: hidden; opacity: 0;
  transition: max-height .45s var(--ease), opacity .35s var(--ease), margin .45s var(--ease);
  color: var(--ink-soft); max-width: 58ch;
}
.acc .row[aria-expanded="true"] .body { max-height: 220px; opacity: 1; margin-top: 12px; }
.acc .row .plus { font-size: 22px; color: var(--ink-soft); transition: transform .35s var(--ease); }
.acc .row[aria-expanded="true"] .plus { transform: rotate(45deg); }
.acc .tags { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 14px; }
.acc .tags span {
  font-size: 12px; border: 1px solid var(--line); border-radius: 999px;
  padding: 4px 11px; color: var(--ink-soft);
}

/* ---------- pricing ---------- */
.plans { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); }
.plan {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 34px; display: flex; flex-direction: column;
  transition: transform .35s var(--ease), box-shadow .35s var(--ease);
}
.plan:hover { transform: translateY(-4px); box-shadow: 0 20px 46px rgba(14,14,12,.1); }
.plan.featured { border-color: var(--ink); }
.plan .tag {
  align-self: flex-start; font-size: 10px; font-weight: 700;
  letter-spacing: .13em; text-transform: uppercase;
  background: var(--accent); color: #fff; padding: 5px 11px;
  border-radius: 999px; margin-bottom: 16px;
}
.plan h3 { margin: 0 0 6px; font-size: 26px; letter-spacing: -.02em; }
.plan .blurb { color: var(--ink-soft); margin: 0 0 22px; }
.price { display: flex; align-items: baseline; gap: 9px; }
.price .amt { font-size: 54px; letter-spacing: -.035em; }
.price .per { color: var(--ink-soft); font-size: 14px; }
.turnaround { color: var(--ink-soft); font-size: 14px; margin: 6px 0 24px; }
.plan ul { list-style: none; margin: 0 0 26px; padding: 0; display: grid; gap: 11px; }
.plan li { position: relative; padding-left: 26px; font-size: 15px; }
.plan li::before {
  content: ""; position: absolute; left: 3px; top: 9px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--accent);
}
.plan .btn { width: 100%; margin-top: auto; }
.pay-note { text-align: center; color: var(--ink-soft); font-size: 13.5px; margin-top: 20px; }

/* ---------- faq ---------- */
.faq { display: grid; gap: 10px; }
.faq details {
  background: var(--card); border: 1px solid var(--line);
  border-radius: 12px; padding: 19px 22px;
}
.faq summary { cursor: pointer; font-weight: 500; list-style: none; display: flex; justify-content: space-between; gap: 14px; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--ink-soft); }
.faq details[open] summary::after { content: "\2212"; }
.faq p { margin: 12px 0 0; color: var(--ink-soft); }

/* ---------- cta band ---------- */
.band {
  background: var(--ink); color: var(--paper);
  border-radius: 26px; padding: 66px 44px; text-align: center;
}
.band h2 { margin: 0 0 14px; font-size: clamp(30px, 4.4vw, 52px); letter-spacing: -.025em; }
.band p { color: #a8a79f; margin: 0 auto 26px; max-width: 46ch; }
.band .btn { background: var(--paper); color: var(--ink); }
.band .btn:hover { background: #fff; }

footer {
  padding: 44px 0 60px; border-top: 1px solid var(--line);
  color: var(--ink-soft); font-size: 14px;
  display: flex; gap: 18px; flex-wrap: wrap; align-items: center;
}
footer .spacer { flex: 1; }
footer a:hover { color: var(--ink); }

/* ---------- modal ---------- */
.modal {
  position: fixed; inset: 0; z-index: 100; padding: 20px;
  background: rgba(14,14,12,.5); backdrop-filter: blur(5px);
  display: grid; place-items: center;
}
.modal[hidden] { display: none; }
.modal .box {
  background: var(--card); border-radius: 20px; padding: 32px;
  width: min(460px, 100%); border: 1px solid var(--line);
}
.modal h3 { margin: 0 0 6px; font-size: 27px; letter-spacing: -.02em; }
.modal p.small { color: var(--ink-soft); font-size: 14.5px; margin: 0 0 22px; }
.field { display: grid; gap: 6px; margin-bottom: 15px; }
.field label { font-size: 13px; color: var(--ink-soft); }
.field input {
  background: var(--paper); border: 1px solid var(--line); color: var(--ink);
  border-radius: 11px; padding: 13px 14px; font: inherit;
}
.field input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
.modal .row { display: flex; gap: 10px; margin-top: 6px; }
.modal .row .btn { flex: 1; }
.err { color: #c0341a; font-size: 14px; min-height: 20px; }
.wait { color: var(--ink-soft); font-size: 14px; min-height: 20px; }

/* ---------- narrow screens ----------
   The nav links overflowed the header below ~700px, pushing the page wider
   than the viewport. Brand and the one CTA are what matter on a phone. */
@media (max-width: 760px) {
  .nav { gap: 16px; height: 64px; }
  .nav a.link { display: none; }
  /* Sign-in is a real destination with no other path on a phone, unlike the
     scroll-anchor links (Work/Process/etc) it's collapsed alongside. */
  .nav a.link.persist { display: inline-flex; font-size: 14px; white-space: nowrap; }
  /* The header's own "Start a build" button only exists on index.html, where
     the fixed .mobile-cta bar already covers that action on a phone, drop
     the duplicate so "My builds" has room instead of wrapping. */
  .nav .btn { display: none; }
  .wrap { padding: 0 18px; }
  section { padding: 64px 0; }
  .hero { padding: 54px 0 26px; }
}

@media (max-width: 560px) {
  .hero-foot {
    flex-direction: column; align-items: flex-start; gap: 7px;
    font-size: 11px;
  }
  .hero-cta { flex-direction: column; align-items: stretch; }
  .hero-cta .btn { width: 100%; }
  .band { padding: 46px 22px; border-radius: 18px; }
  .plan { padding: 26px; }
  .acc .row { grid-template-columns: 40px 1fr auto; gap: 12px; }
  .modal .box { padding: 24px; }
}

/* a phone should always have the buy action within thumb reach */
.mobile-cta { display: none; }
@media (max-width: 760px) {
  .mobile-cta {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 55;
    background: rgba(247,246,243,.95); backdrop-filter: blur(12px);
    border-top: 1px solid var(--line); gap: 10px; align-items: center;
    padding: 12px 18px calc(12px + env(safe-area-inset-bottom, 0px));
  }
  .mobile-cta .price-min { flex: 1; font-size: 13.5px; color: var(--ink-soft); }
  .mobile-cta .btn { padding: 12px 20px; }
  body { padding-bottom: 74px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .reveal { opacity: 1; transform: none; }
}

/* ---------- cursor glow + click ripple ----------
   Applied by fx.js via event delegation, so it reaches elements the page's
   own JS renders later (bento tiles, plan cards, category grid) without
   those scripts needing to know this exists. A soft radial-gradient burst
   rather than a hard-edged Material ripple, so it never needs its own
   clipping and can't visibly poke past a rounded corner. */
.btn, .chip, .plan, .tile, .cat, .ref, .way, .card, .opt-card, .gbtn, .linkbtn {
  position: relative;
  overflow: hidden;
}
.btn::before, .chip::before, .plan::before, .tile::before, .cat::before,
.ref::before, .way::before, .card::before, .opt-card::before, .gbtn::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: radial-gradient(circle at var(--mx,50%) var(--my,50%), rgba(255,92,43,.16), transparent 55%);
  opacity: 0; transition: opacity .25s var(--ease);
}
.btn:hover::before, .chip:hover::before, .plan:hover::before, .tile:hover::before,
.cat:hover::before, .ref:hover::before, .way:hover::before, .card:hover::before,
.opt-card:hover::before, .gbtn:hover::before {
  opacity: 1;
}
.fx-ripple {
  position: absolute; z-index: 1; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255,92,43,.32), rgba(255,92,43,0) 70%);
  transform: scale(0); opacity: 1;
  animation: fxRipple .55s var(--ease) forwards;
}
@keyframes fxRipple { to { transform: scale(1); opacity: 0; } }

/* ---------- region picker ----------
   A small, dismissible bar rather than a modal: the Cloudflare middleware
   already routes Indian visitors to /in/, so this exists for the cases geo
   gets wrong (VPN, NRI, an Indian agency billing a client abroad) and must
   not block anyone who does not need it. */
.regionbar {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  flex-wrap: wrap; padding: 9px 18px; font-size: 13.5px;
  background: var(--ink); color: var(--paper);
}
.regionbar .rb-txt { opacity: .85; }
.regionbar select {
  font: inherit; font-size: 13.5px; padding: 5px 10px; border-radius: 8px;
  border: 1px solid rgba(247,246,243,.28); background: transparent;
  color: var(--paper); cursor: pointer;
}
/* The popup is painted by the OS/browser, not by the bar, and on a dark
   system theme it defaults to a dark background - which made these options
   dark-on-dark and invisible until hovered. Both colours are set explicitly
   so the list is readable regardless of the visitor's theme. */
.regionbar select option,
.regionbar select optgroup {
  color: #0e0e0c;
  background: #ffffff;
}
.regionbar select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.regionbar .rb-cur { opacity: .7; font-size: 12.5px; }
.regionbar .rb-x {
  background: none; border: 0; color: var(--paper); opacity: .6;
  font-size: 16px; line-height: 1; cursor: pointer; padding: 2px 4px;
}
.regionbar .rb-x:hover { opacity: 1; }
@media (max-width: 560px) { .regionbar { font-size: 12.5px; gap: 8px; } }
