/* --------------------------------------------------------------------------
   Jost, served from this site's own fonts/ folder rather than from Google.
   Two files, ~20 KB each; nothing to configure, nothing third-party.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Jost";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("fonts/jost-300.woff2") format("woff2");
}

@font-face {
  font-family: "Jost";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/jost-700.woff2") format("woff2");
}

/* ==========================================================================
   Juci Architecture — juciarc.com
   One stylesheet for all three pages.
   ========================================================================== */

:root {
  --paper:   #ffffff;
  --ink:     #2a2a2a;
  --muted:   #5d5d5d;
  --slate:   #40505a;   /* the colour of the JUCI mark */
  --rule:    #e4e7e9;

  --measure: 460px;     /* reading width of the Info text and portrait */
  --gutter:  22px;      /* clear space at the screen edges on a phone */

  --serif: Georgia, "Times New Roman", Times, serif;
  --sans:  "Jost", "Century Gothic", system-ui, -apple-system, "Segoe UI", sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; }

a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 180ms ease, color 180ms ease;
}

a:hover,
a:focus-visible { border-bottom-color: currentColor; }

:focus-visible {
  outline: 2px solid var(--slate);
  outline-offset: 3px;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: 50%;
  top: -60px;
  transform: translateX(-50%);
  z-index: 50;
  padding: 10px 18px;
  background: var(--slate);
  color: #fff;
  font-size: 14px;
  transition: top 160ms ease;
}

.skip-link:focus { top: 10px; }


/* --------------------------------------------------------------------------
   Shared page furniture
   -------------------------------------------------------------------------- */

.page { display: flex; flex-direction: column; min-height: 100vh; }
.page__main { flex: 1 0 auto; }

.column {
  width: 100%;
  max-width: calc(var(--measure) + (var(--gutter) * 2));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.site-header {
  padding: 46px var(--gutter) 30px;
  text-align: center;
}

.site-header__logo { display: inline-block; border-bottom: 0; }

.site-header__logo img {
  display: block;
  width: clamp(168px, 30vw, 236px);
  height: auto;
}

.site-footer {
  flex-shrink: 0;
  margin-top: 78px;
  padding: 32px var(--gutter) 56px;
  text-align: center;
  border-top: 1px solid var(--rule);
}

.site-footer__nav a { margin: 0 11px; }

.site-footer__nav a[aria-current="page"] {
  color: var(--slate);
  border-bottom-color: var(--rule);
}

.site-footer__contact {
  margin: 26px 0 0;
  font-size: 14px;
  line-height: 2;
  color: var(--muted);
}


/* --------------------------------------------------------------------------
   Home — crossfade slideshow
   -------------------------------------------------------------------------- */

.slideshow {
  position: relative;
  width: 100%;
  /* Hold the whole picture on screen: never taller than the window less the
     logo above it, and never cropped to get there. */
  max-width: calc((100vh - 290px) * 1.5);
  max-width: calc((100svh - 290px) * 1.5);
  margin-inline: auto;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: #f2f3f4;
}

.slideshow__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 800ms ease;
}

.slideshow__slide.is-active { opacity: 1; }

.slideshow__slide img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

 /* No arrows. The right half of the picture goes forward, the left half goes
    back, and pressing and holding anywhere stops it. The cursor is what tells
    a visitor this, so these two halves stay invisible but keep real buttons
    underneath for anyone using a keyboard or a screen reader. */
