/* OMFC International | components.css: header, buttons, loader, menu,
   and photo viewer. */


/* === 1. Site header =====================================================
   Transparent: the logo (left), London time (centre) and the menu button (right) sit straight on the page. Over
   dark sections the text is light, over light sections dark (initHeader in ui.js sets .is-on-light); the logo
   keeps its own colours.
   Sizes: --header-h, --control-h and --logo-h in tokens.css. */

.site-header {
  position: fixed;
  z-index: var(--z-header);
  top: var(--header-top);
  left: var(--margin);
  right: var(--margin);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-rows: var(--header-h);
  align-items: center;
  color: var(--bone);
  pointer-events: none;
  transition:
    color var(--dur-3) var(--ease-out),
    transform 0.5s var(--ease-out),
    opacity 0.35s var(--ease-out);
}

.site-header > * {
  pointer-events: auto;
}

.site-header.is-on-light {
  color: var(--ink);
}

/* Scrolling down past the first half screen: the header slides up out of the way of the text (ui.js) */
.site-header.is-hidden {
  opacity: 0;
  transform: translateY(calc(-1 * (var(--logo-h) + var(--header-top) + 0.5rem)));
}

.site-header.is-hidden > * {
  pointer-events: none;
}

/* Logo: the OMFC International logo in its own colours on a transparent background, at one fixed size (it hangs
   below the header's line). Its width follows from the image's own shape, so another logo file can be dropped in
   without changing this. */
.site-header__logo {
  position: relative;   /* the black logo sits over the white one */
  grid-column: 1;
  justify-self: start;
  align-self: start;
  display: block;
}

/* OMFC's white logo over the dark hero, with a soft shadow for bright patches of the photographs; their black logo,
   in the same place, while the header is over a light section (.is-on-light, like the header text) */
.site-header__logo img {
  display: block;
  width: auto;
  height: var(--logo-h);
  transition: opacity var(--dur-3) var(--ease-out);
}

.site-header__logo-white {
  filter: var(--logo-shadow);
}

.site-header__logo-black {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;   /* a little wider than the white logo that sizes the link */
  opacity: 0;
}

.site-header.is-on-light .site-header__logo-white {
  opacity: 0;
}

.site-header.is-on-light .site-header__logo-black {
  opacity: 1;
}

/* Once the hero's photographs have scrolled from under it, the logo stays away, even when the header comes back on
   scrolling up, so it never sits over the text (ui.js sets .is-scrolled). It is back over the hero, or on keyboard
   focus. */
.site-header__logo {
  transition: opacity var(--dur-3) var(--ease-out);
}

.site-header.is-scrolled .site-header__logo {
  opacity: 0;
  pointer-events: none;
}

.site-header.is-scrolled .site-header__logo:focus-visible {
  opacity: 1;
  pointer-events: auto;
}

/* Clock ---------------------------------------------------------------------- */

.clock {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  white-space: nowrap;
}

/* Blinking square, like a site status light: hi-vis over dark sections, the logo's green over light ones */
.clock__dot {
  width: 6px;
  height: 6px;
  background: var(--hivis);
  animation: clock-blink 2s steps(1, end) infinite;
}

.is-on-light .clock__dot {
  background: var(--logo-green);
}

.clock__city {
  opacity: 0.55;
}

/* Tabular figures stop the digits from jiggling as they change */
.clock__time {
  min-width: 8ch;
  font-variant-numeric: tabular-nums;
}

.clock__tz {
  opacity: 0.55;
}

@keyframes clock-blink {
  50% {
    opacity: 0.15;
  }
}

/* Right: "Start a project" (desktop) and the menu button, the same height ---------- */

