/* vantoro.au only. Tailwind does layout and colour; this file is the depth, texture
   and motion layer that utility classes can't express cleanly.

   Every effect is progressive. With reduced motion requested, or in a browser without
   scroll-driven animation, nothing is hidden: the page is complete and holds still. */

/* ---------------------------------------------------------------- fonts */

/* Served from this site rather than Google Fonts: one less server to reach before the
   page can draw, and visitors' IP addresses don't go to Google. Both are variable
   fonts, so one Latin file each covers every weight. Listed in site.config.json
   selfHostedFonts, which preloads them and drops the Google Fonts link. */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/space-grotesk-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin.woff2") format("woff2");
}

:root {
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
  --skeleton: #e9e2d8;
}

/* ---------------------------------------------------------------- buttons */

/* Squared, with a hard offset shadow the button presses into. Dark sections swap
   the shadow to sunset orange so it still reads against navy. */
.on-dark { --btn-shadow: var(--brand-sun); }
.on-light { --btn-shadow: var(--brand-night); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  font-family: var(--brand-font), ui-sans-serif, system-ui, sans-serif;
  font-weight: 600;
  line-height: 1.1;
  padding: 0.95rem 1.6rem;
  background: var(--brand-accent);
  color: var(--brand-night);
  box-shadow: 4px 4px 0 var(--btn-shadow, var(--brand-night));
  transition: transform 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}
.btn:hover { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--btn-shadow, var(--brand-night)); }
.btn:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--btn-shadow, var(--brand-night)); }
.btn:focus-visible { outline: 3px solid var(--brand-sun); outline-offset: 4px; }
.btn--sm { padding: 0.6rem 1rem; font-size: 0.95rem; box-shadow: 3px 3px 0 var(--btn-shadow, var(--brand-night)); }
.btn--sm:hover { box-shadow: 5px 5px 0 var(--btn-shadow, var(--brand-night)); }
.btn .arrow { transition: transform 180ms var(--ease-out); }
.btn:hover .arrow { transform: translateX(3px); }

/* A text link whose underline fills with sunset orange from the left on hover. */
.link-u {
  padding-bottom: 3px;
  background-image:
    linear-gradient(var(--brand-sun), var(--brand-sun)),
    linear-gradient(color-mix(in srgb, currentColor 35%, transparent), color-mix(in srgb, currentColor 35%, transparent));
  background-size: 0% 2px, 100% 2px;
  background-position: 0 100%, 0 100%;
  background-repeat: no-repeat;
  transition: background-size 260ms var(--ease-out);
}
.link-u:hover { background-size: 100% 2px, 100% 2px; }

/* Small blue text. The brand blue itself is just under 4.5:1 on the light
   backgrounds, so body-size links use a darkened version of it. */
