/* ============================================================
   XQUBE GLOBAL — CONTACT & FAQ
   The threshold. The film's closing frame: the page opens on the
   world, hands over the real numbers, lights the eleven states,
   answers six questions without hurrying, and rests on the mark.
   Page-specific only — everything else is css/main.css.
   ============================================================ */

/* ---------- you are here ---------- */
.nav-links a.is-here { color: var(--text); }
.nav-links a.is-here::after { transform: scaleX(1); opacity: 0.55; }
.mobile-links a.is-here { color: var(--text); }
.mobile-links a.is-here .mono { color: var(--pink-soft); }

/* ============================================================
   SCENE — THE THRESHOLD
   Registered as the page's prologue so the number-field builds;
   the world formation is 'globe', the bookend the film opened on.
   ============================================================ */
section[data-scene="prologue"] { height: 200vh; }
@media (max-width: 980px) { section[data-scene="prologue"] { height: auto; } }

/* HEADER FIX: the brief makes this hero ~980px tall — taller than one screen.
   Pinned at 100svh with overflow:hidden, the base stage centred that block and
   slid the eyebrow and the top of the headline up UNDER the fixed nav (and
   clipped the form's foot). No alignment fixes that while the stage clips at one
   screen, so on desktop the threshold now flows to its own height exactly like
   it already does on mobile: min-height fills the screen when the content is
   short, the box grows when it is tall, and the nav padding keeps the headline
   clear either way. The reveal is timer-driven (--introop), not scroll-driven,
   so it needs no pinned scroll room, and the number-field is a fixed canvas
   behind all of it. */
@media (min-width: 981px) {
  section[data-scene="prologue"] { height: auto; }
  .threshold-stage {
    position: static;
    height: auto; min-height: 100svh;
    overflow: visible;
  }
}

/* the world turns behind every line on this page, so each block of
   type carries its own vignette — the copy always wins, the world
   is never switched off to make that happen */
.threshold-stage::before,
.faq::before,
.desk::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 0;
}
.threshold-stage::before {
  background:
    radial-gradient(54% 44% at 50% 48%, rgba(10, 10, 14, 0.86), rgba(10, 10, 14, 0.44) 58%, transparent 82%),
    radial-gradient(50% 42% at 50% 26%, rgba(91, 76, 255, 0.13), transparent 68%),
    radial-gradient(46% 40% at 62% 78%, rgba(255, 77, 128, 0.075), transparent 64%);
}
.desk::before {
  background: radial-gradient(62% 46% at 50% 52%, rgba(10, 10, 14, 0.7), rgba(10, 10, 14, 0.3) 62%, transparent 86%);
}
.faq::before {
  background: radial-gradient(64% 44% at 50% 50%, rgba(10, 10, 14, 0.9), rgba(10, 10, 14, 0.6) 58%, transparent 88%);
}
.threshold-content {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  width: 100%;
  max-width: 1080px;
}
/* the eyebrow sits inside the turning globe, so it gets a chip of its
   own rather than fighting the place names for the same pixels */
.threshold-content .kicker-center {
  position: relative;
  width: fit-content;
  padding: 9px 20px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: rgba(10, 10, 14, 0.74);
  backdrop-filter: blur(10px) saturate(150%);
  -webkit-backdrop-filter: blur(10px) saturate(150%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07);
}
.threshold-h1 {
  font-size: clamp(40px, 6.2vw, 92px);
  line-height: 1.05;
  letter-spacing: -0.03em;
  max-width: 13ch;
  margin: 0 auto;
}
.threshold-rest {
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(28px, 4.4vh, 48px);
  margin-top: clamp(34px, 5.5vh, 68px);
  width: 100%;
}
.js .threshold-rest {
  opacity: var(--introop, 0);
  transform: translateY(calc((1 - var(--introop, 0)) * 30px));
}
.threshold-rest .lede-center { max-width: 56ch; }

@media (max-width: 980px) {
  .threshold-h1 { font-size: clamp(36px, 9.2vw, 54px); max-width: 100%; }
  .threshold-stage .scroll-cue { display: none; }
}

