/* ========================================
   ZeroLoss GPS - SIM-free vehicle trackers
   Warm paper theme: bone, clay, ink, chroma accent
   ======================================== */

:root {
  --bg: #f4f1ec;
  --bg2: #ece6dd;
  --card: #ffffff;
  --card2: #f7f4ef;
  --panel: #e4dace;
  --panel-deep: #3a302a;
  --text: #16120f;
  --text2: #5f574f;
  --muted: #8c8279;
  --accent: #f4436c;
  --accent-lt: #ff6f8f;
  --accent-dk: #c92a52;
  --accent-ink: #ffffff;
  --ink: #16120f;
  --chroma: linear-gradient(100deg, #ff8a3d, #f4436c 28%, #a855f7 56%, #3b82f6 80%, #22d3ee);
  --accent-glow: rgba(244, 67, 108, .16);
  --glow: rgba(244, 67, 108, .07);
  --warn: #b46b00;
  --border: rgba(22, 18, 15, .10);
  --border-light: rgba(22, 18, 15, .18);
  --display: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --body: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: var(--display);
  --font-body: var(--body);
  --ease: cubic-bezier(.25, .46, .45, .94);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --maxw: 1240px;
  --radius: 22px;
}

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; overflow-x: hidden; -webkit-text-size-adjust: 100%; }
/* The nav is sticky, so anchor targets must stop clear of it. */
[id] { scroll-margin-top: 5.25rem; }
body { font-family: var(--body); background: var(--bg); color: var(--text); line-height: 1.6; overflow-x: hidden; }
a { text-decoration: none; color: inherit; }
ul, ol { list-style: none; }
/* height:auto is load-bearing. Every <img> carries width/height attributes for
   layout stability, and without this the attribute height wins once max-width
   scales the element down, stretching the image vertically. */
img { max-width: 100%; height: auto; display: block; border-radius: 14px; }
button { cursor: pointer; font-family: inherit; border: none; background: none; color: inherit; }
a, button, summary, input, select, textarea { -webkit-tap-highlight-color: rgba(142, 240, 74, .18); }
input, textarea, select { font-family: inherit; font-size: 1rem; }
::selection { background: var(--accent); color: #fff; }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: var(--bg2); }
::-webkit-scrollbar-thumb { background: var(--text2); border-radius: 2px; }

/* ===== TYPOGRAPHY ===== */
h1, h2, h3, h4 { font-family: var(--display); font-weight: 600; line-height: 1.14; letter-spacing: -.03em; }
h3, h4 { font-weight: 600; line-height: 1.32; letter-spacing: -.015em; }
h1 { font-size: clamp(2.1rem, 4.6vw, 3.5rem); }
h2 { font-size: clamp(1.6rem, 3.2vw, 2.5rem); }
h3 { font-size: clamp(.98rem, 1.4vw, 1.08rem); }
h4 { font-size: 1rem; }
.eyebrow { font-size: .68rem; text-transform: uppercase; letter-spacing: .16em; color: var(--muted); font-weight: 600; margin-bottom: 1rem; display: block; }
.lead { font-size: clamp(1rem, 1.6vw, 1.15rem); color: var(--text2); max-width: 62ch; }
.section-head { max-width: 62ch; margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.section-head p { color: var(--text2); margin-top: .85rem; }
.prose { color: var(--text2); max-width: 74ch; }
.prose h2 { color: var(--text); margin: 2.5rem 0 1rem; }
.prose h3 { color: var(--text); margin: 2rem 0 .75rem; }
.prose p { margin-bottom: 1rem; }
.prose ul { margin: 0 0 1.15rem 1.15rem; list-style: disc; }
.prose li { margin-bottom: .5rem; }
.prose a { color: var(--accent); }
.prose strong { color: var(--text); }

/* ===== LAYOUT ===== */
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.25rem, 4vw, 2.5rem); }
.wrap-narrow { max-width: 880px; margin: 0 auto; padding: 0 clamp(1.25rem, 4vw, 2.5rem); }
section { padding: clamp(3.5rem, 8vw, 7rem) 0; }
section.tight { padding: clamp(2rem, 4vw, 3.5rem) 0; }
.grid { display: grid; gap: clamp(1rem, 2.5vw, 2rem); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: clamp(1.25rem, 2.5vw, 2rem); transition: border-color .3s var(--ease), transform .3s var(--ease), box-shadow .3s var(--ease); }
.card:hover { border-color: var(--border-light); box-shadow: 0 18px 40px -28px rgba(22,18,15,.45); }
.card h3 { margin-bottom: .6rem; }
.card p { color: var(--text2); font-size: .93rem; }
.card-lift:hover { transform: translateY(-3px); }
.bg-alt { background: var(--bg2); }

