/* ===========================================================================
   REFRESH ELECTRICAL — cross-platform layer.

   Loads LAST, after styles.css, refresh.css and the per-page Astro scoped
   sheets, so equal-specificity rules here win on source order. Everything in
   this file is a platform correction — notched/rounded viewports, touch
   input, iOS/Android browser chrome, landscape phones and tablet-portrait
   widths. No brand or layout decisions are made here; where a selector looks
   over-qualified it is matching the specificity of the rule it corrects.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Platform hygiene
   ------------------------------------------------------------------------- */

/* Android Chrome and Samsung Internet will auto-invert a page that does not
   declare a scheme. The design is light-on-paper by intent. */
:root {
  color-scheme: light;
}

html {
  /* iOS inflates text when a phone is rotated to landscape unless this is
     pinned. Safari and older Chrome still need the prefixed form. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* The grey flash on tap is a WebKit default; :active/:focus-visible styling
     already carries the affordance. */
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

/* A single wide child (a long ABN, a marquee, a grid that has not collapsed
   yet) should never make the whole document pan sideways. `clip` is preferred
   because it does not create a scroll container — but it is newer, so `hidden`
   goes first as the fallback. Nothing on the site uses `position: sticky`, so
   neither value can break a sticky element. */
html,
body {
  overflow-x: hidden;
}

@supports (overflow: clip) {
  html,
  body {
    overflow-x: clip;
  }
}

/* Removes the 300ms tap delay on anything interactive without disabling
   pinch-zoom on the page as a whole. */
:is(a, button, [role="button"], input, select, textarea, summary, label) {
  touch-action: manipulation;
}

/* ---------------------------------------------------------------------------
   2. Safe areas  (notched iPhones, iPad with rounded display, landscape)
   ------------------------------------------------------------------------- */

/* The gutter is 15px at every breakpoint, which is narrower than the landscape
   inset on a notched phone — text would sit under the sensor housing. max()
   keeps the design gutter everywhere it is already big enough. Browsers
   without env() drop the declaration and keep the 15px rule above. */
.container,
.auto-container,
.hero-sticky {
  padding-left: max(var(--_spacing---margin-padding--container), env(safe-area-inset-left));
  padding-right: max(var(--_spacing---margin-padding--container), env(safe-area-inset-right));
}

/* Clears the home indicator at the very bottom of the document. Applied to the
   footer's base row rather than the footer itself, which already carries a
   higher-specificity padding shorthand. */
.re-ftr-base {
  padding-bottom: env(safe-area-inset-bottom);
}

/* ---------------------------------------------------------------------------
   3. Mobile navigation
   ------------------------------------------------------------------------- */

/* The script adds `nav-open` to <body> when the panel opens but nothing
   consumed it, so the page scrolled away underneath the menu. :has() handles
   browsers that scroll <html>; the body rule covers the rest. */
html:has(body.nav-open),
body.nav-open {
  overflow: hidden;
}

@media screen and (max-width: 991px) {
  /* 90vh is the *largest* viewport height on iOS, so with the toolbars shown
     the panel overflowed off-screen. dvh tracks the collapsing chrome; vh is
     retained first for pre-15.4 Safari. Scroll chaining is contained so
     flicking the end of the menu does not start scrolling the page. */
  .nave-menu {
    max-height: 90vh;
    max-height: calc(100dvh - 78px);
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: env(safe-area-inset-bottom);
  }
}

@media screen and (max-width: 479px) {
  /* Under 480px the template hid `.nav-menu-content` wholesale, which took the
     "Get a quote" button with it — phones had no call-to-action in the header
     at all. The row is restored and only its text links are hidden, since the
     same links already appear in the mobile panel below. */
  .nave-menu .nav-menu-content {
    flex-flow: column;
    align-items: stretch;
    gap: 0;
    padding: 24px 16px 0;
    display: flex;
  }

  .nave-menu .nav-menu-content > .nav-link {
    display: none;
  }

  /* Two columns leaves roughly 129px per cell at 320px, and .nav-menu clips
     its overflow — the email address was cut off mid-domain. One column per
     row, and long strings are allowed to wrap. */
  .mobile-nav-wrap .nav-dropdown-left-wrap-2 {
    grid-template-columns: 1fr;
    grid-row-gap: 28px;
  }

  .mobile-nav-wrap .nav-menu {
    overflow: visible;
    overflow-wrap: anywhere;
  }

  /* The base link colour is a mid grey meant for a light dropdown, but on the
     dark pages these links sit on the near-black panel under 480px — roughly
     2:1 contrast, with only the hovered and current items readable. The
     light-mood panel is white and its links carry `.dark`, so it is excluded. */
  .mobile-nav-wrap .nav-menu:not(.dark) {
    color: var(--color--background-light);
  }

  .mobile-nav-wrap .nav-menu:not(.dark)[aria-current="page"] {
    color: var(--color--accent-on-dark);
  }
}

/* ---------------------------------------------------------------------------
   4. Touch targets
   ------------------------------------------------------------------------- */

/* Footer links sat on a ~32px pitch and the mobile panel links on ~31px, both
   short of the 44px platform guidance. Desktop pointer layouts are untouched:
   these only apply where the primary input is a finger. (The footer links were
   first set to 40px here; 44px since 2026-09-27.) */
@media (hover: none) and (pointer: coarse) {
  .re-ftr .re-ftr-grid .re-ftr-col {
    gap: 2px;
  }

  .re-ftr .re-ftr-col .re-ftr-link,
  .re-ftr .re-ftr-legal .re-ftr-link,
  .re-ftr .re-ftr-mark,
  .navbar-logo-link {
    min-height: 44px;
    align-items: center;
    display: inline-flex;
  }

  /* The enquiry chips were 40px. */
  .re-check { min-height: 44px; }

  /* Links that are small on purpose, the phone numbers and the one-line
     "more" links under a section, reach 44px through an invisible hit area
     rather than padding, so nothing on the page moves. (2026-09-27, polish:
     the hero's "or call" and the /go/ header number measured 27px, the
     section links 18px.) */
  .re-hero-phone, .re-hdr-phone, .re-more a { position: relative; }
  .re-hero-phone::after, .re-hdr-phone::after { content: ""; position: absolute; inset: -9px 0; }
  .re-more a::after { content: ""; position: absolute; inset: -13px 0; }

  /* The closing note is not a link, so it keeps the original breathing room
     the column gap used to give it. */
  .re-ftr .re-ftr-col .re-ftr-quiet {
    margin-top: 8px;
  }

  .mobile-nav-wrap .nav-menu {
    min-height: 44px;
    align-items: center;
    display: flex;
  }

  /* The translate-on-hover nudge fires on tap and leaves the row visibly
     shifted while the next page loads. */
  .nav-menu:hover {
    transform: none;
  }
}

/* ---------------------------------------------------------------------------
   5. Dynamic viewport units
   ------------------------------------------------------------------------- */

/* svh is the small-viewport height — correct for a hero that must be fully
   visible with the iOS toolbars expanded. Safari only learned it in 15.4, so
   vh goes first for everything older. The homepage hero declares both itself
   (index.astro, since 2026-09-27). */

/* ---------------------------------------------------------------------------
   6. Landscape phones and other short viewports
   ------------------------------------------------------------------------- */

/* A phone on its side is about 375px tall. The portrait hero padding
   (120px + 72px) plus a full-height hero container left almost no room for the
   headline itself, and the utility pages pushed their content below the fold
   before a single word was visible. The spacing custom properties are
   redefined on <body> because that is where the template's own breakpoints
   redefine them — a :root override would be shadowed. */
@media (orientation: landscape) and (max-height: 560px) {
  body {
    --_spacing---margin-padding--banner-space: 72px;
    --_spacing---margin-padding--utlity-hero: 88px;
    --_spacing---margin-padding--full-padding: 48px;
  }

  /* The homepage hero keeps its full-viewport minimum, but on a phone on its
     side that is 375px, so it stops reserving 140px for the header and lets
     the headline, line and button set the height. */
  .section.is-hero.re-hero {
    padding-top: 96px;
    padding-bottom: 40px;
  }

  .service-single-title {
    padding-top: 96px;
  }

  .utility-error-page-wrap {
    min-height: 0;
    padding-top: 96px;
    padding-bottom: 48px;
  }
}

/* ---------------------------------------------------------------------------
   7. Marquee containment
   ------------------------------------------------------------------------- */

/* The logo track is `width: max-content` and wider than any phone or laptop.
   Nothing clipped it, so the whole document could be panned sideways; the
   edge-fade mask hid the symptom without stopping the scroll. */
.re-marquee {
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   8. Reveal failsafe
   ------------------------------------------------------------------------- */

/* Content visibility is gated on `.js .reveal-* { opacity: 0 }` being undone
   by the IntersectionObserver in the page script. If that script never
   arrives, or throws before it reaches the observer, the page renders blank.
   The head script announces itself on <html> once the observer is wired; the
   watchdog sets `no-js-fallback` when that announcement does not come, which
   holds every reveal at the state it would have finished in. */
html.no-js-fallback :is(
  .reveal-up, .reveal-left, .reveal-right, .reveal-grow, .reveal-grow-big,
  .reveal-blur, .reveal-blur-fast
),
html.no-js-fallback .reveal-heading .animation-content {
  opacity: 1;
  transform: none;
  filter: none;
  transition: none;
}

html.no-js-fallback .reveal-divider {
  width: 100%;
  transition: none;
}

html.no-js-fallback .reveal-view-image .view-image {
  transform: scale(1.02);
}

html.no-js-fallback .reveal-view-image .view-image-overlay {
  transform: translateY(0);
}

/* The FAQ answers are collapsed by the stylesheet (height 0), not by the
   script, so with no script — or one that failed — every answer sat unreadable
   behind a button that did nothing. Without the script they are simply open,
   and the +/- icon, which would promise a control that does not work, goes.
   A script that did run sets the height inline, which still wins. */
html:not(.js) [data-accordion-panel],
html.no-js-fallback [data-accordion-panel] {
  height: auto;
  visibility: visible;
}

html:not(.js) .accordion-icon-wrapper,
html.no-js-fallback .accordion-icon-wrapper {
  display: none;
}

/* ---------------------------------------------------------------------------
   9. Reduced motion
   ------------------------------------------------------------------------- */

/* The design sheet already holds the reveal system at its final state under
   `prefers-reduced-motion`. These are the two cases it misses. */
@media (prefers-reduced-motion: reduce) {
  /* The footer "view" image was left parked at scale(1.3) with its overlay
     still covering it, because the transition never fires. */
  .js .reveal-view-image .view-image {
    transform: scale(1.02);
    transition: none;
  }

  .js .reveal-view-image .view-image-overlay {
    transform: translateY(0);
    transition: none;
  }

  /* An infinite horizontal scroll is exactly what this preference asks to be
     spared. It becomes the static wrapped row the narrow breakpoints use. */
  .re-marquee .re-marquee-track {
    flex-wrap: wrap;
    gap: 32px 56px;
    width: auto;
    animation: none;
  }
}
