/* ==========================================================================
   IMS Services — overlays
   The cookie notice, the sign-up popup and the floating WhatsApp button.

   These three sit above the page, so this sheet loads after components.css
   and wins the cascade against it.

   Colour discipline is the same as everywhere else: navy is ground, teal is
   structure, cyan is signal only. The WhatsApp button is teal, not cyan: it is
   always there and nothing about it is live. Cyan appears here in exactly one
   place, the focus ring, because focus IS a live state.
   ========================================================================== */

/* ==========================================================================
   Cookie notice

   A bar at the foot of the page, never a full-screen blocker. Someone who came
   for the phone number must be able to read it, scroll, and answer this later.
   Capped at 70dvh and scrollable inside itself so even a long policy
   paragraph on a small phone cannot swallow the viewport.
   ========================================================================== */

.ims-cookie {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--ims-z-overlay);

  /* The element carries .ims-deep, which retargets the semantic slots, so
     --ims-bg here is the deep navy ground and text colours follow for free. */
  background-color: var(--ims-bg);
  color: var(--ims-text);
  border-top: 1px solid var(--ims-border);
  box-shadow: var(--ims-shadow-lg);

  max-height: 70dvh;
  overflow-y: auto;
  overscroll-behavior: contain;

  opacity: 0;
  transform: translateY(100%);
  transition:
    opacity var(--ims-dur-base) var(--ims-ease),
    transform var(--ims-dur-slow) var(--ims-ease-out);
}

/* [hidden] is a UA rule and author rules beat it, so display:none has to be
   restated wherever this sheet sets a display value. Without this the notice
   would be present and focusable before the script has decided anything. */
.ims-cookie[hidden] { display: none; }

.ims-cookie.is-open {
  opacity: 1;
  transform: translateY(0);
}

.ims-cookie__inner {
  width: 100%;
  max-width: var(--ims-shell);
  margin-inline: auto;
  padding: var(--ims-sp-5) var(--ims-gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ims-sp-4) var(--ims-sp-6);
}

/* min-width:0 lets the copy shrink rather than push the bar wider than the
   viewport, which is what would otherwise scroll the page sideways at 320px. */
.ims-cookie__body {
  flex: 1 1 20rem;
  min-width: 0;
}

.ims-cookie__heading {
  font-size: var(--ims-fs-h4);
  margin: 0 0 var(--ims-sp-2);
  color: var(--ims-text);
}

.ims-cookie__text {
  margin: 0;
  max-width: 64ch;
  font-size: var(--ims-fs-sm);
  line-height: var(--ims-lh-normal);
  color: var(--ims-text-mid);
}

/* Accept and reject are the same size and the same weight of control. A reject
   button dressed as an afterthought is not a free choice, and POPIA asks for a
   free choice. */
.ims-cookie__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ims-sp-3);
  flex: 0 1 auto;
}

.ims-cookie__btn { flex: 1 1 auto; }

@media (max-width: 34rem) {
  .ims-cookie__inner {
    padding-block: var(--ims-sp-4);
    gap: var(--ims-sp-4);
  }

  .ims-cookie__actions { width: 100%; }
  .ims-cookie__btn { flex: 1 1 100%; }
}

/* ==========================================================================
   Sign-up popup

   A real modal: backdrop, centred card, focus held inside it by the script.
   ========================================================================== */

.ims-popup {
  position: fixed;
  inset: 0;
  z-index: var(--ims-z-modal);
  display: grid;
  place-items: center;
  padding: var(--ims-sp-5) var(--ims-sp-4);
}

.ims-popup[hidden] { display: none; }

.ims-popup__backdrop {
  position: absolute;
  inset: 0;

  /* Opacity on the element rather than a translucent colour value, so the
     ground stays a token and no colour is invented here. */
  background-color: var(--ims-navy-950);
  opacity: 0;
  transition: opacity var(--ims-dur-base) var(--ims-ease);
}

