/* My Visa Lawyer — behaviour styles.
 *
 * This file is loaded by BOTH the HTML prototype and the WordPress site, so the
 * behaviour that gets reviewed is the behaviour that ships. It contains only
 * what Elementor cannot express: the sticky header's compaction, the mobile
 * drawer, focus rings, and the decorative animation's containment.
 *
 * Everything else -- colour, type, spacing, the hero split, the service band --
 * is set in the Elementor templates as editable widget settings, so the site
 * owner can change it in the editor without touching CSS. Nothing here overrides
 * a value a person can edit in Elementor.
 *
 * Durations are 160-240ms per the art direction. There is no scroll hijacking,
 * no preloader, and no animation that delays content from rendering.
 */

:root {
  --mcl-header-h: 88px;
  --mcl-header-h-compact: 68px;
  --mcl-ui-fast: 160ms;
  --mcl-ui-slow: 240ms;
  --mcl-ui-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --mcl-drawer-w: 320px;
}

@media (max-width: 1024px) {
  :root { --mcl-header-h: 72px; --mcl-header-h-compact: 72px; }
}


/* ------------------------------------------------- a note on the selectors --
 * The position rules below repeat their class: `.mcl-header.mcl-header`.
 *
 * That is not a typo. Elementor's container stylesheet sets `position: relative`
 * on every `.e-con`, at the same specificity as a single class, and it is
 * enqueued after this file. A plain `.mcl-header { position: fixed }` therefore
 * loses, and the header renders in flow, 155px tall, with the drawer panel
 * pushed out into 3680px of horizontal overflow. Repeating the class doubles the
 * specificity and settles it without resorting to !important, which would take
 * the value away from anyone trying to change it later.
 *
 * Found by measuring a real WordPress page. Nothing static could see it: the CSS
 * was correct in isolation and lost an argument it was never told it was in.
 */

/* ---------------------------------------------------------------- header --
 * The bar is fixed and the spacer is a constant height, so compacting the bar
 * moves nothing below it. Making the bar itself `sticky` and animating its
 * height would reflow the whole document on every scroll, which is the layout
 * shift the art direction rules out.
 */
/* ------------------------------------------------- the WordPress admin bar --
 * A logged-in admin gets a fixed bar across the top of the viewport at
 * z-index 99999. Our header is fixed at z-index 100 and the drawer at 200, so
 * on a real host the bar sat over the header, and over the drawer's Close
 * control — which is the one thing a keyboard user needs to find.
 *
 * ANONYMOUS VISITORS ARE UNAFFECTED. --mcl-admin-bar is 0px unless
 * body.admin-bar is present, and WordPress only prints that class for someone
 * who is logged in and has the bar switched on.
 *
 * The two static values are WordPress's own: 32px, and 46px under 782px. They
 * are the no-JavaScript answer and the value before the script runs, so there
 * is no flash. mcl-ui.js then measures the bar's actual bottom edge on
 * scroll, which matters under 600px: there WordPress makes the bar
 * position:absolute so it scrolls away with the page, and a fixed 46px offset
 * would leave a 46px gap above the header for the rest of the visit.
 */
:root { --mcl-admin-bar: 0px; }
body.admin-bar { --mcl-admin-bar: 32px; }
@media screen and (max-width: 782px) {
  body.admin-bar { --mcl-admin-bar: 46px; }
}

.mcl-header.mcl-header {
  position: fixed;
  inset: var(--mcl-admin-bar) 0 auto 0;
  z-index: 100;
  height: var(--mcl-header-h);
  display: flex;
  align-items: center;
  transition: height var(--mcl-ui-slow) var(--mcl-ui-ease),
              box-shadow var(--mcl-ui-slow) var(--mcl-ui-ease),
              background-color var(--mcl-ui-slow) var(--mcl-ui-ease);
  will-change: height;
}

.mcl-header-spacer.mcl-header-spacer {
  height: var(--mcl-header-h);
  flex: 0 0 auto;
}

/* min-height too, or the compaction never happens on WordPress.
 *
 * The Elementor container carrying .mcl-header sets its own Min Height, which
 * Elementor writes as `--min-height: 88px` with `.e-con { min-height:
 * var(--min-height) }`. min-height CLAMPS the used height: it is a box-model
 * rule, so specificity, load order and the doubled-class trick are all
 * irrelevant to it. `height: 68px` could never take effect, and the bar stayed
 * 88px however far the reader scrolled.
 *
 * Worse than doing nothing, because the class was still added: the box-shadow
 * and the logo cap fired, so the wordmark shrank inside a bar that did not.
 *
 * Only the compact state overrides it. The resting height stays Elementor's,
 * which keeps the Min Height control meaningful to whoever opens the editor --
 * this file's own rule is that it never takes away a value a person can edit.
 *
 * Nothing caught this. The behaviour test drives the file:// prototype, whose
 * header is a plain <header> with no Elementor container, and the WordPress
 * acceptance run never scrolled. Both now do. */