/* ============================================================
   THE DESK — the real numbers, given room.
   ============================================================ */
.desk-grid {
  display: grid;
  grid-template-columns: 1.12fr 0.88fr;
  gap: clamp(44px, 6vw, 104px);
  align-items: start;
}
.desk-lines { display: flex; flex-direction: column; }
.desk-row {
  display: grid;
  grid-template-columns: 128px 1fr;
  gap: var(--s3);
  align-items: baseline;
  padding: var(--s4) 0;
  border-top: 1px solid var(--line);
}
.desk-lines .desk-row:last-child { border-bottom: 1px solid var(--line); }
.desk-label {
  font-size: 10.5px; letter-spacing: 0.24em;
  color: var(--faint);
}
.desk-value { display: flex; flex-direction: column; gap: 10px; }
.desk-link {
  position: relative;
  width: fit-content;
  font-size: clamp(19px, 2.1vw, 27px);
  letter-spacing: -0.01em;
  color: var(--text);
  transform: translate(var(--mtx, 0px), var(--mty, 0px));
  transition: transform 0.22s cubic-bezier(0.3, 0.7, 0.3, 1), color 0.3s ease;
}
.desk-link::after {
  content: "";
  position: absolute; left: 0; bottom: -4px;
  width: 100%; height: 1px;
  background: linear-gradient(90deg, var(--purple), var(--pink));
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 0.4s cubic-bezier(0.3, 0.7, 0.3, 1);
}
.desk-link:hover::after,
.desk-link:focus-visible::after { transform: scaleX(1); }
.desk-link-accent { color: var(--pink-soft); }
.desk-text {
  font-size: clamp(19px, 2.1vw, 27px);
  letter-spacing: -0.01em;
  color: var(--text);
}

/* the clocks panel */
.desk-clocks {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
  padding: var(--s4) var(--s4) var(--s3);
  overflow: hidden;
}
.desk-clocks-head {
  font-size: 10.5px; letter-spacing: 0.24em;
  color: var(--faint);
  margin-bottom: var(--s2);
}
/* seven zones now, read west to east: a horizontal strip of small pills that
   wraps within the card rather than a tall stacked list. Left-to-right IS the
   geography — HST at the west end, IST at the east. */
.contact-clocks {
  display: flex; flex-flow: row wrap;
  gap: 7px;
  margin-top: 4px;
}
.contact-clocks .clock {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: rgba(255, 255, 255, 0.022);
  padding: 7px 12px;
  font-size: 10px; letter-spacing: 0.14em;
}
.contact-clocks .clock-dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--faint);
  transition: background 0.4s ease, box-shadow 0.4s ease;
}
.contact-clocks .clock-city { color: var(--mist); }
.contact-clocks .clock-time {
  font-size: 12.5px; letter-spacing: 0.02em;
  color: var(--text);
}
/* the zone lights when it is inside working hours right now */
.contact-clocks .clock.is-open .clock-city { color: var(--text); }
.contact-clocks .clock.is-open .clock-dot {
  background: var(--pink);
  box-shadow: 0 0 8px rgba(255, 77, 128, 0.85);
}
.clock-legend {
  display: flex; align-items: center; gap: 12px;
  border-top: 1px solid var(--line);
  padding-top: 14px; margin-top: 4px;
  font-size: 10px; letter-spacing: 0.2em;
  color: var(--faint);
}
.clock-dot-lit {
  background: var(--pink);
  box-shadow: 0 0 10px rgba(255, 77, 128, 0.9);
}

@media (max-width: 980px) {
  .desk-grid { grid-template-columns: 1fr; gap: var(--s6); }
  .desk-row { grid-template-columns: 1fr; gap: 10px; padding: var(--s3) 0; }
}

/* ============================================================
   SCENE — US PRESENCE
   Eleven states, set quietly, lit one by one as the scroll
   crosses them. Behind them the world writes the figure 11.
   ============================================================ */
