/* webify — Weft. One rule becomes many rules becomes the word. */

:root {
  --bg: #08090c;
  --bg-lift: #10141b;
  --bg-far: #0a0b10;
  --rule: #262a33;
  --lime: #b8ff3c;
  --cyan: #3cf0ff;
  --fg: #e8ecea;
  --muted: #7e8790;
  --ul-rest: rgba(184, 255, 60, 0.3);

  --display: "Archivo Black", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --pad-x: 20px;
  --pad-x: clamp(20px, 3.2vw, 40px);
  --pad-t: var(--pad-x);
  --pad-r: var(--pad-x);
  --pad-b: var(--pad-x);
  --pad-l: var(--pad-x);
  --pad-t: max(var(--pad-x), env(safe-area-inset-top));
  --pad-r: max(var(--pad-x), env(safe-area-inset-right));
  --pad-b: max(var(--pad-x), env(safe-area-inset-bottom));
  --pad-l: max(var(--pad-x), env(safe-area-inset-left));

  --gap-desc: clamp(22px, 3vh, 34px);
  --frame-i: clamp(14px, 2.2vw, 26px);
  --tick: clamp(12px, 1.1vw, 16px);
  /* lifted from the old #262A33: at 1px on a dim OLED that value was ~1.4:1
     and the frame simply vanished */
  --tick-c: rgba(232, 236, 234, 0.2);
  --wm-max: clamp(6rem, 30vw, 18.5rem);
  --fit-bias: 0.46;

  --grain-a: 0.05;
  --bloom-w: 62%;
  --bloom-h: 26%;

  /* written once per bake by JS */
  --mark-l: 20px;
  --mark-w: 335px;
  --canvas-top: 0px;
  --canvas-h: 0px;
  --support-y: 60%;
  --baseline-y: 44%;
  --bloom-y: 40%;
}

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

html,
body {
  height: 100%;
  margin: 0;
  background: var(--bg);
}

