/* =========================================================
   Lumora — stylesheet
   Order: tokens → base → chrome (nav) → homepage → sub-pages
          → components → motion → responsive
   ========================================================= */

@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/fonts/BricolageGrotesque.woff2') format('woff2');
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/HankenGrotesk.woff2') format('woff2');
}

/* ---------- Tokens ---------- */

:root {
  /* Palette sampled directly from media/Background.png rather than
     eyeballed — bg is a darkened version of the image's own near-black
     top-center indigo, accent is its vivid coral-red, neutrals carry a
     cool violet bias. */
  --bg: #0c0a16;
  --text: #f4f2fb;
  --text-muted: #a9a2c4;
  --accent: #f8503c;
  --accent-soft: rgba(248, 80, 60, 0.16);
  --accent-dim: rgba(248, 80, 60, 0.5);
  --border: rgba(244, 242, 251, 0.12);
  --border-strong: rgba(244, 242, 251, 0.22);
  --surface: rgba(12, 10, 22, 0.5);
  /* Body copy that sits on the bare image needs to be brighter than the
     muted tone used inside cards, or it vanishes in the pale regions. */
  --text-on-image: rgba(244, 242, 251, 0.88);

  /* Spacing scale. Every gap on the site is one of these four values, so
     blocks line up by construction instead of by coincidence. */
  --s-1: 8px;
  --s-2: 16px;
  --s-3: 24px;
  --s-4: 32px;

  /* Layout. --page-pad is the single source of truth for the site's left
     edge: the nav, the homepage hero, and every content container all
     use it, so nothing is ever a few pixels off from anything else.

     The pages set viewport-fit=cover so the background reaches the screen
     edges on a notched phone — without it Safari letterboxes the page and
     fills the notch and home-indicator strips with the page background,
     which reads as black bars. That means content now has to keep clear of
     those areas itself, hence the safe-area insets below. They resolve to
     0px on every device that doesn't have a notch. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --page-pad: max(clamp(20px, 5vw, 64px), env(safe-area-inset-left, 0px),
    env(safe-area-inset-right, 0px));
  --nav-top: calc(24px + var(--safe-top));
  --nav-clearance: calc(clamp(100px, 14vh, 130px) + var(--safe-top));
  --radius: 28px;

  /* How far a scrim halo or the price card extends past its text column.
     Kept below --page-pad at every width so nothing can reach the
     viewport edge (see the min-width bump below). */
  --bleed: 12px;

  /* Text sitting on the photographic background carries its own contrast.
     Each of these pairs a tight shadow, which puts a hard edge right at
     the glyph so it separates from a pale backdrop, with a wider ambient
     one for depth. A single wide blur alone spreads too thin to read. */
  --shadow-text: 0 1px 2px rgba(0, 0, 0, 0.55), 0 2px 12px rgba(0, 0, 0, 0.4);
  --shadow-text-lg: 0 2px 4px rgba(0, 0, 0, 0.5), 0 4px 24px rgba(0, 0, 0, 0.45);
  /* For body copy on the bare image, which needs the most help. */
  --shadow-text-body: 0 1px 2px rgba(0, 0, 0, 0.7), 0 1px 8px rgba(0, 0, 0, 0.55),
    0 2px 20px rgba(0, 0, 0, 0.4);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  color-scheme: dark;
}

@media (min-width: 720px) {
  :root {
    --bleed: var(--s-3);
  }
}

/* Smooth cross-page navigation where supported; falls back to a normal
   page load everywhere else. */
@view-transition {
  navigation: auto;
}

/* ---------- Base ---------- */

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: inherit;
}

.display {
  font-family: 'Bricolage Grotesque', -apple-system, BlinkMacSystemFont, sans-serif;
}

::selection {
  background: var(--accent-soft);
  color: var(--text);
}

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Stage + background ---------- */

.stage {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--nav-clearance) var(--page-pad)
    calc(clamp(26px, 4vw, 48px) + var(--safe-bottom));
  overflow: hidden;
  background: var(--bg);
}

/* Full-bleed background image. Fixed to the viewport rather than to the
   stage so a tall page can't stretch it — every page frames the image
   identically, and it holds still while the page scrolls.

   Height is the LARGE viewport, not 100%: on iOS the address bar retracts
   as you scroll and the visible area grows, but a fixed element sized to
   the current viewport doesn't grow with it, leaving a strip of bare page
   background along the bottom. Sizing to lvh means it always covers. */
.ambient-glow,
.grain {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100vh;
  height: 100lvh;
  pointer-events: none;
}

.ambient-glow {
  z-index: 0;
  background-image: url('/media/background.webp');
  background-size: cover;
}