/* ===== HOME DOT FIELD =====
   The layer behind the home page: three soft washes of the palette on a
   fixed pane, and over them one plane carrying one grid of dots.

   There were two grids until now - a larger dot every 216px sitting at
   the centre of four small ones. It is gone, and with it the whole
   apparatus that kept it honest: the 3:1 spacing, the 36px offset, the
   need for the two grids to stay commensurate through the stretch. One
   grid has none of those failure modes.

   72px, thinned there from an original 32px that put close to a
   thousand dots on a desktop screen and read as a printed halftone.

   The dots are a .10 ink, about 22 levels of contrast on the paper
   ground - visible as a pattern rather than as a watermark, which is
   where they sat at half this.

   All vector, one gradient, no request, crisp at any density. */
.dot-field {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  background-image:
    radial-gradient(60rem 42rem at 84% -8%, rgba(244, 67, 108, .06), rgba(244, 67, 108, 0) 62%),
    radial-gradient(54rem 40rem at -10% 24%, rgba(228, 218, 206, .55), rgba(228, 218, 206, 0) 64%),
    radial-gradient(46rem 34rem at 46% 112%, rgba(58, 48, 42, .05), rgba(58, 48, 42, 0) 60%);
  background-repeat: no-repeat;
  /* Dissolves at the edges instead of tiling away to infinity, which is
     the difference between a field with an extent and a wallpaper. It
     lives here rather than on the plane because the plane moves, and a
     mask would jump with every wrap. */
  -webkit-mask-image: radial-gradient(128% 108% at 50% 6%, #000 40%, rgba(0, 0, 0, .62) 78%, rgba(0, 0, 0, 0) 100%);
          mask-image: radial-gradient(128% 108% at 50% 6%, #000 40%, rgba(0, 0, 0, .62) 78%, rgba(0, 0, 0, 0) 100%);
}

/* Overhangs the pane at each end and is clipped by it, so neither the
   drift nor the stretch can expose an edge. The overhang has to clear
   the wrap: the drift runs from 0 to minus one full period, so the
   plane can sit up to 72px high and leave that much bare at the foot.

   That period was 216px while the large dots set it, which is why this
   was 240px. It follows the grid down. The stretch needs nothing extra
   either way - theme.js only ever scales this up, and scaling up about
   the centre moves both edges further out. */
.dot-plane {
  position: absolute;
  left: 0; right: 0; top: -120px; bottom: -120px;
  display: block;
  background-image:
    radial-gradient(circle at 1px 1px, rgba(22, 18, 15, .10) 1px, rgba(22, 18, 15, 0) 1.6px);
  background-size: 72px 72px;
}

/* A phone sees a third of the width, so the desktop spacing leaves the
   dots sparse enough to look scattered. */
@media (max-width: 640px) {
  .dot-plane { background-size: 52px 52px; }
}

/* ===== BUTTONS ===== */
.btn-primary, .btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: 1.05rem 2rem; border-radius: 999px; min-height: 48px;
  font-size: .74rem; font-weight: 600; text-transform: uppercase; letter-spacing: .14em;
  transition: all .3s var(--ease); cursor: pointer; text-align: center;
}
/* A pink fill rather than filtered glass. The glass took its colour from
   whatever was behind it, which is why the same button read olive on the
   cream page and near-black on a photograph. A fill is the same colour
   everywhere, which is what a primary action should be. */
.btn-primary {
  background: var(--accent);
  border: 1px solid transparent;
  box-shadow: 0 6px 18px rgba(244, 67, 108, .22);
  position: relative; overflow: hidden;
  color: #fff;
}
.btn-primary:hover {
  background: var(--accent-lt);
  box-shadow: 0 8px 22px rgba(244, 67, 108, .3);
}

/* A sweep of light travelling across the face, on its own and again on
   hover.

   It used to run only on hover, which meant it did not exist on a phone -
   there is no hover there, and that is most of the traffic. It now runs on a
   long cycle: the sweep takes about a fifth of it and the rest is dark, so
   the button is still most of the time, and the shine reads as an occasional
   catch of light rather than a blinking element.

   A pseudo-element rather than an animated background, so it cannot disturb
   the fill; the buttons already clip their overflow. The skew makes the
   highlight read as a reflection crossing a curved face rather than a bar
   sliding past, and pointer-events stays off so it never intercepts a click. */
.btn-primary::after,
.btn-pill::after,
.btn-pill-light::after {
  content: ''; position: absolute; top: -60%; bottom: -60%; left: -75%;
  width: 45%; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.45), transparent);
  transform: skewX(-18deg) translateX(0);
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .btn-primary::after,
  .btn-pill::after,
  .btn-pill-light::after {
    opacity: 1;
    /* linear, deliberately. --ease-out is a hard decelerate: on a segment
       this short it puts the highlight across the button in the first few
       frames and parks it, so the sweep reads as a flash rather than a
       travel. An even rate is what makes it look like light moving. */
    animation: zl-gloss 5s linear infinite;
  }

  /* Hovering brings the next pass forward rather than waiting for the cycle. */
  .btn-primary:hover::after,
  .btn-pill:hover::after,
  .btn-pill-light:hover::after {
    animation: zl-gloss-once .9s linear;
  }

  /* The travel happens in the first fifth; the remainder parks it off the
     far edge, out of sight, until the cycle comes round again. */
  @keyframes zl-gloss {
    0%   { transform: skewX(-18deg) translateX(0); }
    18%  { transform: skewX(-18deg) translateX(430%); }
    100% { transform: skewX(-18deg) translateX(430%); }
  }
  /* The hover pass is the same travel with no parked tail. */
  @keyframes zl-gloss-once {
    from { transform: skewX(-18deg) translateX(0); }
    to   { transform: skewX(-18deg) translateX(430%); }
  }
}