.slideshow__zone {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50%;
  padding: 0;
  border: 0;
  background: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

/* The cursors are drawn here rather than taken from the browser's own set,
   because `w-resize` and `e-resize` are double-headed arrows in most browsers
   and so pointed both ways at once. Each is a single chevron, white over a
   soft dark copy of itself so that it stays legible on a light or a dark
   photograph, with the point of the cursor at its centre (the 16 16). While
   the picture is held, both halves show a pause mark instead. The named
   cursor after each comma is the fallback if the drawing fails to load. */

.slideshow__zone--prev {
  left: 0;
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 7 11 16 20 25' stroke='%232a2a2a' stroke-opacity='.62' stroke-width='5.5'/%3E%3Cpolyline points='20 7 11 16 20 25' stroke='%23ffffff' stroke-width='2.4'/%3E%3C/g%3E%3C/svg%3E") 16 16, w-resize;
}

.slideshow__zone--next {
  right: 0;
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='12 7 21 16 12 25' stroke='%232a2a2a' stroke-opacity='.62' stroke-width='5.5'/%3E%3Cpolyline points='12 7 21 16 12 25' stroke='%23ffffff' stroke-width='2.4'/%3E%3C/g%3E%3C/svg%3E") 16 16, e-resize;
}

.slideshow.is-holding .slideshow__zone {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg stroke-linecap='round'%3E%3Cpath d='M12 9.5v13M20 9.5v13' stroke='%232a2a2a' stroke-opacity='.62' stroke-width='7'/%3E%3Cpath d='M12 9.5v13M20 9.5v13' stroke='%23ffffff' stroke-width='3'/%3E%3C/g%3E%3C/svg%3E") 16 16, progress;
}

.slideshow__zone:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: -8px;
  filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.6));
}


/* --------------------------------------------------------------------------
   Info
   -------------------------------------------------------------------------- */

/* Justified, so the block of text sits in the same rectangle as the portrait
   below it rather than ending raggedly short of the picture's edge. Only the
   last line of each paragraph runs free, as it should in body text. */
.prose p {
  margin: 0 0 1.45em;
  line-height: 1.65;
  text-align: justify;
  hyphens: none;
}

.prose p:last-child { margin-bottom: 0; }

/* A figure carries a 40px side margin of the browser's own, which was holding
   the portrait 80px narrower than the text above it. Clearing it lets the
   picture fill the column, so its edges and the justified text's line up. */
.portrait { margin: 46px 0 0; }

.portrait img {
  display: block;
  width: 100%;
  height: auto;
}


/* --------------------------------------------------------------------------
   What Is Juci — four full-screen panels

   The base rules below are the version every browser gets: four ordinary
   stacked sections, each one screen tall, all fully visible. The scroll-driven
   crossfade is layered on top only when script.js confirms the browser can
   take it (see the .js-scene rules further down), so the page still reads
   correctly with scripting off.
   -------------------------------------------------------------------------- */

.scene { position: relative; }

.scene__layer {
  display: grid;
  place-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: 56px var(--gutter);
  background: var(--paper);
}

.scene__layer--image { padding: 0; }

.scene__layer--image img {
  display: block;
  width: 100%;
  height: 100vh;
  height: 100svh;
  object-fit: cover;
}

/* The closing panel. The mark is centred in the space above the footer rule
   rather than in the whole screen, so it does not sit low once the footer has
   arrived. --footer-h is measured by script.js, because the footer's height
   changes with the width of the screen. The whole lockup is centred, mark and
   wordmark together, not the square alone. */
.scene__mark img {
  display: block;
  width: clamp(168px, 30vw, 236px);
  height: auto;
}

/* Both statements are set justified, including their last line, so each one
   reads as a solid rectangle of text rather than as a ragged column. The two
   measures differ on purpose: each is the width at which that statement fills
   its lines without a short one left over, which is why the Architecture block
   is the wider of the two. Nothing is hyphenated.

   The Juci measure is 15.75em rather than the 15em that first looked right.
   At 15em its last line filled the measure to within a hair, and below about
   1050px wide, where the type starts scaling with the window, that hair was
   enough to drop "piece." onto a line of its own. The extra three quarters of
   an em is the margin that keeps four lines at every width. */
.statement {
  margin: 0;
  max-width: 15.75em;
  font-family: var(--sans);
  font-weight: 300;
  font-size: clamp(21px, 3.6vw, 38px);
  line-height: 1.34;
  text-align: justify;
  text-align-last: justify;
  hyphens: none;
  color: var(--ink);
}

.scene__layer--closing .statement { max-width: 18em; }

/* Juci and Architecture: bold and in the mark's slate, in ordinary case, so
   the two of them read as the firm's name across the two panels. */
.statement .term {
  font-weight: 700;
  letter-spacing: 0.015em;
  color: var(--slate);
}

