/* Shared styles for the static service pages (/3d-websites/, /affordable-web-design-sydney/ …).

   Palette and type are lifted from the main site's :root so the pages cannot
   drift from the world. These pages carry no WebGL on purpose — they have to be
   instant and fully readable to a crawler. */
:root {
  --black: #04050a;
  --black-2: #0b0e18;
  --red: #e10600;
  --red-hot: #f51100; /* the brand red one step brighter, for the hovered call only */
  --ember: #ff7a46;
  --cold: #8ea6cc;
  --silver-1: #f2f3f5;
  --silver-2: #9a9da3;
  --silver-3: #7c8088;
  --silver-4: #2a2c31;
  --silver-hint: #73777e;
  --silver-grad: linear-gradient(160deg, #f7f8fa 0%, #c8cbd0 55%, #8a8e95 100%);
  --display: 'Archivo', 'Arial Narrow', system-ui, sans-serif;
  --body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: var(--black);
  color: var(--silver-2);
  font: 400 clamp(1rem, 0.97rem + 0.14vw, 1.0625rem)/1.65 var(--body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* starfield + a red sun, the same light the world uses */
body::before,
body::after {
  content: '';
  position: fixed;
  pointer-events: none;
  z-index: 0;
}
body::before {
  inset: 0;
  background:
    radial-gradient(1px 1px at 12% 18%, rgba(255,255,255,0.5), transparent),
    radial-gradient(1px 1px at 68% 9%, rgba(255,255,255,0.35), transparent),
    radial-gradient(1.5px 1.5px at 34% 62%, rgba(255,255,255,0.4), transparent),
    radial-gradient(1px 1px at 88% 44%, rgba(255,255,255,0.3), transparent),
    radial-gradient(1px 1px at 22% 88%, rgba(255,255,255,0.35), transparent),
    radial-gradient(1.5px 1.5px at 78% 76%, rgba(255,255,255,0.28), transparent),
    radial-gradient(1px 1px at 52% 32%, rgba(255,255,255,0.3), transparent);
}
body::after {
  right: -14vw; top: 24vh; width: 60vw; height: 60vw; max-width: 760px; max-height: 760px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(225,6,0,0.16) 0%, rgba(225,6,0,0.05) 42%, transparent 70%);
}

.wrap { position: relative; z-index: 1; width: min(72rem, 100% - 2.5rem); margin-inline: auto; }

a { color: var(--silver-1); text-decoration-color: var(--silver-4); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--red); }

/* ------------------------------------------------------------------ header */
header {
  position: sticky; top: 0; z-index: 10;
  background: rgba(4, 5, 10, 0.82);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--silver-4);
}
.bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.9rem 0; }
.mark {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--display); font-variation-settings: 'wdth' 122, 'wght' 800;
  font-size: 1rem; letter-spacing: 0.02em; color: var(--silver-1);
  text-decoration: none; text-transform: uppercase;
}
.mark i { width: 7px; height: 7px; border-radius: 50%; background: var(--red); }
.bar .call {
  padding: 0.4rem 0;
  font-size: 0.8125rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--silver-2); text-decoration: none; white-space: nowrap;
}
.bar .call:hover { color: var(--silver-1); }

/* -------------------------------------------------------------------- type */
h1, h2, h3 {
  font-family: var(--display);
  font-variation-settings: 'wdth' 120, 'wght' 800;
  letter-spacing: -0.035em; line-height: 0.94; text-transform: uppercase;
  background: var(--silver-grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
h1 { font-size: clamp(2rem, 1.2rem + 4.4vw, 4.6rem); margin-bottom: 1.25rem; overflow-wrap: break-word; }
h2 { font-size: clamp(1.75rem, 1.3rem + 2.1vw, 3rem); margin-bottom: 1.25rem; }
h3 {
  font-size: 1.0625rem; letter-spacing: 0.02em; line-height: 1.25;
  font-variation-settings: 'wdth' 112, 'wght' 700;
  margin-bottom: 0.5rem;
}

section { padding: clamp(3.25rem, 7vw, 6rem) 0; border-bottom: 1px solid var(--silver-4); }
/* sticky header measures 64px; anchored sections must land clear of it */
[id] { scroll-margin-top: 88px; }
.lede { font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.3125rem); color: var(--silver-2); max-width: 46ch; }
p + p { margin-top: 1rem; }
strong { color: var(--silver-1); font-weight: 600; }

/* Constrain the children, never the wrap itself — a narrowed wrap would be
   centred by margin-inline:auto and drift right of the hero's left edge. */
.wrap.measure > * { max-width: 62ch; }

/* -------------------------------------------------------------------- hero */
.hero { padding-top: clamp(3rem, 8vw, 6.5rem); }
.eyebrow {
  display: block; max-width: 62ch;
  font-size: 0.75rem; line-height: 1.6; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--silver-hint); margin-bottom: 1.5rem;
}
/* the dot is inline so wrapped text follows it; a flex dot sat alone on line 1 at 390px */
.eyebrow::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--red); margin-right: 0.55rem; vertical-align: middle;
}