.btn-primary:disabled { background: var(--muted); color: #fff; cursor: not-allowed; box-shadow: none; }

/* Google's brand guidelines require their mark on a plain white or plain
   dark button, so this one deliberately opts out of the glass treatment. */
.btn-google {
  display: inline-flex; align-items: center; justify-content: center; gap: .65rem;
  width: 100%; padding: 1.05rem 1.5rem; border-radius: 999px; min-height: 48px;
  background: #fff; border: 1px solid var(--border-light); color: var(--text);
  font-family: var(--body); font-size: .84rem; font-weight: 600; letter-spacing: .01em;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
  cursor: pointer;
}
.btn-google:hover { border-color: var(--text2); box-shadow: 0 2px 10px rgba(22, 18, 15, .08); }
.btn-google:disabled { opacity: .55; cursor: not-allowed; box-shadow: none; }
.btn-google svg { width: 18px; height: 18px; flex-shrink: 0; }

/* "or" rule between the Google button and the email forms */
.auth-divider {
  display: flex; align-items: center; gap: .9rem;
  margin: 1.25rem 0; color: var(--muted);
  font-size: .72rem; text-transform: uppercase; letter-spacing: .14em;
}
.auth-divider::before, .auth-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.btn-ghost {
  background: rgba(255, 255, 255, .42);
  -webkit-backdrop-filter: blur(30px) saturate(180%) brightness(1.25);
          backdrop-filter: blur(30px) saturate(180%) brightness(1.25);
  border: 1px solid rgba(255, 255, 255, .62);
  box-shadow: none;
  position: relative; overflow: hidden;
  color: var(--text);
}
.btn-ghost:hover {
  background: rgba(255, 255, 255, .58);
  border-color: rgba(255, 255, 255, .95); color: var(--ink);
}
.btn-block { width: 100%; }

/* ===== BADGES / PILLS ===== */
.pill { display: inline-flex; align-items: center; gap: .4rem; padding: .4rem .85rem; border-radius: 999px; background: var(--card); border: 1px solid var(--border); font-size: .7rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text2); font-weight: 600; }
.pill-accent { border-color: transparent; background: var(--accent); color: #fff; }
.pill-warn { border-color: rgba(180,107,0,.4); color: var(--warn); background: rgba(180,107,0,.08); }
.pill-row { display: flex; gap: .6rem; flex-wrap: wrap; }

/* ===== FORMS ===== */
.field { display: flex; flex-direction: column; gap: .45rem; margin-bottom: 1.1rem; }
.field label { font-size: .7rem; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); font-weight: 600; }
.field input, .field textarea, .field select { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: .95rem 1.05rem; color: var(--text); transition: border-color .25s, box-shadow .25s; width: 100%; }
.field textarea { min-height: 140px; resize: vertical; }
.field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px rgba(22,18,15,.08); }
.field .err { font-size: .74rem; color: var(--accent-dk); display: none; }
/* A prefixed field: the wrapper draws the box, the input inside it is
   stripped bare so the two read as one control rather than as a label
   sitting next to a second field. */