.mcl-header.is-compact {
  height: var(--mcl-header-h-compact);
  min-height: var(--mcl-header-h-compact);
  box-shadow: 0 1px 0 rgba(23, 45, 77, 0.10), 0 6px 20px -12px rgba(23, 45, 77, 0.35);
}

/* The logo shrinks with the bar, and NEVER has both dimensions set at once.
 *
 * Two separate problems live here, and both needed the doubled class.
 *
 * 1. ASPECT. This rule used to say `height: 34px; width: auto`. Elementor's
 *    Image widget sets the width from its own control at higher specificity, so
 *    the two combined to pin both dimensions: the wordmark is 8.22:1 and it
 *    rendered at 6.82:1 on desktop and 4.41:1 on mobile. A 47% horizontal
 *    squeeze reads as a different logo, not as a smaller one. The width is now
 *    the editor's to set, the height follows from the file, and the compact
 *    state animates a max-width cap instead of a height.
 *
 * 2. SHRINKING. Elementor's width control also writes `max-width: 190px` on the
 *    image. At 320px the container correctly shrank to 145px and the image
 *    ignored it and carried on underneath the menu button -- overflowing
 *    nothing, so no edge check could see it. `max-width: 100%` at a single
 *    class loses to Elementor's per-element rule on load order; doubling the
 *    class wins it without !important, which would take the value away from
 *    anyone trying to change it later.
 *
 * min-width: 0 on the whole chain is what lets any of it shrink at all: a flex
 * item's min-width defaults to its content's width, which here is the image.
 */
.mcl-header__logo,
.mcl-header__logo .elementor-element,
.mcl-header__logo .elementor-widget-container,
.mcl-header__logo a { min-width: 0; max-width: 100%; }

.mcl-header__logo.mcl-header__logo img,
.mcl-header__logo.mcl-header__logo svg {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  transition: max-width var(--mcl-ui-slow) var(--mcl-ui-ease);
}

.mcl-header.is-compact .mcl-header__logo.mcl-header__logo img,
.mcl-header.is-compact .mcl-header__logo.mcl-header__logo svg { max-width: min(200px, 100%); }

/* ---------------------------------------------------------------- drawer --
 * Right-hand panel. Hidden with `visibility` as well as opacity so that nothing
 * inside it is focusable while closed -- an offscreen panel that is still in the
 * tab order is the usual accessibility failure in this pattern.
 */
.mcl-drawer.mcl-drawer {
  position: fixed;
  /* Below the admin bar, so the panel's Close control is reachable rather than
     sitting underneath it. The overlay stops short of the bar too, which is
     correct: the bar is not part of the site and dimming it would suggest the
     drawer had captured it. */
  inset: var(--mcl-admin-bar) 0 0 0;
  z-index: 200;
  visibility: hidden;
  pointer-events: none;
  /* The closed panel is parked at translateX(100%), which is 320px past the
     right edge of the viewport. A fixed ancestor does not clip it, so the
     document grows by 320px and the page scrolls sideways -- on a page that
     otherwise fits exactly. Clipping here costs nothing: the drawer covers the
     whole viewport and has nothing to show outside it. */
  overflow: hidden;
}

.mcl-drawer.is-open { visibility: visible; pointer-events: auto; }

.mcl-drawer__overlay.mcl-drawer__overlay {
  position: absolute;
  inset: 0;
  background: rgba(23, 45, 77, 0.45);
  opacity: 0;
  transition: opacity var(--mcl-ui-slow) var(--mcl-ui-ease);
}

.mcl-drawer.is-open .mcl-drawer__overlay { opacity: 1; }