.site-header__actions {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Menu button ---------------------------------------------------------------- */

.menu-toggle {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  height: var(--control-h);
  padding: 0 1rem;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  transition:
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}

.menu-toggle:hover {
  background: var(--hivis);
  color: var(--ink);
}

/* Label roll: a copy of the word (data-text) waits below and rolls up on hover */
.menu-toggle__label {
  display: block;
  height: 1.4em;
  overflow: hidden;
  line-height: 1.4;
}

.menu-toggle__label > span {
  position: relative;
  display: block;
  transition: transform 0.5s var(--ease-roll);
}

.menu-toggle__label > span::after {
  content: attr(data-text);
  position: absolute;
  top: 100%;
  left: 0;
}

.menu-toggle:hover .menu-toggle__label > span {
  transform: translateY(-100%);
}

/* Two-line icon that turns into a cross while the menu is open */
.menu-toggle__icon {
  position: relative;
  width: 16px;
  height: 8px;
}

.menu-toggle__icon i {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: currentColor;
  transition:
    transform 0.5s var(--ease-roll),
    width 0.5s var(--ease-roll);
}

.menu-toggle__icon i:first-child {
  top: 0;
}

.menu-toggle__icon i:last-child {
  bottom: 0;
  width: 60%;
}

.menu-toggle:hover .menu-toggle__icon i:last-child {
  width: 100%;
}

.menu-toggle[aria-expanded="true"] .menu-toggle__icon i:first-child {
  transform: translateY(3.25px) rotate(45deg);
}

.menu-toggle[aria-expanded="true"] .menu-toggle__icon i:last-child {
  width: 100%;
  transform: translateY(-3.25px) rotate(-45deg);
}

/* Tablet and phone: no "Start a project" in the header (the menu has Enquire). Two classes, to win over .btn */

/* Phones: the logo and the menu button only */
@media (max-width: 639px) {
  .clock {
    display: none;
  }
}


/* === 2. Buttons ============================================================
   The fill dissolves in pixel by pixel (pixelate() in ui.js); variants only set the --btn-* values. */

.btn {
  --btn-fg: currentColor;       /* text colour */
  --btn-bg: transparent;        /* background colour */
  --btn-line: currentColor;     /* 1px outline colour */
  --btn-fill: var(--hivis);     /* hover fill colour */
  --btn-fill-fg: var(--ink);    /* text colour on top of the fill */
  --btn-h: 3rem;                /* height, also the width of the icon cell */

  position: relative;
  isolation: isolate;           /* keeps the fill (z-index: -1) inside the button */
  display: inline-flex;
  align-items: stretch;
  min-height: var(--btn-h);
  overflow: hidden;
  color: var(--btn-fg);
  background: var(--btn-bg);
  box-shadow: inset 0 0 0 1px var(--btn-line);
  font-family: var(--font-mono);
  font-size: 0.71875rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;

  /* The text colour changes just after the fill has started to appear */
  transition:
    color 0.12s linear 0.14s,
    box-shadow var(--dur-2) var(--ease-out);
}

.btn__fill {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--btn-fill);

  /* Flip-book mask from pixelate(); solid by default so the fill works before it runs */
  -webkit-mask-image: var(--pixel-mask, linear-gradient(#000, #000));
  mask-image: var(--pixel-mask, linear-gradient(#000, #000));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: var(--pixel-size, 100% 100%);
  mask-size: var(--pixel-size, 100% 100%);
  -webkit-mask-position: 0% 0%;
  mask-position: 0% 0%;
  transition:
    -webkit-mask-position 0.46s steps(var(--pixel-steps, 1), jump-end),
    mask-position 0.46s steps(var(--pixel-steps, 1), jump-end);
}

/* Before pixelate() has run (no data-pixel yet): a simple slide-up fill */
.btn:not([data-pixel]) .btn__fill {
  transform: translateY(101%);
  transition: transform 0.5s var(--ease-roll);
}

/* The label is a one-line mask; its copy waits just below and rolls up on hover */
.btn__label {
  display: block;
  align-self: center;
  height: 1.3em;
  margin: 0 1.2rem;
  overflow: hidden;
}

.btn__label > span {
  position: relative;
  display: block;
  line-height: 1.3;
  transition: transform 0.5s var(--ease-roll);
}

.btn__label > span::after {
  content: attr(data-text);
  position: absolute;
  top: 100%;
  left: 0;
}

/* Icon cell with a dotted divider; --ix / --iy = the direction the arrow leaves on hover */
.btn__icon {
  --ix: 260%;
  --iy: 0%;
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: var(--btn-h);
  overflow: hidden;
  background-image: linear-gradient(currentColor 50%, transparent 0);
  background-size: 1px 6px;
  background-repeat: repeat-y;
  background-position: 0 0;
}

/* North-east arrow variant: the arrow leaves towards the top right */
.btn--ne .btn__icon {
  --ix: 260%;
  --iy: -260%;
}

.btn__icon svg {
  grid-area: 1 / 1;          /* both arrows share the same cell */
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  transition: transform 0.5s var(--ease-roll);
}

/* The second arrow waits outside the cell, on the opposite side */
.btn__icon svg:last-child {
  transform: translate(calc(var(--ix) * -1), calc(var(--iy) * -1));
}

/* Hover effects only on devices with a real hover (not touch screens) */
@media (hover: hover) {
  .btn:hover {
    color: var(--btn-fill-fg);
  }

  .btn:hover .btn__fill {
    -webkit-mask-position: 100% 0%;
    mask-position: 100% 0%;
  }

  .btn:not([data-pixel]):hover .btn__fill {
    transform: none;
  }

  .btn:hover .btn__label > span {
    transform: translateY(-100%);
  }

  .btn:hover .btn__icon svg:first-child {
    transform: translate(var(--ix), var(--iy));
  }

  .btn:hover .btn__icon svg:last-child {
    transform: none;
  }
}

/* Keyboard focus shows the same filled state as hover */
.btn:focus-visible {
  color: var(--btn-fill-fg);
}

.btn:focus-visible .btn__fill {
  -webkit-mask-position: 100% 0%;
  mask-position: 100% 0%;
  transform: none;
}

/* Pressed */
.btn:active {
  transform: translateY(1px);
}

/* Disabled and busy (while the enquiry form is sending) */
.btn[disabled],
.btn.is-busy {
  pointer-events: none;
}

.btn[disabled] {
  opacity: 0.45;
}

/* Variants ------------------------------------------------------------------- */

/* Outline button (header). Adapts when the header is over a light section. */
.btn--line {
  --btn-line: rgba(245, 243, 238, 0.5);
  --btn-bg: rgba(16, 17, 18, 0.18);
}

.is-on-light .btn--line {
  --btn-line: rgba(16, 17, 18, 0.45);
  --btn-bg: rgba(230, 226, 218, 0.4);
  --btn-fill: var(--ink);
  --btn-fill-fg: var(--bone);
}

/* Translucent dark button over photographs (hero "View project") */
.btn--glass {
  --btn-bg: rgba(16, 17, 18, 0.46);
  --btn-line: rgba(245, 243, 238, 0.32);
  --btn-fg: var(--bone);
}

/* Solid ink button (enquiry "Send enquiry") */
.btn--solid {
  --btn-bg: var(--ink);
  --btn-fg: var(--bone);
  --btn-line: var(--ink);
}

/* Hi-vis button, with a light fill on hover */
.btn--hivis {
  --btn-bg: var(--hivis);
  --btn-fg: var(--ink);
  --btn-line: var(--hivis);
  --btn-fill: var(--bone);
  --btn-fill-fg: var(--ink);
}

/* Scramble button (About): label re-typed on hover (initScramble in ui.js); text turns ink on the fill */
.btn--scramble {
  --btn-bg: rgba(16, 17, 18, 0.72);
  --btn-fg: var(--bone);
  --btn-line: transparent;
  --btn-fill: var(--hivis);
  --btn-fill-fg: var(--ink);
  align-items: center;
  gap: 1.1rem;
  min-height: 2.5rem;
  padding: 0 0.95rem 0 1rem;
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
}

.btn--scramble__text {
  display: inline-block;
  white-space: pre;                     /* keep spaces while letters are swapped */
  font-variant-numeric: tabular-nums;
}

.btn--scramble__icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  transition: transform var(--dur-3) var(--ease-roll);
}

.btn--scramble:hover .btn--scramble__icon,
.btn--scramble:focus-visible .btn--scramble__icon {
  transform: translateX(4px);
}

/* Square icon button (menu close, case study and viewer controls) ------------ */

.icon-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: inherit;
  box-shadow: inset 0 0 0 1px var(--line, currentColor);
  transition:
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}

.icon-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  transition: transform var(--dur-3) var(--ease-roll);
}

/* On hover the button fills with its own text colour and the icon inverts */
@media (hover: hover) {
  .icon-btn:hover {
    background: currentColor;
  }

  .icon-btn:hover svg {
    stroke: var(--icon-hover, var(--graphite));
  }
}

[data-theme="light"] .icon-btn,
.case .icon-btn {
  --icon-hover: var(--bone);
}


/* === 3. Loader =============================================================
   main.js draws the paths, raises the level (--level: 0 top, 1 bottom), then lifts the panels. */

.loader {
  display: none;
}

.js .loader {
  position: fixed;
  inset: 0;
  z-index: var(--z-loader);
  display: grid;
  place-items: center;
  color: var(--bone);
}

.loader__panels {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.loader__panels span {
  background: var(--graphite);
  box-shadow: inset -1px 0 0 rgba(245, 243, 238, 0.06);
}

.loader__drawing {
  position: relative;
  width: min(70vw, 600px);
  aspect-ratio: 600 / 440;
}

.loader__svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Every path starts hidden: dash length 1, offset 1 (pathLength="1") */
.loader__lines path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0.8;
}

/* The laser level: wider than the drawing, positioned by --level */
.loader__level {
  --level: 0.91;
  position: absolute;
  top: calc(var(--level) * 100%);
  left: -14vw;
  right: -14vw;
  height: 0;
}

.loader__level-line {
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: var(--hivis);
  box-shadow: 0 0 12px rgba(220, 245, 60, 0.6);
}

.loader__level-tag {
  position: absolute;
  right: 14vw;
  bottom: 6px;
  display: flex;
  gap: 0.8em;
  color: var(--hivis);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

/* "OMFC International" in the bottom-left corner */
.loader__meta {
  position: absolute;
  left: var(--margin);
  right: var(--margin);
  bottom: var(--margin);
  display: flex;
  justify-content: flex-start;
  gap: var(--s-4);
  color: var(--muted-on-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}


/* === 4. Menu ===============================================================
   Full-screen dialog: panels drop in, then the links rise (initMenu in ui.js). */

.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  overflow: hidden;
  color: var(--bone);
}

.menu__panels {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.menu__panels span {
  background: var(--graphite);
  box-shadow: inset -1px 0 0 rgba(245, 243, 238, 0.07);
  transform-origin: 50% 0;
}

/* Rows: [close button] / [links + preview] / [footer line] */
.menu__inner {
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-template-rows: auto 1fr auto;
  column-gap: var(--gutter);
  height: 100%;
  padding: var(--header-top) var(--margin) var(--margin);
  overflow-y: auto;
}

/* Close button, top right */
.menu__top {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  min-height: var(--header-h);
  color: var(--muted-on-dark);
}

.menu__close {
  --line: var(--line-on-dark);
  color: var(--bone);
}

.menu__nav {
  grid-column: 1 / span 8;
  align-self: center;
  padding-block: var(--s-7);
}

/* Each link rises out of its own mask when the menu opens */
.menu__list li {
  overflow: hidden;
}

.menu__list a {
  display: flex;
  align-items: baseline;
  gap: clamp(0.75rem, 2vw, 2rem);
  padding-block: 0.04em;
  font-family: var(--font-narrow);
  font-size: clamp(2.2rem, 5.4vh + 2.1vw, 6.4rem);   /* eight links fit a short laptop screen */
  font-weight: 300;
  font-stretch: 68%;
  line-height: 0.94;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  transition:
    opacity var(--dur-3) var(--ease-out),
    color var(--dur-2);
}

/* Small number before each link (01 to 07) */
.menu__no {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: var(--track-label);
  opacity: 0.5;
  transform: translateY(-1.6em);
}

/* Link roll: the hi-vis copy (from data-text) rolls up on hover */
.menu__text {
  display: block;
  overflow: hidden;
}

.menu__text > span {
  position: relative;
  display: block;
  transition: transform 0.6s var(--ease-roll);
}

.menu__text > span::after {
  content: attr(data-text);
  position: absolute;
  top: 100%;
  left: 0;
  color: var(--hivis);
}

@media (hover: hover) {
  /* Dim the other links while one is hovered */
  .menu__list:hover a {
    opacity: 0.32;
  }

  .menu__list a:hover,
  .menu__list a:focus-visible {
    opacity: 1;
  }

  .menu__list a:hover .menu__text > span {
    transform: translateY(-100%);
  }
}

/* Photograph preview for the hovered link */
.menu__preview {
  grid-column: 9 / -1;
  align-self: center;
  max-height: 68vh;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--graphite-2);
}

.menu__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Footer line with the London time, bottom right */
.menu__foot {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
  gap: var(--s-5);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line-on-dark);
  color: var(--muted-on-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 1.6;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

.menu__time time {
  color: var(--bone);
  font-variant-numeric: tabular-nums;
}

/* Mobile: links only, no preview */
@media (max-width: 767px) {
  .menu__inner {
    grid-template-columns: 1fr;
  }

  .menu__nav {
    grid-column: 1 / -1;
  }

  .menu__preview {
    display: none;
  }
}


/* === 5. Photo viewer ==================================================== */

.viewer {
  --line: var(--line-on-dark);
  position: fixed;
  inset: 0;
  z-index: var(--z-viewer);
  display: grid;
  background: rgba(13, 14, 15, 0.97);
  color: var(--bone);
}

/* Image on top, caption underneath */
.viewer__figure {
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  gap: var(--s-4);
  min-height: 0;
  padding: calc(var(--header-top) + 3.5rem) var(--margin) var(--margin);
}

.viewer__img {
  width: auto;
  min-height: 0;
  max-height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}

.viewer__caption {
  display: flex;
  gap: var(--s-4);
  max-width: 70ch;
  color: rgba(245, 243, 238, 0.8);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.viewer__caption .label {
  flex: none;
  padding-top: 0.15em;
  color: var(--hivis);
}

/* Previous / next / close, top right */
.viewer__controls {
  position: absolute;
  top: var(--header-top);
  right: var(--margin);
  display: flex;
  gap: var(--s-2);
}


/* === 6. Cookie choice (consent.js) =========================================
   A dark card fixed to the bottom of the screen until the visitor accepts or rejects analytics cookies; the footer's
   "Cookie settings" opens it again. Both buttons have the same weight: rejecting is as easy as accepting. */

.consent {
  position: fixed;
  right: var(--margin);
  bottom: var(--margin);
  left: var(--margin);
  z-index: var(--z-consent);
  display: grid;
  gap: var(--s-3);
  max-width: 27rem;
  padding: var(--s-5);
  background: var(--graphite);
  box-shadow: inset 0 0 0 1px var(--line), var(--shadow-float);
  font-size: var(--fs-small);
  line-height: var(--lh-body);
  opacity: 0;
  transform: translateY(1.5rem);
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
}

.consent.is-open {
  opacity: 1;
  transform: none;
}

.consent[hidden] {
  display: none;
}

.consent__title {
  color: var(--muted);
}

.consent__text .text-link {
  background-size: 100% 1px;
}

.consent__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-2);
}

.consent__actions .btn {
  flex: 1 1 8rem;
  justify-content: center;
}

@media (min-width: 768px) {
  .consent {
    right: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .consent {
    transition: none;
  }
}
