/**
 * Portal Block Styles
 */

/* Core Portal */
div.portal {
  max-width: 560px;
  margin: auto;
  /* Anchor for the loading / fallback overlay. */
  position: relative;
  scrollbar-width: none;
  -ms-overflow-style: none;

  &::-webkit-scrollbar {
    display: none;
  }

  > iframe {
    border: none;
  }
}

/* Scroll lock when modal is open.
   overflow:hidden only — position:fixed disrupts iOS touch-event routing into iframes. */
body.cps-modal-open {
  overflow: hidden;
}

/* Portal Modal */
dialog.cps-portal-modal {
  border: 1px solid;
  border-radius: 6px;
  padding: 0;
  width: 95%;
  max-width: 550px !important;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;

  ::backdrop {
    background: rgba(0, 0, 0, 0.7);
  }

  div.portal {
    height: calc(100dvh - 40px);
    max-height: 700px;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
    -webkit-transform: translateZ(0);
    > iframe {
      border: none;
      height: 99%;
      width: 100%;
    }
  }

  .close-button {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.5);
    color: white;
    font-size: 20px;
    cursor: pointer;
    z-index: 1001;
    display: flex;
    align-items: center;
    justify-content: center;

    &:hover {
      background: rgba(0, 0, 0, 0.7);
    }
  }

  /* Mobile */
  @media (max-width: 767px) {
    top: 0 !important;
    max-width: 500px !important;
    height: 100%;
  }

  /* Desktop */
  @media (min-width: 768px) {
    max-height: 95dvh;
  }
}

/* Portal loading state and timeout fallback.
   The portal is an app on another origin, so on a slow connection the iframe is
   a white box until it boots. This covers that wait, and becomes a retry / open
   directly / call panel once the load timeout passes.

   The wait is typically 3-4 seconds, so this is a state people actually sit and
   look at rather than a flash. Everything here is built to be watched: nothing
   cuts, every state change is a transition, and the motion is slow and eased
   rather than busy. Durations sit in the 400-650ms range with a single easing
   curve so the whole thing feels like one object moving, not four. */

:where(.cps-portal-status) {
  /* One curve for everything, so the states feel related. */
  --cps-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --cps-ease-out: cubic-bezier(0.2, 0.8, 0.25, 1);
  /* Roughly how long the portal takes, used to pace the progress bar. */
  --cps-portal-wait: 4.5s;
}

.cps-portal-status {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px;
  overflow: hidden;
  background: #fff;
  color: #333;
  font-size: 15px;
  line-height: 1.45;
  text-align: center;
  opacity: 1;
  transition:
    opacity 480ms var(--cps-ease),
    visibility 480ms linear,
    background-color 600ms var(--cps-ease);
}

/* A slow sheen across the panel. Very low contrast on purpose — it should read
   as light moving over a surface, not as a loading bar. */
.cps-portal-status::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(0, 0, 0, 0) 32%,
    rgba(0, 0, 0, 0.022) 46%,
    rgba(0, 0, 0, 0.038) 50%,
    rgba(0, 0, 0, 0.022) 54%,
    rgba(0, 0, 0, 0) 68%
  );
  background-size: 240% 100%;
  background-repeat: no-repeat;
  animation: cps-portal-sheen 3.2s var(--cps-ease) infinite;
  opacity: 1;
  pointer-events: none;
  transition: opacity 400ms var(--cps-ease);
}

/* Once the fallback is up we are not loading any more, so the sheen stops.
   Browsers without :has() simply keep it, which is harmless. */
.cps-portal-status:has(.cps-portal-fallback:not([hidden]))::before {
  animation: none;
  opacity: 0;
}

@keyframes cps-portal-sheen {
  from { background-position: 140% 0; }
  to   { background-position: -40% 0; }
}

/* Fading out rather than display:none, so the portal is revealed instead of
   uncovered. Kept in the layer (it is absolutely positioned, so it costs no
   layout) but invisible and untouchable. */