.grain {
  z-index: 1;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.stage .ambient-glow {
  background-position: 40% 45%;
}

.contact-page .ambient-glow {
  background-position: 65% 25%;
}

.services-page .ambient-glow {
  background-position: 30% 70%;
}

/* Everything readable sits above the image and the grain. */
.hero,
.strip,
.contact-layout,
.page-content {
  position: relative;
  z-index: 2;
}

/* ---------- Nav ---------- */

.nav {
  position: fixed;
  top: var(--nav-top);
  left: var(--page-pad);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 0;
  width: fit-content;
  height: 50px;
  padding: 0 var(--s-1);
  border-radius: 999px;
  background: rgba(12, 10, 22, 0.45);
  border: 1px solid var(--border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  /* Deliberately NOT given a view-transition-name. Naming a backdrop-filtered
     element pulls it into its own snapshot layer, where the blur has no
     backdrop left to sample — it renders as a flat black or white square with
     the rounded corners gone. It rides the root crossfade instead, and since
     it sits at the same coordinates on every page it reads as static anyway. */
}

/* Logo and links carry identical horizontal padding, and the pill's own
   padding is set so the space at each end of the bar matches (20px) and
   the space between every item matches (24px). */
.nav-logo,
.nav-link {
  padding: 8px 12px;
  border-radius: 999px;
  text-decoration: none;
  transition: background 0.25s var(--ease), color 0.25s var(--ease);
}

.nav-logo {
  font-size: 1.02rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.nav-link {
  position: relative;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
  background: transparent;
}

.nav-link::after {
  content: '';
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 6px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s var(--ease);
}

.nav-logo:hover,
.nav-logo:focus-visible,
.nav-link:hover,
.nav-link:focus-visible {
  background: var(--accent-soft);
}

.nav-link:hover::after,
.nav-link:focus-visible::after {
  transform: scaleX(1);
}

/* ---------- Homepage ---------- */

.hero {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s-3);
}

.hero-title {
  font-size: clamp(3.4rem, 12vw, 8rem);
  font-weight: 800;
  line-height: 0.92;
  letter-spacing: -0.03em;
  margin: 0;
  text-shadow: var(--shadow-text-lg);
}

.hero-tagline {
  max-width: 30ch;
  margin: 0;
  font-size: clamp(1.05rem, 1.8vw, 1.25rem);
  color: var(--text-on-image);
  font-weight: 400;
  text-shadow: var(--shadow-text-body);
}

/* The homepage's one call to action. Same button as the services page so
   the site has a single primary-action treatment. */
.hero-cta {
  margin-top: var(--s-1);
}

.hero-cta svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  transition: transform 0.25s var(--ease-out);
}

.hero-cta:hover svg,
.hero-cta:focus-visible svg {
  transform: translateX(3px);
}

.strip {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
}

.strip-label {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-shadow: var(--shadow-text);
}

.strip-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  text-decoration: none;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  padding-bottom: 2px;
  border-bottom: 1px solid var(--border-strong);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
  text-shadow: var(--shadow-text);
}

.strip-link:hover,
.strip-link:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
}

.strip-link svg {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  transition: transform 0.25s var(--ease-out);
}

.strip-link:hover svg,
.strip-link:focus-visible svg {
  transform: translate(2px, -2px);
}

/* ---------- Sub-page shell ---------- */

/* Shared by contact, services, and anything added later. Horizontal
   padding lives on the inner containers only, so it is never applied
   twice. */
.stage-sub {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100svh;
  padding-left: 0;
  padding-right: 0;
  padding-bottom: calc(clamp(40px, 6vh, 80px) + var(--safe-bottom));
}

.contact-layout {
  max-width: calc(1040px + 2 * var(--page-pad));
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--page-pad);
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  gap: clamp(48px, 7vw, 100px);
  align-items: start;
}

.page-content {
  max-width: calc(640px + 2 * var(--page-pad));
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--page-pad);
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.contact-intro {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

/* ---------- Surfaces ---------- */

/* Soft scrim for text blocks that sit directly on the image with no
   bordered card. It bleeds outward via the pseudo-element's own negative
   inset, never via margin on the real box, so the element's size and
   position stay exactly what the layout expects. */
.text-scrim {
  position: relative;
}

.text-scrim::before {
  content: '';
  position: absolute;
  inset: calc(-1 * var(--s-3)) calc(-1 * var(--bleed));
  background: radial-gradient(
    ellipse 100% 100% at 25% 20%,
    rgba(12, 10, 22, 0.68),
    rgba(12, 10, 22, 0.42) 70%,
    rgba(12, 10, 22, 0.2) 100%
  );
  border-radius: var(--radius);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  pointer-events: none;
}

.text-scrim > * {
  position: relative;
}


.panel-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(28px, 4vw, 44px);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
}

/* Gradient hairline along the top-left edge. Needs both the prefixed and
   standard mask properties — with only the prefixed pair this renders as
   a solid overlay in Firefox instead of a 1px edge. */