body {
  position: fixed;
  inset: 0;
  overflow: hidden;
  overscroll-behavior: none;
  touch-action: manipulation;
  font-family: var(--mono);
  font-weight: 400;
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── atmosphere ─────────────────────────────────────────────── */

.atmos {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 900ms linear 200ms;
  background:
    radial-gradient(120% 55% at 50% var(--baseline-y), rgba(14, 59, 68, 0.2) 0%, rgba(14, 59, 68, 0) 60%),
    radial-gradient(
      var(--bloom-w) var(--bloom-h) at 44% var(--bloom-y),
      rgba(14, 59, 68, 0.55) 0%,
      rgba(14, 59, 68, 0.16) 48%,
      rgba(14, 59, 68, 0) 72%
    ),
    radial-gradient(130% 85% at 50% 47%, var(--bg-lift) 0%, var(--bg-far) 45%, var(--bg) 100%);
}

.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 800ms linear 300ms;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

.go .atmos {
  opacity: 1;
}

.go .grain {
  opacity: var(--grain-a);
}

/* ── stage ──────────────────────────────────────────────────── */

.stage {
  position: absolute;
  inset: 0;
  z-index: 2;
  padding: var(--pad-t) var(--pad-r) var(--pad-b) var(--pad-l);
}

.wm {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.mark {
  position: absolute;
  left: 0;
  top: var(--canvas-top);
  width: 100%;
  height: var(--canvas-h);
  pointer-events: none;
}

/* the caliper: pinned to the mark's measured extremes, never to a clamp() */
.support {
  position: absolute;
  left: var(--mark-l);
  top: var(--support-y);
  width: var(--mark-w);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  font-size: clamp(0.625rem, 0.42vw + 0.53rem, 0.8125rem);
  line-height: 1;
  color: var(--muted);
}

.support p {
  margin: 0;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 500ms cubic-bezier(0.16, 1, 0.3, 1), transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.support p.tagline {
  text-transform: uppercase;
  letter-spacing: 0.22em;
  transition-delay: 950ms;
}

.support p.services {
  align-self: flex-end;
  text-align: right;
  letter-spacing: 0.2em;
  margin-right: -0.2em;
  white-space: nowrap;
  transition-delay: 1030ms;
}

.services i {
  font-style: normal;
  color: var(--cyan);
}

.go .support p {
  opacity: 1;
  transform: none;
}

/* ── contact: the only door in the room ─────────────────────── */

.contact {
  position: absolute;
  left: var(--pad-l);
  bottom: var(--pad-b);
  display: inline-block;
  padding: 15px 10px;
  margin: -15px -10px;
  line-height: 1;
  font-size: clamp(0.8125rem, 0.9375rem - 0.14vw, 0.90625rem);
  letter-spacing: 0.02em;
  color: var(--fg);
  text-decoration: none;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 500ms cubic-bezier(0.16, 1, 0.3, 1) 1110ms,
    transform 500ms cubic-bezier(0.16, 1, 0.3, 1) 1110ms;
}

.go .contact {
  opacity: 1;
  transform: none;
}

.contact::after {
  content: "";
}

.contact::after,
.contact .ul {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 9px;
  height: 1px;
}

.contact::after {
  background: var(--ul-rest);
}

.contact .ul {
  background: var(--lime);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}

.contact:hover .ul,
.contact:focus-visible .ul,
.contact:active .ul {
  transform: scaleX(1);
}

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

/* ── frame ──────────────────────────────────────────────────── */

.frame {
  position: fixed;
  inset: var(--frame-i);
  inset: max(var(--frame-i), env(safe-area-inset-top)) max(var(--frame-i), env(safe-area-inset-right))
    max(var(--frame-i), env(safe-area-inset-bottom)) max(var(--frame-i), env(safe-area-inset-left));
  z-index: 3;
  pointer-events: none;
}

.tick {
  position: absolute;
  width: var(--tick);
  height: var(--tick);
  opacity: 0;
  transition: opacity 480ms cubic-bezier(0.16, 1, 0.3, 1) 1110ms;
}

.go .tick {
  opacity: 1;
}

.tl {
  top: 0;
  left: 0;
  border-top: 1px solid var(--lime);
  border-left: 1px solid var(--lime);
}

.tr {
  top: 0;
  right: 0;
  border-top: 1px solid var(--tick-c);
  border-right: 1px solid var(--tick-c);
}

.bl {
  bottom: 0;
  left: 0;
  border-bottom: 1px solid var(--tick-c);
  border-left: 1px solid var(--tick-c);
}

.br {
  bottom: 0;
  right: 0;
  border-bottom: 1px solid var(--tick-c);
  border-right: 1px solid var(--tick-c);
}

/* the lime tick stays in the SAME corner at every size — a wandering accent
   reads as a bug. It and the lime tittle are the page's only chromatic axis. */
.go .tl {
  opacity: 0.9;
}

/* four brackets on a 375px screen reads busy: keep the diagonal pair */
@media (max-width: 640px), (max-height: 460px) {
  .tr,
  .bl {
    display: none;
  }
}

.metrics {
  position: absolute;
  top: 0;
  left: 0;
  visibility: hidden;
  pointer-events: none;
  padding: var(--pad-t) var(--pad-r) var(--pad-b) var(--pad-l);
}

.metrics i {
  display: block;
  font-size: var(--wm-max);
  width: var(--gap-desc);
  height: var(--tick);
}

/* ── desktop ────────────────────────────────────────────────── */

@media (min-width: 641px) {
  :root {
    --fit-bias: 0.38;
    --grain-a: 0.04;
    --bloom-w: 46%;
    --bloom-h: 34%;
  }

  .support {
    flex-direction: row;
    justify-content: space-between;
    align-items: baseline;
    gap: 1.5em;
  }

  .support p.services {
    align-self: baseline;
  }

  .contact {
    left: auto;
    right: var(--pad-r);
    /* padding + cancelling margin keeps a >=44px hit area while the optical
       edge still sits on the page inset */
    padding: 16px 6px;
    margin: -16px -6px;
  }

  .contact::after,
  .contact .ul {
    left: 6px;
    right: 6px;
    bottom: 10px;
  }





}

/* ── tall portrait: phone and tablet ─────────────────────────── */

@media (max-aspect-ratio: 4 / 5) {
  :root {
    --fit-bias: 0.5;
  }
}

/* ── landscape phone ────────────────────────────────────────── */

@media (max-height: 460px) {
  :root {
    --pad-x: 14px;
    --gap-desc: 14px;
    --fit-bias: 0.4;
    --wm-max: clamp(3.25rem, 26vh, 11rem);
  }

  .support {
    flex-direction: row;
    justify-content: space-between;
    align-items: baseline;
    gap: 1.5em;
  }

  .support p.services {
    align-self: baseline;
  }

  .contact {
    left: auto;
    right: var(--pad-r);
    padding: 15px 6px;
    margin: -15px -6px;
  }

  .contact::after,
  .contact .ul {
    left: 6px;
    right: 6px;
    bottom: 9px;
  }




}

/* ── degraded: no JS, no canvas, poisoned canvas ────────────── */

/* No stripe mask here on purpose. Faking the weave in CSS produced stray bars
   past the letterforms and a broken "if" cluster — a solid gradient wordmark
   plus the rule is a reduced identity, not a rendering bug. */

.nocanvas .mark {
  display: none;
}

.nocanvas .wm {
  position: static;
  width: auto;
  height: auto;
  clip-path: none;
  overflow: visible;
  font: 400 var(--wm-max) / 0.95 var(--display);
  letter-spacing: -0.028em;
  text-align: center;
  margin: 0 auto;
  padding-top: 26vh;
  color: var(--fg);
  background-image: linear-gradient(
    90deg,
    #b8ff3c 0%,
    #d6ff7a 30%,
    #eafbf3 55%,
    #7fe9f5 78%,
    #3cf0ff 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .nocanvas .wm {
    color: transparent;
  }
}

.nocanvas .support {
  position: static;
  width: auto;
  margin-top: var(--gap-desc);
  flex-direction: row;
  justify-content: center;
  gap: 2em;
}

.nocanvas .support p.services {
  align-self: baseline;
  text-align: center;
}

/* the seed rule still has to exist — it is the spine of the composition */
.nocanvas .stage::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  /* sit on the fallback word's baseline, not an arbitrary 47%, or the rule
     reads as a strikethrough */
  top: calc(26vh + var(--wm-max) * 0.76);
  height: 1px;
  background: var(--rule);
}

/* ── reduced motion ─────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  /* The staggered entrance collapses into one 400ms cross-fade. Nothing
     translates; a cross-fade is within reduced-motion etiquette, a transform
     is not. Everything else — rule, bloom, grain, ghost, layout — is
     byte-identical to the animated build. */
  .mark,
  .support p,
  .contact,
  .tick {
    transition: none;
    transform: none;
    opacity: 1;
  }

  .atmos,
  .grain {
    transition: opacity 400ms linear;
  }

  .stage {
    opacity: 0;
    transition: opacity 400ms linear;
  }

  .go .stage {
    opacity: 1;
  }

  /* a discrete, user-initiated state change is not a motion hazard, and
     removing it would break the only affordance on the page */
  .contact .ul {
    transform: scaleX(0);
    transition: transform 120ms linear;
  }

  .contact:hover .ul,
  .contact:focus-visible .ul,
  .contact:active .ul {
    transform: scaleX(1);
  }
}