.cta-row { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }
.btn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.85rem 1.5rem; border-radius: 999px;
  font-size: 0.8125rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  text-decoration: none; transition: transform 0.4s var(--ease), background 0.3s;
}
.btn--primary { background: var(--red); color: #fff; border: 1px solid transparent; box-shadow: 0 0 28px -6px rgba(225,6,0,0.7); }
.btn--primary:hover { transform: translateY(-2px); background: var(--red-hot); }
.btn--ghost { border: 1px solid var(--silver-4); color: var(--silver-1); }
.btn--ghost:hover { transform: translateY(-2px); border-color: var(--silver-3); }

/* ------------------------------------------------------------------- cards */
.grid { display: grid; gap: 1rem; margin-top: 2.25rem; }
@media (min-width: 46rem) {
  .grid.three { grid-template-columns: repeat(3, 1fr); }
  .grid.two { grid-template-columns: repeat(2, 1fr); }
}
.card {
  padding: 1.5rem; border: 1px solid var(--silver-4); border-radius: 0.9rem;
  background: linear-gradient(180deg, rgba(11,14,24,0.7), rgba(4,5,10,0.4));
}
.card p { font-size: 0.9375rem; }
.card .price { font-size: clamp(2rem, 1.5rem + 2vw, 2.75rem); margin: 0.25rem 0 0.5rem; }
.card .per { font-size: 0.8125rem; color: var(--silver-hint); letter-spacing: 0.1em; text-transform: uppercase; }

/* -------------------------------------------------------------------- list */
.ticks { list-style: none; margin-top: 1.5rem; display: grid; gap: 0.7rem; }
.ticks li { position: relative; padding-left: 1.6rem; }
.ticks li::before {
  content: ''; position: absolute; left: 0; top: 0.62em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--red);
}

/* ------------------------------------------------------------------- price */
.price-band { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.75rem 1.25rem; margin-bottom: 0.5rem; }
.price {
  font-family: var(--display); font-variation-settings: 'wdth' 118, 'wght' 800;
  font-size: clamp(3rem, 2rem + 5vw, 5rem); line-height: 1; color: var(--silver-1);
}
.price-note { font-size: 0.875rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--silver-hint); }

/* ------------------------------------------------------------------ tables */
.table-wrap { overflow-x: auto; margin-top: 1.75rem; position: relative; }
/* on a phone the comparison table swipes sideways; a fade on the right edge and a
   one-line hint say so, because a cut-off column reads as broken otherwise */
@media (max-width: 600px) {
  .table-wrap:has(thead) {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(90deg, #000 calc(100% - 2.5rem), transparent);
  }
  /* the last column's text must stop before the 2.5rem fade, or its final words sit half-hidden at max scroll */
  table:has(thead) th:last-child, table:has(thead) td:last-child { padding-right: 3.25rem; }
  .table-wrap:has(thead)::before {
    content: 'Swipe sideways to see the whole table'; display: block;
    position: sticky; left: 0; width: max-content;
    font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--silver-hint); margin-bottom: 0.5rem;
  }
}
table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
/* only the 3-column comparison table (the one with a header row) needs room; the
   2-column ledgers fit a phone and must not scroll */
table:has(thead) { min-width: 34rem; }
th, td { text-align: left; padding: 0.8rem 0.9rem; border-bottom: 1px solid var(--silver-4); vertical-align: top; }
th {
  font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--silver-hint); font-weight: 600;
}
td:first-child { color: var(--silver-1); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
tr.sum td { color: var(--silver-1); font-weight: 600; border-top: 1px solid var(--silver-3); }
tr.remaining td { color: var(--ember); font-weight: 600; }

/* --------------------------------------------------------------------- faq */
.faq { margin-top: 2rem; }
details { border-top: 1px solid var(--silver-4); }
details:last-of-type { border-bottom: 1px solid var(--silver-4); }
summary {
  cursor: pointer; list-style: none; padding: 1.15rem 2.5rem 1.15rem 0; position: relative;
  font-family: var(--display); font-variation-settings: 'wdth' 110, 'wght' 700;
  font-size: 1.0625rem; color: var(--silver-1);
}
summary::-webkit-details-marker { display: none; }
summary::after {
  content: '+'; position: absolute; right: 0.35rem; top: 50%; transform: translateY(-50%);
  font-family: var(--body); font-size: 1.4rem; font-weight: 400; color: var(--red); line-height: 1;
}
details[open] summary::after { content: '−'; }
details > p { padding: 0 0 1.3rem; max-width: 68ch; font-size: 0.9375rem; }
summary:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }

