/* ==========================================================================
   NHV-33 — Age gate
   ==========================================================================
   The "Are you 18 or older?" modal, on every page until the shopper answers.

   Paired with catalog/view/theme/nhv/template/extension/ageverifypro/
   ageverifypro.twig, which is our override of the ageverifypro extension's own
   template. The extension still decides WHETHER to show the gate, supplies the
   logo, background image and wording from its admin screen, and owns the
   cookie. Everything below is only how it looks.

   NOTHING HERE IS NAMED THE WAY THE EXTENSION NAMES THINGS. Its stylesheet is
   added by its controller with addStyle(), and header.twig renders {{ styles }}
   after every one of our block stylesheets — so at equal specificity it wins.
   Using our own names means its rules never match ours and there is no fight.
   ========================================================================== */

/* The lock. `.mp-modal-open{overflow:hidden}` in the extension's stylesheet
   used to do this; we do not use that class any more. On <html> as well as
   <body> because iOS Safari ignores it on body alone. */
html.nhv-agegate-open,
body.nhv-agegate-open { overflow: hidden; }

.nhv-agegate {
  position: fixed;
  inset: 0;
  z-index: 3000;                    /* over the sticky header and the cart drawer */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--nhv-gutter);
}

/* `inset` is not understood before Safari 14.1 / Chrome 87, and a dialog that
   collapses to nothing is a shop with no age gate — so the four sides are
   spelled out as well. Same reason the rule is not merged into the one above:
   an engine that chokes on `inset` must still get these. */
.nhv-agegate { top: 0; right: 0; bottom: 0; left: 0; }

/* --- The page behind ------------------------------------------------------
   Darkened and drained of colour, so the shop is clearly still there but
   clearly not available yet. The filter is the nice-to-have; the flat veil
   underneath is what actually does the work, and it is what a browser without
   backdrop-filter is left with. */
.nhv-agegate-veil {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgba(2, 19, 27, 0.78);
}
@supports (backdrop-filter: grayscale(1)) or (-webkit-backdrop-filter: grayscale(1)) {
  .nhv-agegate-veil {
    background: rgba(2, 19, 27, 0.62);
    -webkit-backdrop-filter: grayscale(0.85) blur(2px);
    backdrop-filter: grayscale(0.85) blur(2px);
  }
}

/* --- The panel ------------------------------------------------------------ */

.nhv-agegate-panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 520px;

  /* Tall on purpose. The panel is only as tall as its words otherwise, and a
     square photograph behind a 300px-tall box is cropped to a strip — you get
     the top of a hookah and some foliage instead of the picture. min() rather
     than a flat value so a short viewport takes the viewport's height and the
     max-height below never has to fight it. */
  min-height: 640px;
  min-height: min(640px, calc(100vh - (var(--nhv-gutter) * 2)));
  max-height: calc(100vh - (var(--nhv-gutter) * 2));
  overflow-y: auto;
  background-color: var(--nhv-footer-ground);
  border: 1px solid var(--nhv-navy-border);
  border-radius: var(--nhv-radius-sm);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);

  /* The one piece of copper on the panel. Drawn as an inset shadow rather than
     a border so it does not double up with the border above. */
  box-shadow: inset 0 3px 0 var(--nhv-copper), 0 24px 60px rgba(0, 0, 0, 0.55);
}

/* The photograph, as an element rather than a CSS background — see the note in
   the template. object-fit means it fills the panel at any panel height without
   being stretched, whatever the admin uploads. */