/* A quiet mark that the page continues. Delete this rule and the
   <p class="scroll-cue"> in what-is-juci.html to remove it entirely. */
.scroll-cue {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  color: var(--muted);
  opacity: 0.5;
  transition: opacity 400ms ease;
  animation: cue-drift 2.6s ease-in-out infinite;
}

.scroll-cue svg { display: block; width: 18px; height: 18px; }
.scroll-cue.is-spent { opacity: 0; }

@keyframes cue-drift {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 6px); }
}

/* --- the enhanced version: all four panels pinned, crossfading on scroll ---

   The height below is the whole length of the scroll: raise it to make every
   transition slower and longer, lower it to quicken them all. The individual
   fades are placed along it by the five pairs at the top of script.js, where
   the mark's arrival is deliberately the longest passage of the page. */

.js-scene .scene {
  height: 700vh;
  height: 700svh;
}

.js-scene .scene__viewport {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
}

/* translateZ(0) hands each panel to the graphics card as its own layer. On a
   phone that is the difference between a smooth fade and a visible stutter,
   because the panel is then composited rather than redrawn on every frame. */
.js-scene .scene__layer {
  position: absolute;
  inset: 0;
  min-height: 0;
  height: 100%;
  opacity: 0;
  will-change: opacity;
  transform: translateZ(0);
  backface-visibility: hidden;
}

.js-scene .scene__layer--first { opacity: 1; }
.js-scene .scene__layer--image img { height: 100%; }

/* The closing statement clears before the mark arrives, so its text fades on
   its own while the white panel under it stays put, keeping the photograph
   covered. FADE_GO in script.js is when that happens. */
.js-scene .scene__layer--closing .statement { will-change: opacity; }

/* Each piece of text, and the mark, drifts a little as it fades, so that it
   reads as arriving rather than simply appearing. The white panels themselves
   never move, or their edges would show. DRIFT in script.js is the distance. */
.js-scene .statement,
.js-scene .scene__mark { will-change: opacity, transform; }

/* Centred above the footer, not in the whole screen. */
.js-scene .scene__layer--mark {
  padding-bottom: calc(56px + var(--footer-h, 0px));
}

/* While the panels are running, the footer is held at the foot of the screen
   and kept out of sight until the closing panel calls it up. Its opacity is
   set by script.js, on the same scroll position as the mark. */
.js-scene .site-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  margin-top: 0;
  background: var(--paper);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}

.js-scene .site-footer.is-present { pointer-events: auto; }


/* --------------------------------------------------------------------------
   Visitors who have asked their device for reduced motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .slideshow__slide { transition: none; }

  .scroll-cue { animation: none; }

  .js-scene .scene { height: auto; }

  .js-scene .scene__viewport {
    position: static;
    height: auto;
    overflow: visible;
  }

  .js-scene .scene__layer {
    position: relative;
    inset: auto;
    height: auto;
    min-height: 100vh;
    min-height: 100svh;
    opacity: 1 !important;
  }

  .js-scene .scene__layer--image img {
    height: 100vh;
    height: 100svh;
  }

  .js-scene .scene__layer--closing .statement { opacity: 1 !important; }

  .js-scene .statement,
  .js-scene .scene__mark { transform: none !important; }

  .js-scene .scene__layer--mark { padding-bottom: 56px; }

  .js-scene .site-footer {
    position: static;
    opacity: 1 !important;
    pointer-events: auto;
    margin-top: 78px;
  }
}


/* --------------------------------------------------------------------------
   Small screens
   -------------------------------------------------------------------------- */

@media (max-width: 600px) {
  .site-header { padding-top: 34px; }
  .site-footer { margin-top: 56px; }
  .site-footer__nav a { margin: 0 8px; }

  /* A phone is too narrow to hold the two measures, so both statements take
     the full width and rewrap. Their last lines no longer fall where they do
     on a larger screen, so justifying the last line is dropped here: it would
     otherwise stretch two remaining words across the whole width. */
  .statement,
  .scene__layer--closing .statement { max-width: 100%; }
  .statement { text-align-last: auto; }
}