.cps-portal-status[hidden] {
  display: flex;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.cps-portal-status[hidden]::before {
  opacity: 0;
}

/* Peek state.
   The overlay is removed by the iframe's load event, which waits for every async
   third party inside the portal (gtag, the Facebook pixel, the Cloudflare
   challenge frame, Google Maps' runtime modules). The portal paints and becomes
   interactive well before that, so an opaque sheet held until load sits on top
   of a working scheduler — measured at ~2.3s in a local reproduction.

   After cpsPortalConfig.revealTimeout the backdrop is dropped and the overlay
   stops taking pointer events, so a painted portal is visible and usable. The
   indicator glides down out of the way rather than jumping, and stays until the
   portal actually loads or the timeout fallback takes over. A portal that
   genuinely has not painted is white underneath, which is what the backdrop was
   showing anyway, so nothing is lost in the case the loader exists for. */
.cps-portal-status[data-cps-peek] {
  background: rgba(255, 255, 255, 0);
  pointer-events: none;
}

.cps-portal-status[data-cps-peek]::before {
  opacity: 0;
}

/* Both panels are centred in the same place so they can move and cross-fade
   without the container's justify-content jumping them around. */
.cps-portal-loading,
.cps-portal-fallback {
  position: absolute;
  left: 24px;
  right: 24px;
  top: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  transform: translateY(-50%);
  transition:
    top 620ms var(--cps-ease),
    transform 620ms var(--cps-ease),
    opacity 380ms var(--cps-ease);
}

/* Glide the indicator down to the edge instead of re-anchoring it. */
.cps-portal-status[data-cps-peek] .cps-portal-loading {
  top: 100%;
  transform: translateY(calc(-100% - 14px)) scale(0.86);
}

.cps-portal-status[data-cps-peek] .cps-portal-progress {
  opacity: 0;
}

.cps-portal-status[data-cps-peek] .cps-portal-status-text {
  /* Legible over whatever the portal has painted underneath. */
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 1px 10px rgba(0, 0, 0, 0.06);
  font-size: 13px;
}

/* The UA's [hidden] rule loses to the display above, so state it here. The
   status panel itself is excluded — it fades (above) rather than cutting. */
.cps-portal-loading[hidden],
.cps-portal-fallback[hidden] {
  display: none;
}

.cps-portal-status p {
  margin: 0;
}

/* Entrance. The overlay is painted with the page, so the panel easing in reads
   as deliberate rather than as something that failed to render in time. */
.cps-portal-loading {
  animation: cps-portal-fade 560ms var(--cps-ease-out) backwards;
}

.cps-portal-status-text,
.cps-portal-progress {
  animation: cps-portal-rise 620ms var(--cps-ease-out) backwards;
}

.cps-portal-status-text { animation-delay: 90ms; }
.cps-portal-progress    { animation-delay: 180ms; }

@keyframes cps-portal-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes cps-portal-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* A tapered ring rather than a hard border arc: the stroke fades out around the
   circle instead of stopping, which is what stops it looking mechanical. Paired
   with a slow breath so it is alive without being busy. */
.cps-portal-spinner {
  display: block;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    rgba(0, 0, 0, 0) 0deg,
    rgba(0, 0, 0, 0.05) 90deg,
    rgba(0, 0, 0, 0.22) 210deg,
    currentColor 350deg,
    currentColor 360deg
  );
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.6px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.6px));
  opacity: 0.7;
  transition: width 620ms var(--cps-ease), height 620ms var(--cps-ease);
  /* Rotation stays linear — eased rotation stutters at the loop seam. The
     character comes from the slow breath layered over it. */
  animation:
    cps-portal-spin 1.15s linear infinite,
    cps-portal-breathe 2.8s var(--cps-ease) infinite;
}

.cps-portal-status[data-cps-peek] .cps-portal-spinner {
  width: 22px;
  height: 22px;
}

