/* ═══════════════════════════════════════════════════════════════════════
   WebitWorx — shared shell stylesheet
   Loaded by index.html, 404.html, /ip/, /privacy/ BEFORE each page's own
   inline <style>, so page-specific rules always win.
   Page-specific styles stay inline on the page that owns them.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── FONTS ─── */
/* ═══════════════════════════════════════════════════════════════════════
   WebitWorx — self-hosted fonts (no Google Fonts; kills FOUT + the 3rd-party
   request). Binaries are subset/instanced to what the site actually renders:

     Inter           variable, instanced to wght 400-700 (was 100-900).
                     FULL latin unicode-range kept on purpose — this face
                     renders user-typed form input and the ipapi.co city /
                     region / ISP strings on /ip/, which can contain accents.
     Space Grotesk   variable, instanced to wght 400-700 (was 300-700).
     Barlow Condensed 800 / 900, static.

   The three display faces are subset to ASCII + Latin-1 accented letters +
   the punctuation the site actually uses (© ° – — ‘ ’ “ ” …). Adding a
   HEADING that needs a glyph outside that set means re-subsetting — body
   copy is unaffected because it renders in Inter.

   Re-subset with fontTools:
     pyftsubset <in>.woff2 --flavor=woff2 \
       --unicodes="U+20-7E,U+A9,U+B0,U+C0-FF,U+2013,U+2014,U+2018,U+2019,U+201C,U+201D,U+2026"
     fonttools varLib.instancer <in>.woff2 wght=400:700 -o out.ttf

   NOTE: '→' (U+2192) is in NONE of these binaries and never was — the site
   uses an inline SVG arrow instead. Do not add it to a unicode-range
   expecting it to render; the glyph is genuinely absent.

   NOTE: these rules used to live in /fonts/fonts.css, where url() could be
   relative. They are in /assets/ now, so every url() below MUST stay
   ABSOLUTE (/fonts/…). A relative url() resolves against THIS stylesheet,
   which would 404 all four faces — and the display faces are
   font-display:block, so that is ~3s of invisible text sitewide. The ?v=2
   on each must also keep matching the <link rel="preload"> hrefs.
   ═══════════════════════════════════════════════════════════════════════ */

/* Inter — body copy, form input, and all API-sourced text. font-display:swap
   is safe here: Inter's metrics are close to the system sans, so the reflow
   on swap is minor, and body copy being readable early is worth more than
   avoiding it. The two display faces stay on `block` — see below. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2?v=2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Barlow Condensed + Space Grotesk — display faces. font-display stays
   `block`: Barlow Condensed 900 is roughly HALF the advance width of the
   default sans, so swapping .hero-logo (clamp(4rem,14vw,10rem)) would first
   paint "WEBITWORX" wide enough to overflow the viewport and then snap — a
   guaranteed CLS regression on the largest element, and exactly the FOUT
   these self-hosted fonts exist to prevent. */
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url('/fonts/barlow-condensed-800-latin.woff2?v=2') format('woff2');
  unicode-range: U+0020-007E, U+00A9, U+00B0, U+00C0-00FF, U+2013-2014,
    U+2018-2019, U+201C-201D, U+2026;
}
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url('/fonts/barlow-condensed-900-latin.woff2?v=2') format('woff2');
  unicode-range: U+0020-007E, U+00A9, U+00B0, U+00C0-00FF, U+2013-2014,
    U+2018-2019, U+201C-201D, U+2026;
}

@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: block;
  src: url('/fonts/space-grotesk-latin.woff2?v=2') format('woff2');
  unicode-range: U+0020-007E, U+00A9, U+00B0, U+00C0-00FF, U+2013-2014,
    U+2018-2019, U+201C-201D, U+2026;
}

/* ─── RESET ─── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ─── TOKENS ─── */
:root {
  color-scheme: dark;
  --bg: #0a0a0a;
  --surface: #111111;
  --surface-2: #181818;
  --border: rgba(255,255,255,0.07);
  --red: #C8201A;
  --red-light: #e84040;
  /* Brand red as SMALL TEXT — re-pointed per theme so BOTH clear 4.5:1.
     Dark is #ea4440, not #e84040: on the .service-card surface (#181818) the
     original measured 4.43:1, just under AA for small text. The +2R/+4G nudge
     is visually indistinguishable and lands at 4.57:1. */
  --red-text: #ea4440;
  /* Brand red as a HOVER BACKGROUND. --red-light must stay light (it is also a
     hover background elsewhere), so the darkened hover gets its own token. */
  --red-hover: #D42B24;
  --text: #f5f5f5;
  --muted: #888;
  --radius: 16px;
  --transition: 0.3s cubic-bezier(0.4,0,0.2,1);
}

