/* THE MILESTONE TIMELINE — the rail behind the button at the foot of NEUStory.
   Dr KC's reference: a rail across the middle, year markers on it, and the
   cards alternating above and below so the eye zig-zags along the years
   instead of reading a list.

   Kept in its own file, like profile.css and reelbox.css, so a timeline
   cannot disturb a section that was already working. */

/* ── the overlay ── */
.mstone {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(0.6rem, 2vw, 2rem);
}
.mstone[hidden] { display: none; }
.mstone__scrim {
  position: absolute; inset: 0;
  background: rgba(4, 10, 22, 0.72);
  backdrop-filter: blur(6px);
}

.mstone__box {
  position: relative;
  width: min(1400px, 100%);
  max-height: min(92vh, 900px);
  display: flex; flex-direction: column;
  background: linear-gradient(180deg, #f7fafe 0%, #ffffff 46%, #f2f7fd 100%);
  color: #0d1b2a;
  border-radius: clamp(16px, 2vw, 26px);
  box-shadow: 0 40px 120px -40px rgba(4, 10, 22, 0.75);
  overflow: hidden;
  animation: mstone-in 0.32s cubic-bezier(0.2, 0.8, 0.3, 1) both;
}
@keyframes mstone-in {
  from { opacity: 0; transform: translateY(18px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .mstone__box { animation: none; } }

/* ── the head ── */
.mstone__head {
  padding: clamp(16px, 2.4vw, 30px) clamp(18px, 3vw, 42px) clamp(8px, 1.4vw, 16px);
  border-bottom: 1px solid rgba(13, 27, 42, 0.08);
}
.mstone__kicker {
  margin: 0 0 4px;
  color: var(--blue, #0078FF); font-weight: 800;
  font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
}
.mstone__h {
  margin: 0 0 6px;
  font-size: clamp(22px, 3.2vw, 40px); line-height: 1.05; letter-spacing: -0.02em;
}
.mstone__lead {
  margin: 0; max-width: 62ch;
  color: rgba(13, 27, 42, 0.62); line-height: 1.55;
  font-size: clamp(13px, 1.3vw, 16px);
}
.mstone__x {
  position: absolute; top: clamp(10px, 1.6vw, 18px); right: clamp(10px, 1.6vw, 18px);
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(13, 27, 42, 0.12); background: #fff;
  font-size: 24px; line-height: 1; color: #0d1b2a;
  cursor: pointer;
}
.mstone__x:hover { background: #eef4fd; }

/* ── the rail ──
   THREE ROWS: a card above, the rail, a card below. Every item is one column
   of the same grid, so the pegs line up on one straight line however tall the
   cards on either side turn out to be — which is what makes it read as a
   timeline rather than as two rows of cards with a line between them. */
/* A FLEX CONTAINER, so that the rail inside it can be given the height there
   actually is. `height: 100%` on the rail did nothing at all: a percentage
   height needs a definite height to measure against, and `.mstone__box` has a
   max-height and no height — its own height comes from its content, so asking
   the content how tall it should be is circular and the browser correctly
   ignores it. `align-items: stretch` does not have that problem: it hands the
   child the container's used height once layout has worked it out.

   The tell was that a hard pixel height on the rail made the rows collapse to
   171px immediately — the row sizing was never the fault. */
.mstone__scroll {
  flex: 1; min-height: 0;
  display: flex; align-items: stretch;
  overflow-x: auto; overflow-y: hidden;
  padding: clamp(10px, 1.6vw, 22px) clamp(18px, 3vw, 42px);
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
}
.mstone__scroll:focus-visible { outline: 3px solid var(--blue, #0078FF); outline-offset: -3px; }
@media (prefers-reduced-motion: reduce) { .mstone__scroll { scroll-behavior: auto; } }

/* THE ROWS ARE minmax(0, 1fr), NOT 1fr, and the difference is the whole
   layout. A plain `1fr` row will not shrink below the tallest thing in it —
   its minimum is min-content — so with a 350px card above and a 350px card
   below, the grid insisted on being 760px tall inside a 600px space, the rail
   was pushed almost a hundred pixels below centre, and the lower cards ran
   out through the foot of the panel. `minmax(0, …)` lets the rows take the
   height there is; the cards below cap themselves to their row and clip
   politely instead of the whole rail sliding. */
.mtl {
  list-style: none; margin: 0; padding: 0;
  flex: none;                            /* keep its full width; the box scrolls */
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(210px, 21vw, 280px);
  grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);   /* above · rail · below */
  gap: 0 clamp(10px, 1.4vw, 20px);
  align-items: stretch;
  min-width: min-content;
}

/* An item owns all three rows of its column; which row its card sits in is
   what makes it an up or a down. */
.mtl__item {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  position: relative;
  --c: #7aa2ff;                          /* the chapter's colour, set below */
}
/* subgrid is the clean way to do this and is widely supported now, but a
   browser without it must not collapse the rail — so the rows are restated. */
@supports not (grid-template-rows: subgrid) {
  .mtl__item { grid-template-rows: 1fr auto 1fr; }
}
.mtl__item--up   .mcard { grid-row: 1; align-self: end;   margin-bottom: 14px; }
.mtl__item--down .mcard { grid-row: 3; align-self: start; margin-top: 14px; }
/* never taller than the row it is standing in — with the margin taken off,
   or the last 14px of every card would be the thing that overflows */
.mtl__item--up   .mcard { max-height: calc(100% - 14px); }
.mtl__item--down .mcard { max-height: calc(100% - 14px); }
.mtl__peg { grid-row: 2; }

/* THE RAIL ITSELF is drawn by the pegs, not by one long line under them:
   a line under an overflowing grid stops at the viewport and leaves the
   later years floating. Each peg carries its own segment, so the rail is
   exactly as long as the timeline is. */
.mtl__peg {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  height: 58px;
}
/* AN OPAQUE GREY, NOT A TRANSLUCENT ONE. Each peg's segment reaches a whole
   gap either side so the rail cannot break on a sub-pixel rounding — which
   means neighbouring segments overlap by the width of the gap. At 13% black
   that overlap painted itself twice and left a darker dash at the midpoint
   between every pair of dots, evenly spaced all the way down the rail and
   looking for all the world like a deliberate dashed line. An opaque colour
   is the same grey however many times it is painted. */
.mtl__peg::before {
  content: ''; position: absolute;
  left: calc(-1 * clamp(10px, 1.4vw, 20px)); right: calc(-1 * clamp(10px, 1.4vw, 20px));
  top: 50%; height: 3px; transform: translateY(-50%);
  background: #dee4ec;
}
.mtl__item:first-child .mtl__peg::before { left: 50%; border-radius: 2px 0 0 2px; }
.mtl__item:last-child  .mtl__peg::before { right: 50%; border-radius: 0 2px 2px 0; }

.mtl__dot {
  position: relative; z-index: 2;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--c);
  border: 3px solid #fff;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c) 34%, transparent),
              0 6px 14px -6px rgba(9, 20, 34, 0.6);
}
/* the stalk from the dot up or down to its card */
.mtl__peg::after {
  content: ''; position: absolute; left: 50%; width: 2px;
  transform: translateX(-50%);
  background: color-mix(in srgb, var(--c) 55%, transparent);
}
.mtl__item--up   .mtl__peg::after { bottom: 50%; height: 22px; }
.mtl__item--down .mtl__peg::after { top: 50%; height: 22px; }

/* THE YEAR, announced once — on the first card that belongs to it. Repeating
   "2025" over every card in 2025 is what makes an infographic look like a
   spreadsheet. */
.mtl__year {
  position: absolute; left: 50%; transform: translateX(-50%);
  top: calc(50% + 16px);
  font-style: normal; font-weight: 800; font-size: 13px; letter-spacing: 0.04em;
  color: #0d1b2a;
  background: #fff;
  border: 1px solid rgba(13, 27, 42, 0.1);
  border-radius: 999px; padding: 2px 10px;
  box-shadow: 0 6px 14px -8px rgba(9, 20, 34, 0.5);
  white-space: nowrap;
}
/* a card hanging BELOW the rail would sit on its own year badge */
.mtl__item--down .mtl__year { top: auto; bottom: calc(50% + 16px); }

/* ── a card on the rail ── */
.mcard {
  display: flex; flex-direction: column;
  min-height: 0; overflow: hidden;
  background: #fff;
  border: 1px solid rgba(13, 27, 42, 0.09);
  border-top: 4px solid var(--c);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 20px 46px -34px rgba(9, 20, 34, 0.6);
}
/* THE HEIGHT BUDGET, and it is a budget rather than a set of nice numbers.
   A card gets half of what is left after the rail — about 260px on a 900px
   window — and a 16:9 picture across a 276px card is 155px of that on its
   own. The text had 76px to live in and the first thing it lost was the
   headline: several cards showed a date, a photograph, and nothing else.

   So the picture is given a height rather than a ratio, and every part of the
   text except the body is `flex: none`. The body is the only thing that can
   give, and it gives by ellipsis rather than by pushing the headline out of
   the card. Whatever the window height, a card shows at minimum its date,
   its headline and its link. */
.mcard__media {
  display: block; flex: none;
  height: clamp(84px, 12.5vh, 132px);
  background: #e8eef7;
}
.mcard__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.mcard__text {
  flex: 1; padding: 10px 13px 12px;
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
}
.mcard__when {
  flex: none; margin: 0 0 2px;
  font-weight: 800; font-size: 11.5px; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--c);
}
/* two lines of headline, and never fewer than the whole of them */
.mcard__h {
  flex: none; margin: 0 0 5px;
  font-size: 14.5px; line-height: 1.25; letter-spacing: -0.01em;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* THE BODY IS CLAMPED, not left to run. These are news paragraphs of wildly
   different lengths, and one 400-word card would set the height of every row
   in the grid — the cards are stretched to a common height by the layout, so
   the tallest one decides. Four lines is enough to know what happened. */
.mcard__body {
  flex: 1 1 auto; min-height: 0;
  margin: 0; font-size: 12.5px; line-height: 1.45; color: rgba(13, 27, 42, 0.7);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* `margin-top: auto` keeps the link on the floor of the card whether the body
   ran to three lines or to none, so the row of links reads straight across */
.mcard__link {
  flex: none; margin-top: auto; padding-top: 8px;
  font-size: 12.5px; font-weight: 700; color: var(--blue, #0078FF); text-decoration: none;
}
.mcard__link:hover { text-decoration: underline; }

/* THE ONES WITH NO DATE. They are not hidden and not guessed at: they stand at
   the end of the rail, plainly marked, where anybody who can edit Backstage
   can see there is something to fill in. */
.mtl__item--undated { --c: #93a3b8; }
.mtl__item--undated .mcard { border-top-style: dashed; }
.mtl__item--undated .mcard__when { color: #7c8ba0; }
.mtl__item--undated .mtl__dot { background: #fff; border-color: #c3ccd9; box-shadow: none; }

/* ── the chapter colours, the same eight the rest of the site uses ── */
.mtl__item[data-pillar="neucity"]    { --c: #ff9f1c; }
.mtl__item[data-pillar="neunature"]  { --c: #2ec4a6; }
.mtl__item[data-pillar="neumotion"]  { --c: #4aa8ff; }
.mtl__item[data-pillar="neufactory"] { --c: #a86bff; }
.mtl__item[data-pillar="neuslm"]     { --c: #00d4c8; }
.mtl__item[data-pillar="neutalents"] { --c: #ff5fa2; }
.mtl__item[data-pillar="neustudio"]  { --c: #ffd166; }
.mtl__item[data-pillar="neustory"]   { --c: #7aa2ff; }
/* an undated card keeps the grey, whatever chapter it belongs to */
.mtl__item--undated[data-pillar] { --c: #93a3b8; }

/* ── the foot ── */
.mstone__foot {
  display: flex; align-items: center; gap: clamp(10px, 2vw, 20px);
  padding: clamp(10px, 1.4vw, 16px) clamp(18px, 3vw, 42px);
  border-top: 1px solid rgba(13, 27, 42, 0.08);
  background: #fff;
}
.mstone__arrows { display: flex; gap: 8px; }
.mstone__arrow {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(13, 27, 42, 0.12); background: #fff;
  font-size: 20px; line-height: 1; color: #0d1b2a; cursor: pointer;
}
.mstone__arrow:hover { background: #eef4fd; }
.mstone__count {
  margin: 0; font-size: 12.5px; color: rgba(13, 27, 42, 0.55);
}
.mstone__all {
  margin-left: auto;
  font-weight: 700; font-size: 13.5px;
  color: var(--blue, #0078FF); text-decoration: none;
}
.mstone__all:hover { text-decoration: underline; }

/* ================= A PHONE READS A TIMELINE DOWNWARDS =================
   A rail across the screen is 280px of card in a 390px window: one card
   visible, and no sense of a run of years at all. So on a phone the rail
   turns ninety degrees — it goes down the left-hand side and the cards stack
   beside it, which is the same information and the only shape that fits.

   Not a media query on width alone: a phone on its side is 844px wide and
   390px tall, and the horizontal rail needs HEIGHT for a card above and a
   card below. Both cases want the upright rail. */
@media (max-width: 820px), (max-height: 560px) {
  .mstone { padding: 0; }
  .mstone__box { max-height: 100vh; height: 100vh; border-radius: 0; width: 100%; }
  .mstone__scroll {
    overflow-x: hidden; overflow-y: auto;
    padding: 14px clamp(12px, 4vw, 20px) 20px;
  }
  .mtl {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    grid-template-rows: none;
    grid-template-columns: 46px 1fr;      /* the rail · the card */
    gap: 0;
    min-width: 0;
    /* AND IT MUST NOT KEEP ITS max-content WIDTH. `flex: none` is right for
       the sideways rail — that is what makes the box scroll — and wrong here,
       where it left the upright timeline 2752px wide inside a 390px phone and
       scrolling in both directions at once. */
    flex: 1 1 auto; width: 100%;
  }
  .mtl__item {
    grid-row: auto;
    grid-template-rows: none;
    grid-template-columns: subgrid;
    grid-column: 1 / -1;
  }
  @supports not (grid-template-columns: subgrid) {
    .mtl__item { grid-template-columns: 46px 1fr; }
  }
  /* up and down stop meaning anything — every card is to the right of the rail.
     BOTH ARE PINNED TO ROW 1, not left on `auto`: auto-placement fills the
     card into row 1 column 2 first, and the cursor never goes back for the
     free cell at row 1 column 1, so the peg dropped into row 2 and every dot
     sat between its own card and the next one down. */
  .mtl__item--up .mcard, .mtl__item--down .mcard {
    grid-row: 1; grid-column: 2;
    align-self: auto; margin: 0 0 14px; max-height: none;
  }
  .mtl__peg {
    grid-row: 1; grid-column: 1;
    height: auto; align-items: flex-start; padding-top: 16px;
  }
  /* the rail runs down the column instead of across it */
  .mtl__peg::before {
    left: 50%; right: auto; top: 0; bottom: -14px; height: auto; width: 3px;
    transform: translateX(-50%);
  }
  .mtl__item:first-child .mtl__peg::before { top: 16px; }
  .mtl__item:last-child  .mtl__peg::before { bottom: 50%; }
  .mtl__peg::after { display: none; }     /* no stalk: the card is alongside */
  .mtl__year {
    position: static; transform: none; margin-top: 6px;
    writing-mode: vertical-rl; padding: 8px 2px;
  }
  .mstone__foot { flex-wrap: wrap; }
}