.nhv-agegate-bg {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* The scrim is not a wash, it is a ramp, and the stops are measured rather than
   chosen.

   The photograph is picked in the admin by someone who cannot see this file, so
   the type has to survive whatever they upload. The current one is very dark on
   average — luminance 0.01 to 0.03 — but the vapour plume peaks at 0.78, and
   against --nhv-cream-bright a 0.78 highlight needs 78% opacity over it before
   the text clears AA. Flat at 78% the photograph is gone.

   So the ramp is light where the picture is and heavy where the words are. The
   panel's own bands, measured off the rendered page, and the worst PIXEL in the
   photograph under each:

     band          panel %      max L    alpha    result
     logo          6.7 - 33.9   0.32     0.30     picture reads normally
     open photo    34 - 66.7    0.78     0.30     the subject of the shot
     title         66.7 - 72.3  0.70     0.80     5.30:1
     copy          74.5 - 84.5  0.72     0.88     7.32:1
     buttons       88 - 95.2    0.10     0.88     solid colour anyway

   Worst-pixel figures, not averages — the 99th percentile clears AA well below
   these. The photograph is 700x700 and the panel crops it horizontally only, so
   a panel percentage and an image percentage are the same thing here; if the
   panel's proportions change, these stops want re-measuring. */
.nhv-agegate-scrim {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-image: linear-gradient(
    180deg,
    rgba(2, 19, 27, 0.28) 0%,
    rgba(2, 19, 27, 0.30) 34%,
    rgba(2, 19, 27, 0.42) 60%,
    rgba(2, 19, 27, 0.80) 67%,
    rgba(2, 19, 27, 0.88) 75%,
    rgba(2, 19, 27, 0.88) 100%
  );
}

.nhv-agegate-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: 42px 34px 30px;
  text-align: center;
}

/* margin-bottom:auto rather than a wrapper round everything else. In a flex
   column that one declaration pushes the title, copy and buttons to the foot of
   the panel and leaves the slack between them and the logo — which is the
   photograph. */
.nhv-agegate-logo {
  display: block;
  width: 172px;
  max-width: 60%;
  height: auto;
  margin: 0 auto auto;
}

.nhv-agegate-title {
  margin: 24px 0 14px;
  font-family: var(--nhv-font-display);
  font-size: 30px;
  font-weight: var(--nhv-fw-bold);
  line-height: 1.2;
  color: var(--nhv-cream-bright);            /* 18.55:1 */
}

/* The copy is admin-authored HTML from the extension's editor, so this styles
   whatever it turns out to be rather than a known shape. */
.nhv-agegate-copy {
  margin: 0 0 22px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-lead);
  line-height: 1.7;
  color: var(--nhv-cream);                   /* 16.95:1 */
}
.nhv-agegate-copy p { margin: 0 0 10px; }
.nhv-agegate-copy p:last-child { margin-bottom: 0; }
/* The editor leaves a trailing <br> at the end of the first paragraph, which
   opens a blank line in the middle of four lines of text. */
.nhv-agegate-copy p > br:last-child { display: none; }
.nhv-agegate-copy a {
  color: var(--nhv-copper-text);             /* 6.51:1 */
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* --- Buttons --------------------------------------------------------------
   The brand already has a green and a red — the "In Stock" green and the SALE
   red — and they were picked to carry the same weight as each other. Reusing
   them here keeps a bright Bootstrap green and a bright Bootstrap red off the
   one screen every single visitor sees. */

.nhv-agegate-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
}

.nhv-agegate-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 148px;
  margin: 0;
  padding: 13px 26px;
  font-family: var(--nhv-font-display);
  font-size: var(--nhv-fs-base);
  font-weight: var(--nhv-fw-semi);
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-align: center;
  text-decoration: none;
  color: var(--nhv-cream-bright);
  border: 1px solid transparent;
  border-radius: var(--nhv-radius-sm);
  cursor: pointer;
  transition: background-color var(--nhv-transition), border-color var(--nhv-transition), transform var(--nhv-transition);
}
.nhv-agegate-btn:hover,
.nhv-agegate-btn:focus { color: var(--nhv-cream-bright); text-decoration: none; }
.nhv-agegate-btn:active { transform: translateY(1px); }
.nhv-agegate-btn:focus-visible { outline: 2px solid var(--nhv-copper); outline-offset: 3px; }
.nhv-agegate-btn:focus { outline: 2px solid var(--nhv-copper); outline-offset: 3px; }
.nhv-agegate-btn:focus:not(:focus-visible) { outline: none; }