.text-link,
.prose-links a { color: color-mix(in srgb, var(--brand-primary) 80%, #000); }
.prose-links a { text-decoration: underline; text-underline-offset: 2px; }

/* Header nav: same idea, no resting underline. The current page keeps its line. */
.navlink {
  position: relative;
  padding-block: 0.35rem;
}
.navlink::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  background: var(--brand-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 240ms var(--ease-out);
}
.navlink:hover::after,
.navlink[aria-current="page"]::after { transform: scaleX(1); }

/* ------------------------------------------------------------- small parts */

/* The one icon on the site: a squared teal tile with a navy tick. */
.tick {
  flex: none;
  width: 1.3rem;
  height: 1.3rem;
  margin-top: 0.12rem;
  background: var(--brand-accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5 10.5l3.2 3.2L15 6.5' fill='none' stroke='%23071A2F' stroke-width='2.6' stroke-linecap='square'/%3E%3C/svg%3E") center / 78% no-repeat;
}

/* Its opposite, for the "doing it yourself" side of a comparison. */
.cross {
  flex: none;
  width: 1.3rem;
  height: 1.3rem;
  margin-top: 0.12rem;
  background: rgba(7, 26, 47, 0.08) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M6.5 6.5l7 7M13.5 6.5l-7 7' fill='none' stroke='%2356606D' stroke-width='2.2' stroke-linecap='square'/%3E%3C/svg%3E") center / 78% no-repeat;
}

/* Hand-drawn underline under the hero's key phrase. Background-based so it follows
   the text onto a second line on a phone. */
.scribble {
  padding-bottom: 0.08em;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 24' preserveAspectRatio='none'%3E%3Cpath d='M3 15C70 6 140 20 210 11s140-6 187 2' fill='none' stroke='%23FF8A4C' stroke-width='7' stroke-linecap='round'/%3E%3C/svg%3E") 0 100% / 100% 0.22em no-repeat;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* "Limited spots" status light. */
.pulse {
  position: relative;
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  background: var(--brand-accent);
}
.pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--brand-accent);
}

/* Film grain over flat colour, so dark sections have texture instead of reading as
   a flat fill. Sits above content but is too faint and soft-lit to touch legibility. */
.grain { position: relative; }
.grain::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------ media layer */

/* Full-bleed photo or video behind a dark section. The video sits over its poster
   and only fades in once it is genuinely playing (see vantoro.js). */
.media { position: absolute; inset: 0; z-index: -2; overflow: hidden; }
.media img,
.media video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.media video { opacity: 0; transition: opacity 1.2s ease; }
.media video.is-playing { opacity: 1; }

/* ---------------------------------------------------------------- marquee */

.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.marquee__track { display: flex; width: max-content; }

/* -------------------------------------------------- the "it builds itself" box */

/* A little browser window that assembles a website on a loop: the build-first
   promise, shown rather than said. Its resting state is the finished site. */
.buildbox { position: relative; }
.browser {
  background: #fff;
  border: 1px solid rgba(7, 26, 47, 0.14);
  box-shadow: 0 40px 70px -40px rgba(7, 26, 47, 0.55), 14px 14px 0 var(--brand-primary);
}
.browser__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 12px;
  background: #f1eadf;
  border-bottom: 1px solid rgba(7, 26, 47, 0.08);
}
.browser__bar i { width: 10px; height: 10px; border-radius: 50%; background: var(--brand-sun); }
.browser__bar i:nth-child(2) { background: var(--brand-accent); }
.browser__bar i:nth-child(3) { background: var(--brand-primary); }
.browser__url {
  flex: 1;
  margin-left: 10px;
  padding: 6px 10px;
  background: #fff;
  color: #56606d;
  font: 500 12px/1 var(--brand-font-body), ui-sans-serif, system-ui, sans-serif;
  white-space: nowrap;
  overflow: hidden;
}
.browser__page { display: grid; gap: 12px; padding: 14px; }
.browser b {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--skeleton);
}
.browser b::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--paint);
  transform-origin: left;
}
.b-nav { display: flex; align-items: center; gap: 8px; }
.b-nav b { width: 34px; height: 8px; --paint: #a7afb9; }
.b-nav .b-logo { width: 22px; height: 22px; --paint: var(--brand-night); }
.b-nav .b-cta { width: 58px; height: 20px; margin-left: auto; --paint: var(--brand-accent); }
.b-hero {
  position: relative;
  display: grid;
  align-content: end;
  gap: 8px;
  min-height: 170px;
  padding: 18px;
  overflow: hidden;
  background: var(--skeleton);
}
.b-photo {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(7, 26, 47, 0.85), rgba(7, 26, 47, 0.2)),
    url(img/port-macquarie-breakwall-800.webp) center / cover;
}
.b-hero b { z-index: 1; height: 13px; width: 72%; background: #d9cfc1; --paint: #fff; }
.b-hero .b-line--short { width: 48%; }
.b-hero .b-btn { width: 84px; height: 24px; margin-top: 6px; --paint: var(--brand-sun); }
.b-hero .b-btn::after { transform-origin: center; }
.b-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.b-cards b { height: 70px; --paint: var(--brand-mist); }
.b-cards b::after { box-shadow: inset 0 3px 0 var(--brand-accent); }
.buildbox__badge {
  position: absolute;
  right: -8px;
  bottom: 28px;
  padding: 9px 13px;
  background: var(--brand-sun);
  color: var(--brand-night);
  font: 700 14px/1 var(--brand-font), ui-sans-serif, system-ui, sans-serif;
  box-shadow: 3px 3px 0 var(--brand-night);
  transform: rotate(3deg);
}

/* ------------------------------------------------------------------ motion */

@media (prefers-reduced-motion: no-preference) {
  .scribble { animation: scribble 900ms 450ms var(--ease-out) both; }
  .pulse::after { animation: pulse 2s var(--ease-out) infinite; }
  .marquee__track { animation: marquee 42s linear infinite; }
  .marquee.is-paused .marquee__track { animation-play-state: paused; }
  /* Hover-to-pause only where there's a real pointer: phones keep :hover after a tap,
     which would stop a second tap from starting it again. */
  @media (hover: hover) {
    .marquee:hover .marquee__track { animation-play-state: paused; }
  }

  /* Photo heroes drift very slowly, so a still photo still feels alive. */
  .media--drift img { animation: drift 26s ease-in-out infinite alternate; }

  /* Build box: one 7s cycle, each part painting in turn, then the whole thing fades
     back to skeleton and starts again. */
  .b-nav b::after { animation: paint-nav 7s var(--ease-out) infinite; }
  .b-photo { animation: paint-photo 7s var(--ease-out) infinite; }
  .b-hero b:nth-of-type(1)::after { animation: paint-l1 7s var(--ease-out) infinite; }
  .b-hero b:nth-of-type(2)::after { animation: paint-l2 7s var(--ease-out) infinite; }
  .b-hero .b-btn::after { animation: pop-btn 7s var(--ease-out) infinite; }
  .b-cards b:nth-child(1)::after { animation: rise-c1 7s var(--ease-out) infinite; }
  .b-cards b:nth-child(2)::after { animation: rise-c2 7s var(--ease-out) infinite; }
  .b-cards b:nth-child(3)::after { animation: rise-c3 7s var(--ease-out) infinite; }
  .buildbox__badge { animation: pop-badge 7s var(--ease-out) infinite; }

  /* Sections rise into place as they scroll in. Children of .stagger arrive one
     after another, offset by their --i. */
  @supports (animation-timeline: view()) {
    .reveal,
    .stagger > * {
      animation: rise var(--ease-out) both;
      animation-timeline: view();
      animation-range: entry calc(4% + var(--i, 0) * 6%) entry calc(52% + var(--i, 0) * 6%);
    }
  }
}

@keyframes rise { from { opacity: 0; transform: translateY(36px); } }
@keyframes scribble { from { background-size: 0% 0.22em; } }
@keyframes pulse { 0% { transform: scale(1); opacity: 0.7; } 80%, 100% { transform: scale(3); opacity: 0; } }
@keyframes marquee { to { transform: translateX(-50%); } }
@keyframes drift { from { transform: scale(1.02); } to { transform: scale(1.12) translate(-1.5%, -1%); } }

@keyframes paint-nav {
  0%, 8% { transform: scaleX(0); opacity: 1; }
  16%, 94% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 0; }
}
@keyframes paint-photo {
  0%, 16% { clip-path: inset(0 100% 0 0); opacity: 1; }
  32%, 94% { clip-path: inset(0 0 0 0); opacity: 1; }
  100% { clip-path: inset(0 0 0 0); opacity: 0; }
}
@keyframes paint-l1 {
  0%, 32% { transform: scaleX(0); opacity: 1; }
  42%, 94% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 0; }
}
@keyframes paint-l2 {
  0%, 38% { transform: scaleX(0); opacity: 1; }
  48%, 94% { transform: scaleX(1); opacity: 1; }
  100% { transform: scaleX(1); opacity: 0; }
}
@keyframes pop-btn {
  0%, 48% { transform: scale(0); opacity: 1; }
  54% { transform: scale(1.18); }
  58%, 94% { transform: scale(1); opacity: 1; }
  100% { transform: scale(1); opacity: 0; }
}
@keyframes rise-c1 {
  0%, 56% { transform: translateY(100%); opacity: 1; }
  66%, 94% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(0); opacity: 0; }
}
@keyframes rise-c2 {
  0%, 60% { transform: translateY(100%); opacity: 1; }
  70%, 94% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(0); opacity: 0; }
}
@keyframes rise-c3 {
  0%, 64% { transform: translateY(100%); opacity: 1; }
  74%, 94% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(0); opacity: 0; }
}
@keyframes pop-badge {
  0%, 76% { transform: scale(0.4) rotate(-8deg); opacity: 0; }
  82% { transform: scale(1.08) rotate(4deg); opacity: 1; }
  86%, 94% { transform: scale(1) rotate(3deg); opacity: 1; }
  100% { transform: scale(1) rotate(3deg); opacity: 0; }
}