section[data-scene="presence"] { height: 250vh; }
.presence-stage { justify-content: center; }
.presence-wrap { position: relative; z-index: 2; width: 100%; }
.presence-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px;
  font-size: 11px; letter-spacing: 0.26em;
  color: var(--faint);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--s3);
  margin-bottom: clamp(32px, 6vh, 64px);
}
.presence-count em { font-style: normal; color: var(--purple-soft); }
.presence-line {
  font-size: clamp(24px, 3.5vw, 46px);
  line-height: 1.34;
  font-weight: 500;
  letter-spacing: -0.022em;
  color: rgba(166, 170, 184, 0.26);
  max-width: 1060px;
}
.us-state {
  color: var(--text);
  transition: color 0.55s ease, text-shadow 0.55s ease;
}
.js .us-state { color: rgba(166, 170, 184, 0.26); }
.js .us-state.lit { color: var(--text); }
.js .us-state.hot { color: var(--pink); text-shadow: 0 0 30px rgba(255, 77, 128, 0.4); }

@media (max-width: 980px) {
  section[data-scene="presence"] { height: auto; }
  section[data-scene="presence"] .scene-stage {
    position: static; height: auto; overflow: visible;
    padding-top: var(--section-gap); padding-bottom: 0;
  }
  .presence-line { font-size: clamp(21px, 5.4vw, 30px); }

  /* THE BEAM, ON A PHONE.
     The row was printed flat here — eleven states plain white from the frame
     the section appeared — because the scene is unpinned at this width and
     scene progress collapses to a single step, so the sweep had nothing to
     run on. js/contact.js now drives the same sweep from the section's travel
     across the screen, so the effect can come back.

     It comes back behind html.us-live, and behind nothing else. That class is
     set by the mobile branch of the presence scene itself, one screen before
     the row is visible. So the dimmed resting state below cannot outlive the
     code that lights it: no engine, no class, and these three rules never
     apply — leaving the flat white above, which is the no-JS state. This page
     does not gamble approved copy on an animation that may not run. */
  .js .us-state,
  .js .us-state.lit,
  .js .us-state.hot { color: var(--text); text-shadow: none; }
  .js.us-live .us-state { color: rgba(166, 170, 184, 0.26); }
  .js.us-live .us-state.lit { color: var(--text); }
  /* 20px of glow rather than the desktop 30px: the type is a little over half
     the size here, so the halo keeps its proportion to the word — and a
     smaller blur radius is a smaller repaint on the one device that has to
     pay for it while scrolling. */
  .js.us-live .us-state.hot { color: var(--pink); text-shadow: 0 0 20px rgba(255, 77, 128, 0.4); }
}
@media (prefers-reduced-motion: reduce) {
  /* js/main.js reads prefers-reduced-motion ONCE at boot and never calls a
     scene function when it is set, so us-live should be unreachable here.
     "Should be" is not good enough for the one class that dims copy: a reader
     who turns reduced motion on mid-session gets this stylesheet immediately
     while the engine carries on with the value it booted with. Name the class
     explicitly so the flatten wins either way. */
  .js .us-state,
  .js .us-state.lit,
  .js .us-state.hot,
  .js.us-live .us-state,
  .js.us-live .us-state.lit,
  .js.us-live .us-state.hot { color: var(--text); text-shadow: none; }
  .js .threshold-rest { opacity: 1; transform: none; }
}
.no-js .threshold-rest { opacity: 1; transform: none; }

/* ============================================================
   COMMON QUESTIONS — a numbered accordion.
   Real buttons, real aria-expanded. Without JS every answer is
   simply open, because an unanswerable page is worse than a
   static one.
   ============================================================ */
.faq .ghost-num { top: 6%; }
.faq-h2 { margin-bottom: clamp(40px, 6vh, 72px); }
.faq-list { border-top: 1px solid var(--line); }
.faq-item { border-bottom: 1px solid var(--line); }
.faq-h { margin: 0; font-size: inherit; font-weight: inherit; }