/* -------------------------------------------------------------------- quote */
.quote {
  border-left: 2px solid var(--red); padding: 0.25rem 0 0.25rem 1.25rem;
  color: var(--silver-1); font-size: 1.0625rem; max-width: 60ch; margin-top: 1.5rem;
}
.quote small { display: block; margin-top: 0.5rem; color: var(--silver-hint); font-size: 0.8125rem; }

/* ------------------------------------------------------------------ footer */
footer { padding: 3rem 0 4rem; }
.foot-row { display: flex; flex-wrap: wrap; gap: 1rem 2rem; justify-content: space-between; align-items: center; }
.foot-row p { font-size: 0.875rem; color: var(--silver-hint); }
.foot-nav { display: flex; flex-wrap: wrap; gap: 0.5rem 1.4rem; font-size: 0.875rem; }
.foot-nav a { color: var(--silver-2); display: inline-block; padding: 0.3rem 0; }

@media (max-width: 480px) {
  th, td { padding: 0.6rem 0.5rem; font-size: 0.875rem; }
  h2 { font-size: clamp(1.5rem, 1.2rem + 2.1vw, 3rem); }
}

/* --------------------------------------------------------------- the life
   DESIGN.md, LIFE PLAN. Four continuous animations, all slow enough to be
   felt rather than watched, plus reveals and a cursor bloom driven by
   /alive.js. Nothing here hides content on its own: the .rv class is added
   by script, so a page with no JavaScript renders complete. */

/* the sun breathes and drifts; this is the hero's continuous motion */
body::after { animation: sun-drift 40s var(--ease) infinite alternate; }
@keyframes sun-drift {
  from { transform: translate3d(0, 0, 0) scale(1); opacity: 0.85; }
  to   { transform: translate3d(-3vw, 4vh, 0) scale(1.08); opacity: 1; }
}

/* The starfield drifts, far too slowly to catch in the act. Halved from 14px
   over 90s after a reader said the specks pulled his eye off the words twice:
   background motion that gets noticed is not background motion. */
body::before { animation: star-pan 150s linear infinite alternate; }
@keyframes star-pan {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-7px, 4px, 0); }
}

/* The red dot in the eyebrow and in the header mark. Opacity only: box-shadow
   is a paint property, and the header dot is on screen for the whole visit, so
   an expanding ring here would repaint forever on every phone. */
.eyebrow::before, .mark i { animation: dot-pulse 4s ease-in-out infinite; }
@keyframes dot-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

/* The primary call swells, so the one thing to do is the one thing moving.
   The glow is a second, brighter shadow on a pseudo-element whose OPACITY
   animates: the size never changes, and nothing repaints. Animating the
   shadow itself grew the halo about 15px past the pill, across the 12px
   .cta-row gap and onto the ghost button's top border at 390. */
.btn--primary { position: relative; }
.btn--primary::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  box-shadow: 0 0 32px -6px rgba(225, 6, 0, 0.85);
  pointer-events: none; opacity: 0;
  animation: cta-breathe 5s ease-in-out infinite;
}
@keyframes cta-breathe {
  0%, 100% { opacity: 0; }
  50%      { opacity: 1; }
}
.btn--primary:hover::after { animation-play-state: paused; }

/* scroll reveals: /alive.js adds .rv, the observer adds .on */
.rv { opacity: 0; transform: translateY(22px); transition: opacity 0.85s var(--ease), transform 0.85s var(--ease); }
.rv.on { opacity: 1; transform: none; }
/* A hidden element is still focusable. Tabbing into an unrevealed band, or
   into one of the seven footer links, would otherwise move focus somewhere
   invisible and take the focus ring with it. */
.rv:focus-within { opacity: 1 !important; transform: none !important; transition: none !important; }
/* Print has no scrolling and no observer worth waiting for. */
@media print { .rv { opacity: 1 !important; transform: none !important; } }

/* the cursor bloom, desktop pointers only; /alive.js creates the element */
.cur-spot { display: none; }
@media (hover: hover) and (pointer: fine) and (min-width: 901px) {
  .cur-spot {
    display: block; position: fixed; left: 0; top: 0; z-index: 0;
    width: 320px; height: 320px; border-radius: 50%;
    pointer-events: none; mix-blend-mode: screen; opacity: 0;
    background: radial-gradient(circle at 50% 50%, var(--red) 0%, rgba(225, 6, 0, 0.4) 34%, transparent 68%);
    transition: opacity 0.35s var(--ease);
    /* No will-change. translate3d already promotes this to its own layer, and
       a permanent hint on a screen-blended fixed element holds a composited
       layer for the life of the page in exchange for nothing. */
  }
  .cur-spot.on { opacity: 0.16; }
}

@media (prefers-reduced-motion: reduce) {
  /* the pseudo-elements must be named: the sun, the starfield and the eyebrow
     dot all animate on ::before / ::after, which a bare * never matches */
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .rv { opacity: 1 !important; transform: none !important; }
  .cur-spot { display: none !important; }
}
