/*
 * Antrino site fixes.
 *
 * Loaded after the Webflow export so it can override it. Keeping every
 * hand-written rule in this one file means a future Webflow re-export can be
 * dropped in without losing the Fas 1 remediation work.
 */

/* ------------------------------------------------------------------ *
 * Semantic headings (BUG-046, BUG-047)
 * ------------------------------------------------------------------ *
 * Webflow exported every heading as a styled <div>, so the pages had no
 * heading elements at all. The divs are now h1/h2/h3, which keeps the
 * .header-* classes for sizing but also pulls in the browser's heading
 * margins (h1 20px/10px, h2 and h3 40px/10px) that the original divs never
 * had. Zeroing them keeps the visual layout byte-for-byte identical.
 *
 * Only margin is reset: .header-l/m/s/xs already declare their own
 * font-size, font-weight and line-height, and win on specificity.
 */

h1[class*="header-"],
h2[class*="header-"],
h3[class*="header-"],
h4[class*="header-"],
h5[class*="header-"],
h6[class*="header-"] {
  margin-top: 0;
  margin-bottom: 0;
}

/* ------------------------------------------------------------------ *
 * Focus visibility (BUG-043, BUG-044)
 * ------------------------------------------------------------------ *
 * The export relied on the UA default focus ring, which is near-black and
 * therefore invisible on the black navbar and the black CTA buttons.
 *
 * Two rings are drawn deliberately: the dark outline carries the light
 * surfaces and the green halo outside it carries the dark ones, so a single
 * declaration is visible everywhere without auditing each component.
 */