.faq-q {
  display: grid;
  grid-template-columns: 88px 1fr 20px;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: clamp(22px, 2.6vh, 30px) 0;
  border: 0;
  background: none;
  color: inherit;
  font-family: var(--sans);
  text-align: left;
  cursor: pointer;
  transition: padding-left 0.4s cubic-bezier(0.3, 0.7, 0.3, 1);
}
.js .faq-q:hover { padding-left: 10px; }
.faq-i {
  font-size: 11.5px; letter-spacing: 0.1em;
  color: var(--purple-soft);
  transition: color 0.35s ease;
}
.faq-i i { font-style: normal; color: var(--faint); }
.faq-t {
  font-size: clamp(17px, 1.9vw, 23px);
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.015em;
  color: var(--mist);
  transition: color 0.35s ease;
}
.faq-q:hover .faq-t,
.faq-q:focus-visible .faq-t { color: var(--text); }
.faq-item.open .faq-t { color: var(--text); }
.faq-item.open .faq-i { color: var(--pink-soft); }

.faq-x { position: relative; width: 16px; height: 16px; justify-self: end; }
.faq-x::before, .faq-x::after {
  content: "";
  position: absolute; left: 0; top: calc(50% - 0.75px);
  width: 16px; height: 1.5px;
  background: var(--faint);
  transition: transform 0.45s cubic-bezier(0.3, 0.7, 0.3, 1), background 0.35s ease;
}
.faq-x::after { transform: rotate(90deg); }
.faq-item.open .faq-x::before,
.faq-item.open .faq-x::after { background: var(--pink); }
.faq-item.open .faq-x::after { transform: rotate(0deg); }
.no-js .faq-x { display: none; }
.no-js .faq-q { cursor: default; }

/* the closing space lives on the last paragraph, not on the panel:
   padding on a collapsed grid row is not clipped, and would leave a
   phantom gap under every shut question */
.faq-a-in { padding: 0; }
.faq-a-in > p:last-child { margin-bottom: clamp(24px, 3vh, 34px); }
.faq-a-in p {
  font-size: clamp(15.5px, 1.35vw, 17.5px);
  line-height: 1.8;
  color: var(--mist);
  max-width: 64ch;
  padding-left: calc(88px + var(--s3));
  border-left: 1px solid transparent;
}
.faq-a-in p + p { margin-top: 14px; }
.faq-item.open .faq-a-in p:first-child { border-left-color: rgba(255, 77, 128, 0.35); }

.js .faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s cubic-bezier(0.22, 0.6, 0.2, 1);
}
/* SAFETY: html.js is asserted in the <head>, but only js/contact.js ever adds
   .open. If it throws or fails to load while the shared engine is fine, all six
   approved FAQ answers collapse to zero height with no way to open them. The
   script adds .faq-ready once its listeners are bound; until then the answers
   stand open, which is also the no-JS state. */
.js:not(.faq-ready) .faq-a { display: block; grid-template-rows: none; }
.js:not(.faq-ready) .faq-a > .faq-a-in { opacity: 1; visibility: visible; overflow: visible; }
.js .faq-a > .faq-a-in {
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0s linear 0.45s;
}
.js .faq-item.open .faq-a { grid-template-rows: 1fr; }
.js .faq-item.open .faq-a > .faq-a-in {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.45s ease 0.12s, visibility 0s;
}

@media (max-width: 700px) {
  /* the ghost numeral lands on the section heading at this width —
     better absent than colliding */
  .faq .ghost-num { display: none; }
  .faq-q { grid-template-columns: 58px 1fr 18px; gap: var(--s2); }
  .faq-i { font-size: 10.5px; letter-spacing: 0.06em; }
  .faq-i i { display: none; }
  .faq-a-in p { padding-left: calc(58px + var(--s2)); }
}

/* ============================================================
   THE CLOSING FRAME — the world reassembles the mark, and the
   only thing left on the page is a way to reach a person.
   ============================================================ */
.close-band { text-align: center; }
.close-inner {
  display: flex; flex-direction: column; align-items: center;
  min-height: 42vh;
  justify-content: center;
}
.close-rule {
  display: block;
  width: 1px; height: clamp(56px, 9vh, 104px);
  background: linear-gradient(180deg, transparent, var(--purple-soft), transparent);
  opacity: 0.7;
}
.close-band .contact-chips { margin-top: var(--s5); }