.ims-popup.is-open .ims-popup__backdrop { opacity: 0.72; }

.ims-popup__dialog {
  position: relative;
  width: 100%;
  max-width: 32rem;

  /* Taller than the viewport scrolls inside the card, never the page behind
     it. dvh, so a mobile browser's collapsing address bar cannot clip the
     submit button off the bottom. */
  max-height: calc(100dvh - var(--ims-sp-8));
  overflow-y: auto;
  overscroll-behavior: contain;

  padding: var(--ims-sp-7) var(--ims-sp-6) var(--ims-sp-6);
  background-color: var(--ims-bg);
  border: 1px solid var(--ims-border);
  border-radius: var(--ims-r-lg);
  box-shadow: var(--ims-shadow-lg);

  opacity: 0;
  transform: translateY(12px) scale(0.98);
  transition:
    opacity var(--ims-dur-base) var(--ims-ease),
    transform var(--ims-dur-base) var(--ims-ease-spring);
}

.ims-popup.is-open .ims-popup__dialog {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.ims-popup__close {
  position: absolute;
  top: var(--ims-sp-3);
  right: var(--ims-sp-3);
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border-radius: var(--ims-r-sm);
  color: var(--ims-ink-soft);
  transition:
    color var(--ims-dur-fast) var(--ims-ease),
    background-color var(--ims-dur-fast) var(--ims-ease);
}

.ims-popup__close:hover {
  color: var(--ims-navy-800);
  background-color: var(--ims-mist-100);
}

.ims-popup__heading {
  font-size: var(--ims-fs-h3);
  margin: 0 0 var(--ims-sp-3);

  /* Clear of the close button, so a long heading cannot run under it. */
  padding-right: var(--ims-sp-7);
}

.ims-popup__text {
  margin: 0 0 var(--ims-sp-5);
  max-width: none;
  font-size: var(--ims-fs-sm);
  line-height: var(--ims-lh-normal);
  color: var(--ims-text-mid);
}

/* Tighter than the page default: this is a short form in a small card. */
.ims-popup .ims-field { margin-bottom: var(--ims-sp-4); }

.ims-popup__consent {
  margin: 0 0 var(--ims-sp-5);
  max-width: none;
  font-size: var(--ims-fs-xs);
  line-height: var(--ims-lh-normal);
  color: var(--ims-ink-soft);
}

.ims-overlay-link {
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* The outcome message. Colour is not the only signal: the rule down the left
   edge carries it too, for anyone who cannot tell teal from red. */
.ims-popup__status {
  margin: var(--ims-sp-4) 0 0;
  padding: var(--ims-sp-3) var(--ims-sp-4);
  border-left: 3px solid;
  border-radius: var(--ims-r-xs);
  background-color: var(--ims-mist-50);
  font-size: var(--ims-fs-sm);
  font-weight: 500;
  max-width: none;
}

/* No message yet, no box. */
.ims-popup__status:empty { display: none; }

.ims-popup__status--success {
  border-color: var(--ims-success);
  color: var(--ims-teal-700);
}

.ims-popup__status--error {
  border-color: var(--ims-danger);
  color: var(--ims-danger);
}

/* Signed up. The form has done its job, so it goes and the message stays. The
   script moves focus to the close button before this applies, otherwise focus
   would fall off the submit button and out of the dialog. */
.ims-popup.is-done .ims-field,
.ims-popup.is-done .ims-popup__consent,
.ims-popup.is-done .ims-popup__submit {
  display: none;
}

@media (max-width: 26rem) {
  .ims-popup { padding: var(--ims-sp-3); }

  .ims-popup__dialog {
    padding: var(--ims-sp-6) var(--ims-sp-4) var(--ims-sp-5);
    max-height: calc(100dvh - var(--ims-sp-6));
  }

  .ims-popup__close {
    top: var(--ims-sp-2);
    right: var(--ims-sp-2);
  }

  .ims-popup__heading { padding-right: var(--ims-sp-6); }
}

/* ==========================================================================
   WhatsApp button

   Fixed bottom-right. Teal, because it is a standing affordance rather than a
   live state, and cyan is reserved for things that are actually happening.
   ========================================================================== */

.ims-whatsapp {
  /* The lift is a variable so the raised state changes one value rather than
     restating the whole bottom calculation. */
  --ims-whatsapp-lift: 0rem;

  position: fixed;
  right: var(--ims-gutter);
  bottom: calc(var(--ims-gutter) + var(--ims-whatsapp-lift));

  /* Under the modal, above the page. The cookie notice sits at
     --ims-z-overlay and the button clears it by moving, not by stacking. */
  z-index: calc(var(--ims-z-overlay) - 1);

  width: 3.5rem;
  height: 3.5rem;
  display: grid;
  place-items: center;
  border-radius: var(--ims-r-full);
  background-color: var(--ims-teal-600);
  color: var(--ims-white);
  box-shadow: var(--ims-shadow-md);
  text-decoration: none;
  transition:
    bottom var(--ims-dur-slow) var(--ims-ease-out),
    background-color var(--ims-dur-base) var(--ims-ease),
    transform var(--ims-dur-base) var(--ims-ease-spring),
    box-shadow var(--ims-dur-base) var(--ims-ease);
}

.ims-whatsapp:hover {
  background-color: var(--ims-teal-500);
  color: var(--ims-white);
  transform: translateY(-2px);
  box-shadow: var(--ims-shadow-lg);
}

.ims-whatsapp:active { transform: translateY(0); }

/* Restated rather than left to the global rule, because a control that floats
   over arbitrary page content is exactly the one whose focus ring must not be
   left to chance. */
.ims-whatsapp:focus-visible {
  outline: 3px solid var(--ims-focus);
  outline-offset: 3px;
}

/*
 * THE INTERACTION: while the cookie notice is showing, the button would sit on
 * top of it. overlays.js toggles .is-raised on this element as the notice
 * appears and disappears, and publishes the notice's measured height on <html>
 * as --ims-cookie-height. The height cannot be a constant here because the
 * notice is as tall as the client's copy makes it; the fallback covers the
 * frame before the first measurement, and the case where the script has not
 * run at all.
 */
.ims-whatsapp.is-raised {
  --ims-whatsapp-lift: calc(var(--ims-cookie-height, 11rem) + var(--ims-sp-3));
}

.ims-whatsapp__icon {
  width: 1.65rem;
  height: 1.65rem;
}

/*
 * The blanket `svg { fill: currentColor }` this used to work around is gone;
 * base.css now scopes it to svg:not([fill]), so the fill="none" on a stroked
 * icon wins on its own.
 *
 * The WhatsApp mark is deliberately NOT reset here any more: it is a brand
 * logo, authored as a filled silhouette, and ims_icon() now renders brand
 * marks with fill="currentColor". Forcing fill:none on it drew the outline of
 * a solid shape, which is what made it look skewed.
 */
.ims-popup__close .ims-icon {
  fill: none;
}

/* ==========================================================================
   Reduced motion

   base.css already collapses durations globally. These rules go further and
   remove the movement itself, so nothing slides in from anywhere: state
   changes are simply true or not. Visibility is carried by the hidden
   attribute, which the script sets synchronously in this mode.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .ims-cookie,
  .ims-popup__backdrop,
  .ims-popup__dialog,
  .ims-whatsapp {
    transition: none;
  }

  .ims-cookie,
  .ims-popup__dialog {
    opacity: 1;
    transform: none;
  }

  .ims-popup__backdrop { opacity: 0.72; }

  .ims-whatsapp:hover,
  .ims-whatsapp:active { transform: none; }
}

/* ==========================================================================
   Print
   None of this belongs on paper.
   ========================================================================== */

@media print {
  .ims-cookie,
  .ims-popup,
  .ims-whatsapp {
    display: none !important;
  }
}