.input-prefix { display: flex; align-items: stretch; background: var(--card); border: 1px solid var(--border); border-radius: 12px; transition: border-color .25s, box-shadow .25s; }
/* An input, so it has to shed the field styling it would otherwise inherit
   and sit flush against the number beside it. Sized to +999 and no wider:
   any more and it reads as a second field rather than a prefix.

   Two classes, and they are load-bearing. `.field input` sets width:100%
   at (0,1,1), which outweighs a bare `.input-prefix-tag` at (0,1,0) - so
   the width below never applied and the country code took the whole flex
   line: 433px of a 435px box, with the number input squeezed to a 17px
   sliver sitting outside the rounded border. Every keystroke therefore
   landed in the country code, which caps at three digits, so the box
   filled up with "+917" and refused everything after it. */
.input-prefix .input-prefix-tag {
  width: 4.1rem; flex: none; border: none; background: transparent;
  padding: .95rem .35rem .95rem 1.05rem; color: var(--text2);
  font-size: .95rem; font-family: inherit; text-align: left;
}
.input-prefix .input-prefix-tag:focus { outline: none; color: var(--text); }
/* min-width:0 so the number shrinks within the flex line. An input's
   automatic minimum is its intrinsic size, which on a narrow phone would
   push it past the wrapper's edge again by a different route. */
.input-prefix input { border: none; border-radius: 0; padding-left: 0; background: transparent; min-width: 0; }
.input-prefix input:focus { box-shadow: none; border-color: transparent; }
/* Focus and error move to the wrapper, since it owns the visible border. */
.input-prefix:focus-within { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(22,18,15,.08); }
.field.invalid .input-prefix { border-color: var(--accent-dk); }

.field.invalid input, .field.invalid textarea, .field.invalid select { border-color: var(--accent-dk); }
.field.invalid .err { display: block; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; gap: 0; } }

/* ===== TABLES ===== */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.data { width: 100%; border-collapse: collapse; min-width: 480px; font-size: .92rem; }
table.data th, table.data td { text-align: left; padding: .9rem 1rem; border-bottom: 1px solid var(--border); vertical-align: top; }
table.data th { color: var(--text2); font-weight: 600; font-size: .74rem; text-transform: uppercase; letter-spacing: .12em; }
table.data td { color: var(--text2); }
table.data td:first-child { color: var(--text); }
table.data tr:last-child td { border-bottom: none; }

/* On a phone a two-column spec table can only be read by scrolling it
   sideways, so each row becomes a stacked label/value pair instead. */
@media (max-width: 620px) {
  table.data { min-width: 0; display: block; }
  table.data tbody, table.data tr, table.data td { display: block; width: 100%; }
  table.data tr { padding: .85rem 0; border-bottom: 1px solid var(--border); }
  table.data tr:last-child { border-bottom: none; }
  table.data td { border: none; padding: 0; }
  table.data td:first-child { color: var(--text2); font-size: .72rem; text-transform: uppercase; letter-spacing: .12em; margin-bottom: .3rem; }
  table.data td:last-child { color: var(--text); font-size: .95rem; }
}