/* ============================================================
   THE BRIEF — the form
   The approved line asks for the business, the setup and the problem,
   so the form asks for those and nothing else. Set as ruled entries
   rather than boxed inputs: this site draws hairlines, not widgets,
   and a bordered field-set here would look like a different website.
   Fully usable with no JS — it is a real <form> with a real action.
   ============================================================ */
.brief {
  width: min(560px, 100%);
  margin: clamp(28px, 4.4vh, 46px) auto 0;
  text-align: left;
}
.brief-head {
  font-size: 10px; letter-spacing: 0.24em;
  color: var(--faint);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--line);
}
.brief-row {
  display: grid;
  grid-template-columns: 148px minmax(0, 1fr);
  align-items: baseline;
  gap: 0 clamp(12px, 2vw, 22px);
  padding: clamp(13px, 1.8vh, 18px) 0;
  border-bottom: 1px solid var(--line);
}
.brief-row-tall { align-items: start; }
.brief-lab {
  font-size: 9.5px; letter-spacing: 0.2em;
  color: var(--faint);
  padding-top: 4px;
}
.brief-in {
  width: 100%;
  background: none;
  border: 0;
  padding: 0;
  color: var(--text);
  font-family: inherit;
  font-size: 15.5px;
  line-height: 1.6;
  letter-spacing: -0.008em;
}
.brief-in::placeholder { color: rgba(135, 140, 156, 0.7); }
.brief-in:focus { outline: none; }
/* the rule under the row is the focus ring — no glowing box */
.brief-row:focus-within { border-bottom-color: var(--purple); }
.brief-row:focus-within .brief-lab { color: var(--purple-soft); }
.brief-area { resize: vertical; min-height: 92px; }
/* only after a real attempt, so it never scolds an untouched field */
.brief-in:user-invalid { color: var(--pink); }
.brief-row:has(.brief-in:user-invalid) { border-bottom-color: var(--pink); }

.brief-foot {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--s3);
  margin-top: clamp(20px, 3vh, 30px);
}
.brief-note {
  font-size: 9.5px; letter-spacing: 0.18em;
  color: var(--faint);
}
.brief-note.is-sent { color: var(--purple-soft); }

/* iOS Safari zooms the whole viewport in whenever a focused control computes
   below 16px, and it does not zoom back out on blur. Every field here was
   15.5px, so tapping YOUR NAME jumped the page to about 110% and the reader
   filled in five fields — and then read the rest of the page — at the wrong
   scale, with the layout running off the side. On the only conversion form
   the site has.
   The other half of the trigger is the viewport meta, which sets no
   maximum-scale. That stays exactly as it is: suppressing the zoom by
   forbidding zoom takes pinch away from anyone who needs it, which is a
   worse page for a real reader in order to spare us half a pixel.
   So: half a pixel. Below the mobile breakpoint, not just below 640px — a
   phone held sideways and a portrait tablet are both over 640 and iOS zooms
   on both. Desktop keeps 15.5px and is untouched. */
@media (max-width: 980px) {
  .brief-in { font-size: 16px; }
}

@media (max-width: 640px) {
  .brief-row { grid-template-columns: 1fr; gap: 6px; }
  .brief-lab { padding-top: 0; }
  .brief-foot { flex-direction: column; align-items: flex-start; }
}
/* the rule is the only affordance, so it must not animate away without JS */
.no-js .brief-row, .no-js .brief-head { border-bottom-color: var(--line); }


/* ============================================================
   GLASS, COSTED FOR A PHONE (page-scoped)
   css/main.css flattens its OWN glass components below 980px, but it cannot
   reach the devices this page declares. backdrop-filter re-blurs everything
   behind an element on every frame it moves, and these sit inside a
   scrolling film — it is the most expensive thing a handset does here.

   Blur removed below 980px. Where the surface was too sheer to survive
   without it (var(--surface) is 3.5% white) an opaque base is added as
   background-COLOR, not background, so any ruled gradient painted on top
   of it is left intact.
   ============================================================ */
@media (max-width: 980px) {
  .threshold-content .kicker-center {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .desk-clocks {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background-color: var(--glass-flat);
  }
}