.panel-card::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(160deg, rgba(244, 242, 251, 0.14), transparent 40%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

/* Wider than the text column, symmetrically, using the same bleed the
   scrims use — so stacked blocks share one left and right edge. */
.price-card {
  width: calc(100% + 2 * var(--bleed));
  margin-left: calc(-1 * var(--bleed));
  margin-right: calc(-1 * var(--bleed));
}

/* ---------- Typography blocks ---------- */

.stack-tight {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.page-eyebrow {
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0;
  text-shadow: var(--shadow-text);
}

.page-heading {
  font-size: clamp(2.4rem, 4.4vw, 3.4rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.04;
  margin: 0;
  text-wrap: balance;
  text-shadow: var(--shadow-text-lg);
}

.page-sub {
  color: var(--text-on-image);
  font-size: 1.05rem;
  line-height: 1.6;
  max-width: 42ch;
  margin: 0;
  text-shadow: var(--shadow-text-body);
}

/* Every labelled section on the site uses this, and the rule it carries
   has identical space above and below it. */
.section-label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 var(--s-3);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--border);
  text-shadow: var(--shadow-text);
}

.section-text {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.95rem;
  line-height: 1.6;
  max-width: 42ch;
  text-shadow: var(--shadow-text);
}

.check-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.check-list li {
  position: relative;
  padding-left: 20px;
  color: var(--text-muted);
  font-size: 0.95rem;
  text-shadow: var(--shadow-text);
}

.check-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

/* ---------- Services: pricing ---------- */

.price-label {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 var(--s-1);
}

.price-amount {
  font-weight: 800;
  font-size: clamp(2.4rem, 6vw, 3.4rem);
  letter-spacing: -0.02em;
  line-height: 1;
  margin: 0 0 var(--s-2);
}

.price-note {
  color: var(--text-muted);
  font-size: 0.98rem;
  line-height: 1.6;
  max-width: 48ch;
  margin: 0 0 var(--s-3);
}

.addon-option {
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--border);
}

.addon-option:first-of-type {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

.addon-title {
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--text);
  margin: 0 0 6px;
  text-shadow: var(--shadow-text);
}

.addon-desc {
  color: var(--text-muted);
  font-size: 0.92rem;
  line-height: 1.55;
  max-width: 46ch;
  margin: 0;
  text-shadow: var(--shadow-text);
}

/* ---------- Contact: form ---------- */

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.field label {
  font-size: 0.83rem;
  font-weight: 600;
  color: var(--text-muted);
}

.field input,
.field textarea {
  background: rgba(244, 242, 251, 0.03);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 13px 16px;
  color: var(--text);
  font-family: inherit;
  font-size: 1rem;
  resize: vertical;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease),
    box-shadow 0.2s var(--ease);
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: rgba(244, 242, 251, 0.05);
  box-shadow: 0 0 0 4px var(--accent-soft);
}

.form-note {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.form-note a {
  color: var(--text);
  text-underline-offset: 3px;
}

.btn-primary {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  font-family: inherit;
  font-size: 0.98rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--bg);
  background: var(--accent);
  padding: 14px 28px;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}

.btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 28px -10px var(--accent-dim);
}

.btn-primary:active {
  transform: translateY(0) scale(0.98);
  transition-duration: 0.1s;
}

/* The contact form's submit button spans the card; the services CTA
   hugs its label. */
.contact-form .btn-primary {
  align-self: stretch;
}

/* ---------- Motion ---------- */

/* One-time staggered reveal on load. Elements are visible by default and
   only animate for viewers who haven't asked for reduced motion, so the
   page is never blank if animation doesn't run. Each element sets its own
   --i, which keeps the stagger correct no matter how many blocks a page
   has. */
.reveal {
  opacity: 1;
}

@media (prefers-reduced-motion: no-preference) {
  .reveal {
    animation: rise-in 0.9s var(--ease-out) both;
    animation-delay: calc(var(--i, 0) * 90ms);
  }

  /* The one deliberately larger moment on the site. */
  .hero-title.reveal {
    animation-name: hero-in;
    animation-duration: 1.15s;
  }
}

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes hero-in {
  from {
    opacity: 0;
    transform: translateY(24px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* A short, controlled crossfade between pages. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.32s;
    animation-timing-function: var(--ease);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ---------- Responsive ---------- */

@media (max-width: 860px) {
  .contact-layout {
    grid-template-columns: 1fr;
    gap: 44px;
  }
}

@media (max-width: 520px) {
  .strip {
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
  }
}

/* Touch devices: grow the tap area to 44px — Apple's minimum — without
   changing how anything looks. The nav pills render at 38px and the work
   link at 27px, both fiddly to hit accurately with a thumb. An overlay
   sized from the element's centre does it without touching layout. */
@media (pointer: coarse) {
  .nav-logo,
  .strip-link {
    position: relative;
  }

  .nav-logo::before,
  .nav-link::before,
  .strip-link::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }
}

@media (max-height: 560px) {
  .hero-title {
    font-size: clamp(2.6rem, 10vw, 5rem);
  }
}