[data-theme="light"] {
  color-scheme: light;
  --bg: #f2f2f2;
  --surface: #ffffff;
  --surface-2: #e8e8e8;
  --border: rgba(0,0,0,0.09);
  --text: #0f0f0f;
  --muted: #5a5a5a;
  --red-text: #b3170f;
}

/* ─── LIGHT-MODE SHELL OVERRIDES ─── */
[data-theme="light"] body::before { opacity: 0.12; }

[data-theme="light"] nav {
  background: rgba(242,242,242,0.85);
  border-bottom-color: rgba(0,0,0,0.09);
}

[data-theme="light"] .mobile-nav {
  background: rgba(242,242,242,0.98);
  border-bottom-color: rgba(0,0,0,0.09);
}

[data-theme="light"] .nav-links a:hover { background: rgba(0,0,0,0.05); }
[data-theme="light"] .theme-toggle:hover { background: rgba(0,0,0,0.06); }
[data-theme="light"] ::-webkit-scrollbar-track { background: var(--bg); }

/* ─── BASE ─── */
html { scroll-padding-top: 88px; }

body {
  font-family: 'Inter', sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  overflow-x: hidden;
}

body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
  /* The SVG carries only a viewBox, so without an explicit size the 4-octave
     turbulence rasterises across the whole viewport instead of tiling a 256px
     square (stitchTiles='stitch' shows a tile was the intent). */
  background-size: 256px 256px;
  pointer-events: none;
  z-index: 0;
  opacity: 0.4;
}

/* ─── NAV ─── */
nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 clamp(20px, 5vw, 80px);
  height: 72px;
  background: rgba(10,10,10,0.8);
  backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid var(--border);
  transition: background var(--transition);
}

/* ─── LOGO ─── */
.logo {
  text-decoration: none;
  display: flex;
  align-items: center;
}

/* The wordmark is a CSS background, not an <img>, so only the file matching the
   theme is ever fetched. data-theme is on <html> in the markup and rewritten by
   the head boot script BEFORE first paint, so the right file is picked on the
   first frame — no dark-logo flash, no wasted request. Deliberately NOT
   <picture>/<source media="(prefers-color-scheme: light)">: <source> outranks
   the scripted theme and would break the manual toggle. */
.logo-mark {
  display: block;
  width: 135px;
  height: 34px;
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 135px 34px;
}

[data-theme="dark"]  .logo-mark { background-image: url('/logo_dark.webp'); }
[data-theme="light"] .logo-mark { background-image: url('/logo_light.webp'); }

.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
}

.nav-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 500;
  padding: 6px 14px;
  border-radius: 8px;
  transition: color var(--transition), background var(--transition);
}

.nav-links a:hover { color: var(--text); background: rgba(255,255,255,0.06); }

.nav-cta {
  background: var(--red) !important;
  color: #fff !important;
  padding: 8px 18px !important;
  border-radius: 8px !important;
  font-weight: 600 !important;
  white-space: nowrap;
}

/* Transform-bearing hover — gated so iOS Safari cannot latch it onto a tap. */
@media (hover: hover) {
  .nav-cta:hover { background: var(--red-hover) !important; transform: translateY(-1px); box-shadow: 0 6px 20px rgba(200,32,26,0.4); }
}

.hamburger { display: none; flex-direction: column; gap: 5px; cursor: pointer; background: none; border: none; padding: 10px; width: 44px; height: 44px; align-items: center; justify-content: center; margin-right: -6px; }
.hamburger span { width: 22px; height: 2px; background: var(--muted); border-radius: 2px; transition: var(--transition); display: block; }

.theme-toggle {
  background: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  transition: color var(--transition), background var(--transition), border-color var(--transition);
}

.theme-toggle:hover { color: var(--text); background: rgba(255,255,255,0.06); }