@keyframes cps-portal-spin {
  to { transform: rotate(360deg); }
}

@keyframes cps-portal-breathe {
  0%, 100% { opacity: 0.72; }
  50%      { opacity: 0.42; }
}

/* Paced progress. It eases out toward 92% over the expected wait — decelerating
   rather than creeping linearly, which is what makes a wait feel like it is
   getting somewhere — and completes as the overlay fades. */
.cps-portal-progress {
  width: min(200px, 62%);
  height: 3px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.07);
  transition: opacity 420ms var(--cps-ease);
}

.cps-portal-progress span {
  display: block;
  width: 2%;
  height: 100%;
  border-radius: inherit;
  background: currentColor;
  opacity: 0.32;
  animation: cps-portal-progress var(--cps-portal-wait) cubic-bezier(0.1, 0.76, 0.28, 1) forwards;
}

@keyframes cps-portal-progress {
  from { width: 2%; }
  to   { width: 92%; }
}

/* Run it to the end on the way out, so it resolves instead of vanishing mid-way. */
.cps-portal-status[hidden] .cps-portal-progress span {
  animation: cps-portal-progress-done 400ms var(--cps-ease-out) forwards;
}

@keyframes cps-portal-progress-done {
  from { width: 92%; }
  to   { width: 100%; }
}

/* The fallback replaces the spinner, so it arrives on its own beat. */
.cps-portal-fallback {
  animation: cps-portal-rise 520ms var(--cps-ease-out) backwards;
}

.cps-portal-status-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px;
}

.cps-portal-retry {
  padding: 10px 18px;
  border: 1px solid currentColor;
  border-radius: 4px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: background-color 240ms var(--cps-ease), color 240ms var(--cps-ease);
}

.cps-portal-retry:hover {
  background: currentColor;
  color: #fff;
}

.cps-portal-status-call .cps-phone-number {
  display: inline;
  font-weight: bold;
}

/* Respect a stated preference for less motion: keep the state changes legible,
   drop everything decorative. The progress bar still moves, because it carries
   information, but it no longer eases. */
@media (prefers-reduced-motion: reduce) {
  .cps-portal-status::before {
    animation: none;
    opacity: 0;
  }

  .cps-portal-spinner {
    animation: cps-portal-spin 2.4s linear infinite;
  }

  .cps-portal-loading,
  .cps-portal-fallback,
  .cps-portal-spinner,
  .cps-portal-status-text,
  .cps-portal-progress {
    animation-name: cps-portal-fade;
  }

  .cps-portal-progress span {
    animation-timing-function: linear;
  }
}

/* Reset notice (?cb=true). Deliberately plain and unbranded — it is a testing
   affordance, and it should never be mistaken for site content. */
.cps-portal-reset-notice {
  position: fixed;
  z-index: 2147483000;
  bottom: 16px;
  left: 50%;
  max-width: calc(100vw - 32px);
  padding: 10px 16px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.92);
  color: #fff;
  font-size: 13px;
  line-height: 1.4;
  text-align: center;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.22);
  transform: translate(-50%, 0);
  opacity: 1;
  transition: opacity 520ms ease, transform 520ms ease;
}

.cps-portal-reset-notice[data-cps-leaving] {
  opacity: 0;
  transform: translate(-50%, 8px);
}

@media (prefers-reduced-motion: reduce) {
  .cps-portal-reset-notice {
    transition: opacity 520ms ease;
  }
  .cps-portal-reset-notice[data-cps-leaving] {
    transform: translate(-50%, 0);
  }
}

/* Phone Number Block */
.phone-icon-wrapper {
  display: inline-flex;
  align-items: center;
  margin-right: 8px;
}

.phone-icon {
  width: 16px;
  height: 16px;
  fill: currentColor;
  display: inline-block;
}

.cps-phone-number {
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  color: #333;
}

.cps-phone-number:hover {
  color: #007bff;
}

.number {
  font-size: 16px;
  font-weight: bold;
}