.nhv-agegate-yes {
  background: var(--nhv-stock-green);        /* 6.36:1 with cream-bright */
  border-color: var(--nhv-stock-green);
}
.nhv-agegate-yes:hover,
.nhv-agegate-yes:focus { background: #175737; border-color: #175737; }   /* 8.40:1 */

.nhv-agegate-no {
  background: var(--nhv-sale-red);           /* 7.06:1 with cream-bright */
  border-color: var(--nhv-sale-red);
}
.nhv-agegate-no:hover,
.nhv-agegate-no:focus { background: #8C2419; border-color: #8C2419; }    /* 8.66:1 */

/* While the POST is in flight. Disabled rather than just dimmed, so a second
   click cannot fire a second request. */
.nhv-agegate-btn.is-busy,
.nhv-agegate-btn[disabled] { opacity: 0.65; cursor: default; }

.nhv-agegate-error {
  margin: 0 0 16px;
  padding: 10px 14px;
  font-family: var(--nhv-font-body);
  font-size: var(--nhv-fs-base);
  color: var(--nhv-cream-bright);
  background: var(--nhv-sale-red);
  border-radius: var(--nhv-radius-sm);
}

/* --- Motion ---------------------------------------------------------------
   A short rise on the way in and a fade on the way out. Both are decoration:
   the panel is at its final position before the animation starts, so an engine
   that ignores it shows the gate correctly, just instantly. */

.nhv-agegate-panel {
  animation: nhv-agegate-in 260ms ease-out both;
}
@keyframes nhv-agegate-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

.nhv-agegate.is-going { opacity: 0; transition: opacity 240ms ease; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .nhv-agegate-panel { animation: none; }
  .nhv-agegate.is-going { transition: none; }
  .nhv-agegate-btn { transition: none; }
}

/* --- Small screens --------------------------------------------------------
   100dvh, with 100vh underneath it: on mobile Safari 100vh is the height with
   the browser chrome hidden, so the bottom of a full-height panel — the two
   buttons — sits underneath the address bar until you scroll. */
@media (max-width: 600px) {
  .nhv-agegate { padding: 10px; }
  .nhv-agegate-panel { min-height: min(560px, calc(100vh - 20px)); max-height: calc(100vh - 20px); }
  .nhv-agegate-body { padding: 24px 20px 22px; }
  /* width only — a margin-bottom here would overwrite the `auto` that holds
     the copy against the foot of the panel, and the slack would fall to the
     bottom of the box instead of into the photograph. */
  .nhv-agegate-logo { width: 132px; }
  .nhv-agegate-title { font-size: 24px; }
  .nhv-agegate-copy { font-size: var(--nhv-fs-base); margin-bottom: 18px; }
  .nhv-agegate-actions { gap: 10px; }
  .nhv-agegate-btn { flex: 1 1 100%; min-width: 0; }
}
@supports (height: 100dvh) {
  .nhv-agegate-panel {
    min-height: min(640px, calc(100dvh - (var(--nhv-gutter) * 2)));
    max-height: calc(100dvh - (var(--nhv-gutter) * 2));
  }

  @media (max-width: 600px) {
    .nhv-agegate-panel {
      min-height: min(560px, calc(100dvh - 20px));
      max-height: calc(100dvh - 20px);
    }
  }
}

/* A very short viewport — a phone in landscape — has no room for a 172px logo
   above four lines of text and two buttons. */
@media (max-height: 560px) {
  .nhv-agegate-logo { width: 96px; }
  .nhv-agegate-title { font-size: 22px; margin-bottom: 8px; }
  .nhv-agegate-body { padding: 20px 22px 18px; }
}