:focus-visible {
  outline: 2px solid var(--color--black, #171a19);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--color--green, #4dffd2);
}

/* Only suppress the default ring where :focus-visible is supported, so
   keyboard focus is never removed in older browsers. */
:focus:not(:focus-visible) {
  outline: none;
}

/* ------------------------------------------------------------------ *
 * Text contrast (BUG-045)
 * ------------------------------------------------------------------ *
 * .black-50 is 50% black, which measures 3.32:1 against the page
 * background - below the 4.5:1 required for body-sized text. 70% takes it
 * to roughly 5.4:1 while keeping the muted look.
 */

.black-50,
.says-trust {
  color: rgba(23, 26, 25, 0.7);
}

/* .tag hardcodes near-black text and ships dark bracket icons. Inside an
 * .invert block (the dark cards on Product and Retail) that overrides the
 * white set by .invert, leaving the step numbers at 1.82:1. */

.invert .tag,
.invert .tag div {
  color: var(--color--white, #fff);
}

.invert .tag .brackets,
.invert .tag .dot {
  filter: invert(1);
}

/* ------------------------------------------------------------------ *
 * Tap targets (BUG-051 - BUG-057)
 * ------------------------------------------------------------------ *
 * The nav and footer links render at 19-22px tall. WCAG 2.2 target size
 * (minimum) asks for 24px, so the height is padded out without moving the
 * text: the links are inline-flex and vertically centred, which changes the
 * box but not the baseline position.
 */

a.header-xs.link,
a.body-regular.link,
a.link-block,
.link-w-icon {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

/* ------------------------------------------------------------------ *
 * Mobile nav reachability at high zoom (BUG-040)
 * ------------------------------------------------------------------ *
 * The overlay menu is a fixed-height panel with overflow visible, so any
 * item past the fold is unreachable with no way to scroll to it. It fits at
 * 200% zoom on the sizes tested, but there is no margin: a shorter window,
 * larger text or one more nav item would strand the last link. Making the
 * panel scroll removes the whole class of failure.
 */

@media screen and (max-width: 991px) {
  .nav-menu-wrapper.w-nav-menu {
    max-height: 100vh;
    max-height: 100dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
}

/* ------------------------------------------------------------------ *
 * Hero text / animation overlap (BUG-041)
 * ------------------------------------------------------------------ *
 * .hero-animation_wrap has padding-top:100px on desktop and 300px at
 * <=991px, where the mobile layout kicks in. Between those two the heading
 * has wrapped onto a third line but the animation was still sitting at the
 * desktop offset, so the panels were drawn straight through the heading and
 * the intro paragraph.
 *
 * The desktop offset is no longer sufficient either, now that the hero
 * carries a row of calls to action under the headline. The canvas is 2:1 and
 * its height therefore tracks the viewport width, so the wider the window
 * the higher the panels reach into the text: at 1440px they started 40px
 * below the headline. One offset for the whole desktop range clears the
 * text everywhere and leaves the widest windows with more air, which is how
 * the hero already reads at 1024px.
 */

@media screen and (min-width: 992px) {
  .hero-animation_wrap {
    padding-top: 400px;
  }
}

/* ------------------------------------------------------------------ *
 * Hero animation clipped in landscape mobile (BUG-038)
 * ------------------------------------------------------------------ *
 * Below 991px the animation is blown up to width:200% inside a wrap that is
 * 160vh tall with overflow:hidden. The canvas keeps a 2:1 ratio, so at
 * 200% width it becomes as tall as the viewport is wide. In portrait there
 * is room for that; in landscape 160vh is short and the wrap cuts the
 * panels off entirely, leaving an empty hero.
 *
 * At 100% width the canvas is 50vw tall, so the wrap is sized to hold the
 * text block plus the animation instead of a viewport-relative height.
 */

@media screen and (max-width: 991px) and (orientation: landscape) {
  .section-hero {
    min-height: calc(400px + 50vw);
  }

  .hero-animation_wrap {
    height: calc(400px + 50vw);
    padding-top: 360px;
    overflow: visible;
  }

  .hero-animation {
    width: 100%;
    top: 0;
  }
}

/* ------------------------------------------------------------------ *
 * Accordion labels clipped on Retail (BUG-005)
 * ------------------------------------------------------------------ *
 * .accordion-trigger-faq is pinned to a fixed height of one line. Around
 * 1024px the accordion column narrows to ~206px, so "Concealment & bag
 * theft" and "Violence & aggression" wrap onto a second line and that line
 * is cut off by the overflow:hidden on .accordion-item.
 *
 * Swapping the fixed height for a min-height keeps the one-line layout
 * everywhere it already fits and lets the trigger grow where it does not.
 * The variants are restated because they also set a fixed height.
 */

.accordion-trigger-faq,
.accordion-trigger-faq.medium {
  height: auto;
  min-height: 26px;
}

.accordion-trigger-faq:where(.w-variant-f16a7c22-00fd-103b-659a-faadd02e0d5f),
.accordion-trigger-faq:where(.w-variant-50ca4142-21d1-66cb-fe48-7d210526c3e8) {
  height: auto;
  min-height: 33px;
}

/* ------------------------------------------------------------------ *
 * Layout shift from the navbar logo (BUG-042)
 * ------------------------------------------------------------------ *
 * .logo-destop already declares a size, but .logo - the one shown below
 * 991px - was auto/auto, so it measured 0x0 until the SVG arrived and the
 * whole navbar jumped. The intrinsic width/height attributes added to the
 * markup cover browsers that honour them; this pins the rendered size too.
 */

.logo {
  width: 28px;
  height: 25px;
}

/* ------------------------------------------------------------------ *
 * Book a demo form validation (BUG-003, BUG-007 - BUG-012)
 * ------------------------------------------------------------------ */

.form-error {
  color: #b3261e;
  font-family: var(--sans), Arial, sans-serif;
  font-size: 14px;
  line-height: 1.4;
  margin-top: 8px;
}

.form-error[hidden] {
  display: none;
}

.form-status {
  font-family: var(--sans), Arial, sans-serif;
  font-size: 14px;
  line-height: 1.4;
  margin-top: 16px;
}

.form-status--error {
  color: #b3261e;
}

.text-field[aria-invalid="true"] {
  border-color: #b3261e;
}

/* The radio itself is a styled span in the Webflow markup, so the invalid
   state has to be drawn on that rather than on the input. */
input[type="radio"][aria-invalid="true"] + span,
input[type="radio"][aria-invalid="true"] {
  border-color: #b3261e;
}

/* Submit button busy state while the submission is in flight. */
.button[aria-busy="true"],
input[type="submit"][aria-busy="true"] {
  cursor: progress;
  opacity: 0.7;
}

/* hCaptcha checkbox, mounted above the submit button by js/form-handler.js.
   The widget is a fixed 303x78 iframe, so the box is reserved up front to
   stop the submit button jumping down when it arrives. */
.form-captcha-field {
  margin-bottom: 24px;
}

.form-captcha {
  min-height: 78px;
}

/* ------------------------------------------------------------------ *
 * Cookie consent banner (js/cookie-consent.js)
 * ------------------------------------------------------------------ *
 * Sits above the navbar (999) but under the Book a demo modal (1002), so it
 * never covers the form's submit button. Both choices share one button
 * style: refusing must not look like the lesser option.
 */

.cookie-banner {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: 16px;
  z-index: 1001;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: 16px 32px;
  max-width: 960px;
  margin: 0 auto;
  padding: 20px 24px;
  background-color: var(--color--bg, #fcfaf7);
  color: var(--color--black, #171a19);
  border: 1px solid var(--border, #1b1e1d4d);
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(23, 26, 25, 0.16);
  font-family: var(--sans), Arial, sans-serif;
}

.cookie-banner[hidden] {
  display: none;
}

.cookie-banner__body {
  flex: 1 1 360px;
}

.cookie-banner__title {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
}

.cookie-banner__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
}

.cookie-banner__link {
  color: inherit;
  text-decoration: underline;
}

.cookie-banner__actions {
  display: flex;
  flex-flow: row wrap;
  gap: 12px;
}

.cookie-banner__button {
  min-height: 40px;
  padding: 8px 16px;
  background-color: var(--color--black, #171a19);
  color: var(--color--white, #fff);
  border: 0;
  border-radius: 4px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

@media screen and (max-width: 479px) {
  .cookie-banner {
    left: 8px;
    right: 8px;
    bottom: 8px;
    padding: 16px;
  }

  .cookie-banner__actions,
  .cookie-banner__button {
    flex: 1 1 auto;
  }
}

/* The footer "Cookie settings" control is a button carrying the footer link
   classes, so the UA button chrome is stripped back to match its siblings. */
button.cookie-settings {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* ------------------------------------------------------------------ *
 * [fade-in] reveal fallback
 * ------------------------------------------------------------------ *
 * Each page carries an inline `[fade-in] { opacity: 0 }` and animates it
 * back with GSAP. Two ways that leaves the page blank forever: scripting is
 * off, or the GSAP CDN does not answer. Both are covered here.
 *
 * !important is required because the rule being overridden lives in a
 * <style> at the end of <body>, which outranks this file on document order.
 *
 * .w-mod-js is set on <html> by Webflow's first inline script, so its
 * absence is a reliable no-JavaScript signal. .reveal-fallback is set by
 * js/site-boot.js and only when the animation has demonstrably not started.
 */

html:not(.w-mod-js) [fade-in],
html.reveal-fallback [fade-in] {
  opacity: 1 !important;
  transform: none !important;
  visibility: visible !important;
}

/* ------------------------------------------------------------------ *
 * Reduced motion
 * ------------------------------------------------------------------ *
 * The export honoured prefers-reduced-motion nowhere. The scripted parts
 * (hero 3D scene, scrubbed headline, logo marquee, background video) are
 * handled in js/site-boot.js and the inline page scripts; what is left here
 * is the [fade-in] reveal and the CSS transitions.
 *
 * Same !important reasoning as the fallback above: the rule being overridden
 * sits in a <style> at the end of <body>.
 */

@media (prefers-reduced-motion: reduce) {
  [fade-in] {
    opacity: 1 !important;
    transform: none !important;
  }

  .card-5col,
  .image_radius,
  .hero-still {
    transition: none !important;
  }
}

/* ------------------------------------------------------------------ *
 * Hero fallback still
 * ------------------------------------------------------------------ *
 * The first viewport is 160vh of 3D scene loaded from unpkg and
 * prod.spline.design. Until both answer - and permanently if either is
 * blocked, which is likely on the corporate networks this is sold into -
 * the hero was blank. This is a render of the same scene, sized like the
 * canvas next to it.
 *
 * It starts hidden. The scene is a continuous animation, so no still can
 * match the frame Spline draws next, and showing one up front meant the hero
 * visibly jumped poses on every single load. The inline module in index.html
 * only adds .is-visible once the scene has failed to turn up.
 *
 * Width-driven height rather than inset:0, because .hero-animation takes its
 * own height from the canvas and would not give the image a box to fill.
 */

.hero-still {
  pointer-events: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: auto;
  opacity: 0;
  transition: opacity 0.6s ease;
}

.hero-still.is-visible {
  opacity: 1;
}

/* ------------------------------------------------------------------ *
 * Hero call to action
 * ------------------------------------------------------------------ *
 * The hero shipped one link, "See how it works", which opened the demo
 * booking modal - a visitor asking to be shown the product was handed a
 * form asking for their email and camera count instead. It also sat in a
 * two-of-twelve column cell at the far right of the grid, where the label
 * wraps and, at 1024px, never appeared in the first viewport at all.
 *
 * It is now a pair directly under the headline: the modal keeps a primary
 * button, and "See how it works" points at #how-it-works, the three-step
 * section that answers it.
 */

.hero-actions {
  flex-flow: row wrap;
  align-items: center;
  gap: 16px 32px;
}

@media screen and (min-width: 992px) {
  #w-node-_0c0ac5df-6475-038a-bd8b-3686bd38f2eb-01ceb03c {
    grid-area: 2 / 1 / 3 / 7;
  }
}

/* ------------------------------------------------------------------ *
 * Duplicate node ids on the home page
 * ------------------------------------------------------------------ *
 * The "Four kinds of question" section was a copy of the block above it and
 * came through the export with four ids that already existed on the page:
 * the section tag reused the one from "The bigger picture", and the fourth
 * question reused the dot, heading and body ids from the first. Duplicate
 * ids are invalid and the grid placement they carry is undefined.
 *
 * The four elements now have unique ids; these rules restate the placement
 * the old ones were getting from the Webflow stylesheet.
 */

#antrino-four-questions-tag {
  grid-area: span 1 / span 6 / span 1 / span 6;
  justify-self: start;
}

#antrino-q4-dot {
  align-self: center;
}

#antrino-q4-heading {
  grid-area: span 1 / span 5 / span 1 / span 5;
}

#antrino-q4-body {
  grid-area: span 1 / span 3 / span 1 / span 3;
}

@media screen and (max-width: 991px) {
  #antrino-q4-body {
    grid-area: 2 / 2 / 3 / 7;
  }
}
