/* ============================================================
   journey.css — WELCOME TO MY JOURNEY

   Two layouts live in this file and only one is ever on screen:

   STATIC   the default. A plain illustrated list, in groups. This is
            what you get with JavaScript off, with WebGL missing, and
            under prefers-reduced-motion. It is not a fallback in the
            apologetic sense — it is the document, and it has to read
            as a designed page on its own.

   SPIRAL   added by js/journey.js once it has measured the stage and
            decided the device can carry it. It takes the same <img>
            elements and hangs them on omr's descending helix.

   Nothing here is generated from an array. Every photograph, title
   and caption is real markup in index.html.
   ============================================================ */

/* ------------------------------------------------------------
   THE LINE BEFORE IT

   Its own screen, on black. The projects case ends, this arrives,
   and the descent begins under it — so the spiral has somewhere
   to fall FROM rather than simply appearing.
   ------------------------------------------------------------ */
.jr-welcome{
  margin: 0;
  font-family: var(--body);
  font-weight: 800;
  font-size: clamp(2rem, 7vw, 5.5rem);
  line-height: 0.98;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  text-align: center;
  max-width: 14ch;
  margin-inline: auto;
  color: #FFFFFF;
}

/* ------------------------------------------------------------
   THE STAGE
   ------------------------------------------------------------ */
.jr{
  position: relative;
  padding: calc(var(--u) * 3) var(--gut);
  max-width: 78rem;
  margin-inline: auto;
}

.jr-stage{ position: relative; }

/* Each group is announced before its pictures — the heading is the
   thing that tells you a new chapter has started. */
.jr-head{
  margin: calc(var(--u) * 3) 0 calc(var(--u) * 1.2);
  font-family: var(--body);
  font-weight: 800;
  font-size: clamp(1.4rem, 3.4vw, 2.75rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: #FFFFFF;
}
.jr-group:first-child .jr-head{ margin-top: 0; }

/* The last group carries NO heading and NO captions, deliberately —
   his instruction, and it is the right one: after three chapters of
   explanation the ending should just be pictures. */

.jr-items{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
  gap: clamp(1rem, 2.6vw, 2.2rem);
}
.jr-item{ margin: 0; }

/* ------------------------------------------------------------
   A CARD

   The title sits over the bottom-left of the picture; the caption
   sits underneath it, outside the frame. That split is his, and it
   is a good one — the title belongs to the image, the caption is
   the voice next to it.
   ------------------------------------------------------------ */
.jr-card{
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: 3px;
  background: var(--ink-2);
  box-shadow: inset 0 0 0 1px var(--hair);
}
.jr-card img{
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 780 / 1024;
  object-fit: cover;
}

.jr-title{
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 2.6em 0.85em 0.7em;
  font-family: var(--body);
  font-weight: 800;
  font-size: clamp(0.95rem, 1.5vw, 1.35rem);
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: #FFFFFF;
  /* The scrim is what lets white type sit on ANY photograph. Without
     it the title is legible on the placeholders and disappears the
     moment a real, bright picture arrives. */
  background: linear-gradient(180deg,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 0.55) 45%,
    rgba(0, 0, 0, 0.86) 100%);
}

.jr-cap{
  margin: 0.7em 0 0;
  font-family: var(--body);
  font-weight: 400;
  font-size: clamp(0.85rem, 1.1vw, 1rem);
  line-height: 1.45;
  color: var(--muted);
}

/* ------------------------------------------------------------
   Reduced motion keeps exactly the layout above and adds nothing.
   js/journey.js checks the same flag and never starts.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce){
  .jr-stage{ position: static; }
}

@media (max-width: 34rem){
  .jr-items{ grid-template-columns: 1fr; }
  .jr-head{ margin-top: calc(var(--u) * 2); }
}

/* ============================================================
   THE TAKEOVER

   Set by js/journey.js ONLY after the spiral has actually drawn a
   frame. Set optimistically and then thrown, this would leave the
   photographs hidden with nothing in their place.
   ============================================================ */

/* NEVER display:none a card. Two things break at once if you do:
   lazy images stop fetching, so the texture never arrives; and the
   list's height IS the scroll runway the helix descends along, so
   the section collapses and the spiral has no scroll to run on.
   visibility:hidden still loads, still lays out, still reserves
   height — which is exactly what is wanted. */
body[data-journey="on"] .jr-item{
  visibility: hidden;
}

/* The stage becomes a full-height window onto the canvas behind, and
   the section keeps its height so the descent has somewhere to go. */
body[data-journey="on"] .jr-stage{
  position: relative;
}
/* ABOVE the photographs, not beside them. Left-aligned at mid-height
   the heading sat next to whichever card happened to be there and read
   as a caption for it; centred and high it reads as the title of the
   chapter you have just entered, with the pictures under it. */
body[data-journey="on"] .jr-head{
  position: sticky;
  top: 12svh;
  z-index: 2;
  pointer-events: none;
  text-align: center;
  margin: 0;
  padding: 0 var(--gut);
  text-shadow: 0 2px 24px rgba(0,0,0,0.85), 0 0 60px rgba(0,0,0,0.6);
}

/* The captions ride with their group rather than with their card —
   on the spiral a card is a moving object and text pinned to it
   would be unreadable. */
body[data-journey="on"] .jr-cap{
  visibility: hidden;
}

/* ------------------------------------------------------------
   THE GAP BEFORE THE JOURNEY

   #welcome is one line of type, but it inherited .ch--tall's 190svh
   and a sticky .hold that centres its content — so the heading sat
   in the middle of nearly two screens and left 910px of black
   between "More to come" and "Welcome to my journey". It still needs
   SOME runway, because the line lights word by word off the
   section's own scroll distance, but a third of a screen is plenty.
   ------------------------------------------------------------ */
#welcome{
  min-height: 86svh;
  padding-top: 0;
  padding-bottom: 0;
}
/* Sitting high in its own box rather than centred in it: the words
   should arrive as the case leaves, not a screen later. */
#welcome .hold{
  min-height: 42svh;
  justify-content: center;
}

/* And the case stops padding the bottom of its own section. .ch--tall
   is 190svh while the case plus its sign-off is about 100 — the ~90svh
   of trailing nothing was most of the gap before "Welcome to my
   journey". It keeps some, because the case is sticky and needs a
   little dwell, but not most of a screen of it. */
#build{ padding-bottom: 0; min-height: 124svh; }

/* The spiral starts right under the line, not a screen below it. */
#journey{ padding-top: calc(var(--u) * 0.5); }

@media (max-width: 46rem){
  #welcome{ min-height: 92svh; }
  #welcome .hold{ min-height: 56svh; }
}

/* ------------------------------------------------------------
   HOW FAST THE DESCENT READS

   t is progress through THIS section, so the section's height is the
   gearing: a taller section means the same wheel-turn covers less of
   the spiral. At the natural height of fourteen hidden list items it
   ran about a screen per photograph, which was too quick to look at
   any of them.
   ------------------------------------------------------------ */
/* The runway is bought PER ITEM, not by stretching the section.

   Stretching #journey made it 21 screens, but the four .jr-group boxes
   inside still only spanned their natural height — so the last third of
   the descent had no group box under it and the sticky headings had
   already unstuck and scrolled away. Giving each hidden item its own
   height makes the groups grow with the section, so a heading is
   sticky for exactly as long as its own photographs are on the helix. */
body[data-journey="on"] .jr-item{
  height: 150svh;
  min-height: 340px;
}
body[data-journey="on"] .jr-items{
  display: block;          /* the grid would lay 14 items side by side */
}