.mcl-drawer__panel.mcl-drawer__panel {
  position: absolute;
  inset: 0 0 0 auto;
  width: var(--mcl-drawer-w);
  max-width: 90vw;
  background: var(--mcl-paper, #F7F8FA);
  transform: translateX(100%);
  transition: transform var(--mcl-ui-slow) var(--mcl-ui-ease);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: -18px 0 44px -28px rgba(23, 45, 77, 0.6);
}

.mcl-drawer.is-open .mcl-drawer__panel { transform: translateX(0); }

/* Scroll lock. Set on <html> by the controller, which also stores the scroll
   position so closing the drawer returns the reader to where they were. */
.mcl-scroll-locked {
  overflow: hidden;
  /* iOS Safari ignores overflow:hidden on <html> during momentum scrolling;
     the controller adds position:fixed with a top offset there. */
}

/* -------------------------------------------------------------- body links --
 * Elementor's Text Editor emits a plain <a>, and with no rule of its own the
 * theme's default wins. On the theme this ships against that default is bright
 * pink, which next to the brand's ink and accent simply looks broken, and on a
 * page about someone's visa it reads as a site nobody finished.
 *
 * Scoped to prose, so it cannot touch buttons, the nav, the drawer or the
 * footer, each of which sets its own link colour.
 *
 * Underlined rather than coloured alone: WCAG 1.4.1 is not satisfied by colour
 * by itself, and a reader with a colour deficiency needs the link to be
 * identifiable without it. The offset keeps descenders legible through the rule.
 */
.mcl-page-body .elementor-widget-text-editor a,
.mcl-page-body .elementor-widget-theme-post-content a,
.mcl-prose a {
  color: var(--mcl-blue, #3564A0);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 0.07em;
}

.mcl-page-body .elementor-widget-text-editor a:hover,
.mcl-page-body .elementor-widget-theme-post-content a:hover,
.mcl-prose a:hover {
  text-decoration-thickness: 0.14em;
}

/* The focus ring below covers these; they do not declare a second one. */

/* ------------------------------------------------------------ focus ring --
 * A visible focus ring on every interactive element. :focus-visible so it does
 * not appear on mouse clicks, with a :focus fallback for browsers without it.
 */
.mcl-header a:focus-visible,
.mcl-header button:focus-visible,
.mcl-drawer a:focus-visible,
.mcl-drawer button:focus-visible,
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--mcl-blue, #3564A0);
  outline-offset: 3px;
  border-radius: 2px;
}

/* -------------------------------------------------------- decorative art --
 * A route stroke drawn over the hero photograph. It carries no information, so
 * it is aria-hidden and its absence changes nothing.
 */
.mcl-route.mcl-route {
  position: absolute;
  pointer-events: none;
  z-index: 2;
}

/* The static fallback is what is in the DOM. The player, if it loads, is
   appended alongside and the fallback is hidden. If the player never loads --
   no network, an error, reduced motion -- the fallback simply stays. */
.mcl-route__fallback { display: block; width: 100%; height: 100%; }
.mcl-route.is-animating .mcl-route__fallback { display: none; }
.mcl-route__player { width: 100%; height: 100%; }

@media (prefers-reduced-motion: reduce) {
  /* Doubled, to match the rules these override. The rules that set these
     transitions had their class doubled to win against Elementor; written at a
     single class, every override here silently lost to them and a reader who
     had asked for reduced motion got the full 240ms animation anyway. */
  .mcl-header.mcl-header,
  .mcl-header__logo.mcl-header__logo img,
  .mcl-header__logo.mcl-header__logo svg,
  .mcl-drawer__overlay.mcl-drawer__overlay,
  .mcl-drawer__panel.mcl-drawer__panel { transition-duration: 1ms; }
  /* The route stroke is never played; the controller checks this same query. */
  .mcl-route.is-animating .mcl-route__fallback { display: block; }
  .mcl-route__player { display: none; }
}

/* The hero's trust line owns the space above it, at every width, so nothing
   above has to remember to leave room. Elementor sets this from the container's
   own margin control; the rule here is for the HTML prototype, which has no
   Elementor to set it. */
.mcl-hero__trust { margin-top: 24px; }

/* ------------------------------------------------ layout Elementor cannot do
 * Three things in this composition have no Elementor control behind them. They
 * are listed here rather than hidden in a template, so that anyone wondering
 * why a value cannot be changed in the editor can see exactly which ones.
 *
 * 1. object-fit. The hero photograph has to COVER a column whose height is set
 *    by the text beside it. Elementor's Image widget offers width and height,
 *    not object-fit, so an image told to fill would distort.
 * 2. Position for the decorative route stroke, which sits over the photograph.
 * 3. The hairline between the service band's three items at desktop only. The
 *    border itself is an editable container setting; only its removal at tablet
 *    width, where the items stack, is here.
 */

.mcl-hero-media.mcl-hero-media { position: relative; overflow: hidden; }

.mcl-hero-media > .elementor-widget-image,
.mcl-hero-media > .elementor-widget-image > .elementor-widget-container,
.mcl-hero-media > .elementor-widget-image figure,
.mcl-hero-media > .elementor-widget-image a { height: 100%; width: 100%; display: block; }

.mcl-hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* 50% 50% rather than centre.
     Where the horizon and the subject sit is a framing decision, and the crop
     that survives is the one the art direction asked for. Centre is only right
     by accident. */
  object-position: 50% 50%;
  display: block;
}

.mcl-hero-media .mcl-route.mcl-route {
  top: 5%;
  right: 4%;
  width: 32%;
  max-width: 300px;
  aspect-ratio: 300 / 220;
  height: auto;
}

/* The route stroke's resting artwork, for the Elementor build where the
   container is empty and the script has nothing to fall back to. Drawn in CSS
   so it needs no upload and no SVG in the media library. */
.mcl-hero-media .mcl-route::before {
  content: '';
  position: absolute;
  inset: 0;
  background: no-repeat center / contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 220' fill='none'%3E%3Cpath d='M292 6C196 60 118 146 40 210' stroke='%23B29665' stroke-width='1.5' stroke-linecap='round'/%3E%3Ccircle cx='40' cy='210' r='3.5' fill='%23B29665'/%3E%3C/svg%3E");
}
.mcl-hero-media .mcl-route.is-animating::before { display: none; }

@media (prefers-reduced-motion: reduce) {
  .mcl-hero-media .mcl-route.is-animating::before { display: block; }
}