/* ===== FAQ ===== */
details.faq { border: 1px solid var(--border); border-radius: 16px; padding: 1.1rem 1.35rem; margin-bottom: .6rem; background: var(--card); }
details.faq summary { cursor: pointer; font-weight: 600; font-size: 1rem; list-style: none; display: flex; justify-content: space-between; gap: 1rem; align-items: center; min-height: 44px; padding: .5rem 0; }
details.faq summary::-webkit-details-marker { display: none; }
details.faq summary::after { content: '+'; color: var(--text2); font-size: 1.3rem; line-height: 1; }
details.faq[open] summary::after { content: '\2212'; }
details.faq p { color: var(--text2); font-size: .93rem; margin-top: .85rem; }

/* ===== STEPS ===== */
.step-num { font-family: var(--display); font-weight: 700; font-size: 1.6rem; color: var(--accent); line-height: 1; margin-bottom: .6rem; display: block; }

/* ===== NOTES ===== */
.note { border: 1px solid rgba(180,107,0,.35); color: var(--warn); background: rgba(180,107,0,.07); border-radius: 12px; padding: .85rem 1.1rem; font-size: .88rem; }
.note-ok { border-color: rgba(244,67,108,.35); color: var(--accent-dk); background: var(--glow); }

/* ===== REVEAL ON SCROLL =====
   Content is visible by default and only hidden once the inline head script
   has confirmed JavaScript is running (.js on <html>). Without that guard a
   failed script, a blocked script, or an IntersectionObserver that never
   fires would leave the entire page blank at opacity 0. */
.reveal { opacity: 1; transform: none; }
.js .reveal { opacity: 0; transform: translateY(24px); transition: opacity .7s var(--ease-out), transform .7s var(--ease-out); }
.js .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* ===== FOOTER ===== */
.site-footer { background: var(--panel-deep); color: #efe7dd; border-radius: var(--radius) var(--radius) 0 0; padding: clamp(2.5rem, 5vw, 4rem) 0 2rem; margin-top: clamp(2rem, 5vw, 4rem); }
.site-footer h4 { font-size: .74rem; text-transform: uppercase; letter-spacing: .14em; color: #efe7dd; margin-bottom: 1rem; font-family: var(--body); }
.site-footer a { color: rgba(239,231,221,.62); font-size: .9rem; display: block; padding: .35rem 0; transition: color .25s; }
.site-footer a:hover { color: #fff; }
.footer-bottom { border-top: 1px solid rgba(239,231,221,.16); margin-top: 2.5rem; padding-top: 1.5rem; color: rgba(239,231,221,.5); font-size: .7rem; line-height: 1.5; display: flex; flex-wrap: wrap; gap: .25rem 1rem; justify-content: center; text-align: center; }

/* ===== GLASS FALLBACK =====
   Without backdrop-filter the tints would read as washed-out rectangles,
   so those browsers get the solid colours back. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .btn-primary { background: var(--ink); }
  .btn-primary:hover { background: #322a24; }
  .btn-ghost { background: #fff; }
}

/* No sheen, gloss or bevel: those read as a moulded 3D object. The glass
   here is a flat pane - transparency, a blurred backdrop and one hairline
   edge do all the work. */

/* WhatsApp call to action on the contact card. Uses WhatsApp's own green
   rather than the site accent, because it is naming another product. */
.btn-wa {
  display: inline-flex; align-items: center; gap: .5rem;
  margin-top: .9rem; padding: .7rem 1.15rem; min-height: 44px;
  border-radius: 999px; background: #25d366; color: #0b3d1f;
  font-size: .78rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  transition: background .25s var(--ease), transform .25s var(--ease);
}
.btn-wa:hover { background: #1fbe5a; }
.btn-wa svg { width: 17px; height: 17px; flex: none; }

/* Present for a screen reader and for the document outline, absent on screen.
   A page with no h1 at all is worse than one whose h1 is not drawn. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