/* Both glyph groups ship in #themeIcon; CSS picks the right one so it paints on
   the first frame instead of being swapped in by the tail script. Dark theme
   shows the SUN — it is the "switch to light" affordance. */
[data-theme="dark"] .icon-moon,
[data-theme="light"] .icon-sun { display: none; }

.nav-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* ─── MOBILE MENU ─── */
.mobile-nav {
  display: none;
  position: fixed;
  top: 72px; left: 0; right: 0;
  background: rgba(10,10,10,0.98);
  backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border);
  padding: 20px clamp(20px,5vw,80px);
  flex-direction: column;
  gap: 4px;
  z-index: 99;
  max-height: calc(100vh - 72px);
  max-height: calc(100dvh - 72px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

@media (max-width: 960px) { .mobile-nav.open { display: flex; } }

.mobile-nav a {
  color: var(--muted);
  text-decoration: none;
  padding: 12px 16px;
  border-radius: 8px;
  font-weight: 500;
  transition: var(--transition);
}

.mobile-nav a:hover { color: var(--text); background: rgba(255,255,255,0.04); }

@media (max-width: 960px) {
  .nav-links { display: none; }
  .hamburger { display: flex; }
}

/* ─── FOOTER ─── */
footer {
  border-top: 1px solid var(--border);
  padding: 40px clamp(20px, 5vw, 80px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 20px;
}

.footer-links { display: flex; gap: 24px; flex-wrap: wrap; }

@media (max-width: 640px) {
  footer { flex-direction: column; align-items: center; text-align: center; }
  .footer-links { justify-content: center; }
}

.footer-links a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  /* 11px block padding lifts a 21.8px line box to ~44px tall (WCAG 2.5.5).
     Block-only, so the 24px gap that carries these targets through the
     SC 2.5.8 spacing exception is untouched — never shrink that gap. */
  padding: 11px 0;
  display: inline-flex;
  align-items: center;
  transition: color var(--transition);
}

.footer-links a:hover { color: var(--text); }

/* Icon-only link: no text to pad out, so give it a full 44x44 box. Works with
   the inline display:flex;align-items:center the pages set on this anchor. */
.footer-links a[aria-label="Instagram"] {
  min-width: 44px;
  min-height: 44px;
  justify-content: center;
}

footer p { color: var(--muted); font-size: 0.82rem; }

/* ─── INLINE ARROW ─── */
/* '→' (U+2192) is in none of the self-hosted font binaries, so it fell back to
   a mismatched system font. Visible copy uses an inline SVG instead. */
.arrow { flex: 0 0 auto; transition: transform var(--transition); }

@media (hover: hover) {
  a:hover > .arrow,
  button:hover > .arrow { transform: translateX(3px); }
}

/* ─── SCROLLBAR ─── */
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: rgba(200,32,26,0.4); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: rgba(200,32,26,0.7); }

/* Skip-to-content link — visible only on keyboard focus (WCAG 2.4.1) */
/* /privacy/ overrides this with its own variant in its inline <style>. */
.skip-link {
  position: absolute; left: 12px; top: -52px; z-index: 1000;
  background: var(--red); color: #fff; padding: 10px 16px;
  border-radius: 8px; font-weight: 600; text-decoration: none;
  transition: top 0.2s ease;
}
.skip-link:focus { top: 12px; }

/* Respect the OS "reduce motion" setting (WCAG 2.3.3) */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ─── PRINT ─── */
/* The default theme is dark, so without this a dark-theme visitor prints
   near-white text on white paper (the privacy policy comes out blank).
   Shell elements only — pages add their own print rules on top. */
@media print {
  body {
    background: #fff !important;
    color: #000 !important;
  }

  body::before { display: none !important; }

  nav,
  .mobile-nav,
  .hamburger,
  .theme-toggle,
  .skip-link { display: none !important; }

  /* The footer wordmark follows the theme; a dark-theme visitor prints the
     WHITE logo, which is invisible on paper and leaves a blank gap. Hide it —
     the "© YEAR WebitWorx LLC" line below still identifies the business.
     Targets the anchor, so it hides the .logo-mark background with it. */
  footer .logo { display: none !important; }

  h1, h2, h3, h4, h5, h6,
  p, li, td, th, a,
  footer p,
  .footer-links a { color: #000 !important; }
}
