/* ===========================================================================
   THE WEDDING JOURNEY

   One railway row per event. Each row is a signal, a track and a locomotive
   that waits on the right until the signal is cleared, then runs to the left
   carrying its destination board.

   Nothing here touches page scrolling: the only trigger is a click on the
   signal. The travel itself is a transition on translate3d, so it stays on
   the compositor and never runs a layout per frame.
   =========================================================================== */

.jsec{position:relative}

/* ------------------------------------------------------------ a journey -- */
.jrow{position:relative;margin-top:clamp(22px,4vw,38px);
  padding:clamp(14px,2.4vw,22px) clamp(12px,2.2vw,22px) clamp(10px,1.8vw,16px);
  border-radius:14px;
  background:linear-gradient(180deg,rgba(141,110,62,.07),rgba(109,79,38,.13));
  box-shadow:inset 0 0 0 1px rgba(122,96,54,.16)}

.jhead{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}
.jcode{font-size:10px;letter-spacing:.2em;color:#8a7850;
  border:1px solid rgba(138,120,80,.45);border-radius:3px;padding:2px 7px}
.jname{font-family:var(--serif);font-size:clamp(16px,3vw,23px);color:var(--rail);
  letter-spacing:.01em}

.jline{display:flex;align-items:flex-end;gap:clamp(8px,1.6vw,16px)}

/* -------------------------------------------------------------- signal --- */
/* a two-aspect post signal; the whole thing is the button */
.jsignal{flex:0 0 auto;position:relative;width:clamp(30px,5vw,42px);
  height:clamp(118px,22vw,240px);
  background:none;border:0;padding:0;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;
  -webkit-tap-highlight-color:transparent}
.jsig-head{position:relative;width:100%;border-radius:7px;
  padding:clamp(5px,.9vw,8px) 0;display:flex;flex-direction:column;
  align-items:center;gap:clamp(4px,.8vw,7px);
  background:linear-gradient(#2b323c,#161b21);
  box-shadow:0 5px 12px rgba(16,22,30,.4),inset 0 1px 0 rgba(255,255,255,.14)}
.jlamp{width:clamp(13px,2.3vw,19px);aspect-ratio:1;border-radius:50%;
  background:#2a2f36;box-shadow:inset 0 0 0 2px rgba(0,0,0,.5);
  transition:background .45s ease,box-shadow .45s ease}
.jsignal .jlamp.red{background:radial-gradient(circle at 36% 32%,#ff8d7a,#c62b1c);
  box-shadow:inset 0 0 0 2px rgba(0,0,0,.45),0 0 14px 3px rgba(226,66,45,.6)}
.jsignal[aria-pressed="true"] .jlamp.red{
  background:#3a2422;box-shadow:inset 0 0 0 2px rgba(0,0,0,.5)}
.jsignal[aria-pressed="true"] .jlamp.green{
  background:radial-gradient(circle at 36% 32%,#b6ffc8,#1f9c45);
  box-shadow:inset 0 0 0 2px rgba(0,0,0,.45),0 0 16px 4px rgba(42,190,90,.6)}
.jsig-post{flex:1;width:clamp(6px,1vw,9px);
  background:linear-gradient(90deg,#39414c,#20262e 60%,#161a1f)}
.jsig-foot{width:100%;height:clamp(6px,1vw,9px);border-radius:3px;
  background:linear-gradient(#39414c,#1a1f25)}
.jsignal:focus-visible{outline:3px solid #e8c98a;outline-offset:4px;border-radius:9px}
.jsignal:hover .jsig-head{filter:brightness(1.12)}

/* ====================================================== the station ======
   The scene the train runs through: a lit arcade in the distance, a canopy
   overhead with hanging lamps, and a platform underfoot.

   All of it is gradients plus ONE small inline SVG of a single arch bay,
   repeated along the x axis as a background. No raster asset, no extra
   request, and nothing animates, so it rasterises once and never again.
   Everything sits behind the rails and is deliberately low in contrast — the
   nameboard on the coach has to stay the clearest thing in the row.
   ========================================================================= */
/* masked at both ends so the shed dissolves into the row instead of
   stopping dead at the track's edge */
.jscene{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;
  --ground:24px;--canopy:clamp(11px,1.8vw,18px);--scal:clamp(7px,1.15vw,13px);
  --drop:clamp(16px,4vw,54px);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 4%,#000 96%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 4%,#000 96%,transparent 100%)}
.jscene > i{position:absolute;display:block}

/* the warm air of the trainshed, brightest away toward the far end */
.jsky{left:0;right:0;top:0;bottom:var(--ground);
  background:
    radial-gradient(120% 90% at 50% 100%,rgba(255,236,198,.55),rgba(255,236,198,0) 62%),
    linear-gradient(180deg,#b9a480 0%,#d9c8a6 22%,#ece1cb 58%,#f4ecdb 100%)}

/* the arcade: one bay tiled along the platform, sitting on the ground line */
.jarcade{left:0;right:0;bottom:var(--ground);top:calc(var(--canopy) * 1.6);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='215'%3E%3Crect width='170' height='215' fill='%23ece0c9'/%3E%3Crect width='170' height='11' fill='%23dccaa6'/%3E%3Crect y='11' width='170' height='13' fill='%23e7d8ba'/%3E%3Crect y='24' width='16' height='191' fill='%23e4d4b5'/%3E%3Crect x='154' y='24' width='16' height='191' fill='%23e4d4b5'/%3E%3Cpath d='M32 215V120a53 53 0 0 1 106 0v95z' fill='%23d2c3a2'/%3E%3Cpath d='M42 215V124a43 43 0 0 1 86 0v91z' fill='%23aeb5c0'/%3E%3Cpath d='M42 215V124a43 43 0 0 1 86 0v91z' fill='none' stroke='%23cbba96' stroke-width='3'/%3E%3Crect x='83.5' y='82' width='3' height='133' fill='%23cbba96'/%3E%3Crect x='42' y='118' width='86' height='3' fill='%23cbba96'/%3E%3Crect x='42' y='158' width='86' height='3' fill='%23cbba96'/%3E%3Crect y='205' width='170' height='10' fill='%23d6c4a0'/%3E%3C/svg%3E");
  background-repeat:repeat-x;background-position:left bottom;
  background-size:auto 100%;opacity:.6}

/* haze, which is what puts the architecture in the distance. A blur filter
   would do it too but would rasterise a wide layer on every paint, and this
   section already learned that lesson with the train's motion blur. */
.jhaze{left:0;right:0;top:0;bottom:var(--ground);
  background:linear-gradient(180deg,
    rgba(244,236,219,.42) 0%,rgba(244,236,219,.2) 38%,
    rgba(244,236,219,.46) 74%,rgba(236,224,200,.78) 100%)}

/* the platform canopy and its scalloped valance */
.jcanopy{left:0;right:0;top:0;height:var(--canopy);
  background:linear-gradient(#6b4a2e,#4a3019);
  box-shadow:0 2px 0 rgba(0,0,0,.1)}
/* The valance was drawn with a hardcoded 7px radius on a 16px tile, but the
   strip's height was responsive — on a phone that height fell to about 5px,
   so each arc was sliced off before it bottomed out and the scallops met as
   sharp points. Radius, tile width and height now all come from one value:
   a circle centred on the top edge, a tile exactly two radii wide and a strip
   exactly one radius tall is a true semicircle, edge to edge, at any size. */
.jcanopy::after{content:"";position:absolute;left:0;right:0;top:100%;
  height:var(--scal);
  background:radial-gradient(circle at 50% 0,
               #4a3019 calc(var(--scal) - .5px),transparent var(--scal))
             0 0/calc(var(--scal) * 2) 100% repeat-x}

/* lamps hung from the canopy */
.jlamps{left:0;right:0;top:var(--canopy);height:0}
.jlamps b{position:absolute;top:var(--drop);
  width:clamp(8px,1.3vw,12px);height:clamp(11px,1.9vw,17px);
  border-radius:3px 3px 54% 54%;translate:-50% 0;
  background:linear-gradient(#fff3cb,#e8a93c);
  box-shadow:0 0 17px 6px rgba(255,201,113,.4),inset 0 -1px 0 rgba(120,70,10,.3)}
.jlamps b::before{content:"";position:absolute;left:50%;bottom:100%;width:2px;
  height:var(--drop);translate:-50% 0;background:#4a3524}
.jlamps b:nth-child(1){left:14%} .jlamps b:nth-child(2){left:38%}
.jlamps b:nth-child(3){left:62%} .jlamps b:nth-child(4){left:86%}

/* the platform itself: stone courses, with the ballast up at the rail line */
.jground{left:0;right:0;bottom:0;height:var(--ground);
  background:
    repeating-linear-gradient(90deg,
      rgba(120,96,58,.16) 0 1px,rgba(0,0,0,0) 1px clamp(26px,4.4vw,42px)),
    linear-gradient(180deg,#d9c7a1 0%,#cbb68e 46%,#bda67c 100%)}
/* where the train meets the ground */
.jground::before{content:"";position:absolute;left:0;right:0;top:0;height:46%;
  background:linear-gradient(180deg,rgba(60,38,14,.22),rgba(60,38,14,0))}

/* --------------------------------------------------------------- track --- */
/* The height of this box IS the height of the outer row: the station
   scene, the rails and the train all live in it. The coach's own size is
   driven by --th and is deliberately independent of it. */
.jtrack{position:relative;flex:1 1 auto;min-width:0;
  height:clamp(170px,26vw,330px);overflow:hidden}

/* sleepers first, rails on top of them */
.jsleepers{position:absolute;z-index:1;left:0;right:0;bottom:7px;height:clamp(13px,2.2vw,19px);
  background:repeating-linear-gradient(90deg,
    #6b4a2c 0 clamp(7px,1.2vw,10px),
    rgba(0,0,0,0) clamp(7px,1.2vw,10px) clamp(20px,3.4vw,30px));
  opacity:.75}
.jrail{position:absolute;z-index:1;left:0;right:0;height:4px;border-radius:2px;
  background:linear-gradient(#b4bec9,#6c7682 55%,#3d444c);
  box-shadow:0 1px 3px rgba(0,0,0,.3)}
.jrail.top{bottom:19px} .jrail.bottom{bottom:4px}
@media (max-width:620px){
  .jrail.top{bottom:16px} .jrail.bottom{bottom:3px}
}

/* --------------------------------------------------------- the train ----- */
/* Engine in front (left, the direction of travel) with the event coach
   coupled behind it. --th is the engine's height and everything else is
   derived from it, so the two always sit on the same rail.

   The parked offset is (track width - ENGINE width), not the whole train's.
   That parks the engine against the right buffer and leaves the coach beyond
   the edge, where the track's clipping hides it; the coach is then revealed
   by travelling into view rather than by fading.

   That offset is written to `transform` inline by script, NOT held in a custom
   property. A transitioned `transform:translate3d(var(--x),0,0)` looks correct
   but never moves: the browser decides whether to start a transition by
   comparing the SPECIFIED value, which is textually identical on every change,
   so the new offset is swallowed and the train sits still. */
.jtrain{--th:clamp(58px,11vw,112px);
  position:absolute;z-index:2;left:0;bottom:0;display:flex;align-items:flex-end;
  transition:transform 4.6s cubic-bezier(.42,.02,.22,1)}

.jloco{position:relative;display:block;flex:0 0 auto}
.loco-img{display:block;height:var(--th);width:auto;
  filter:drop-shadow(0 6px 11px rgba(30,18,6,.4))}

/* the drawbar between engine and coach */
.jhook{flex:0 0 auto;width:clamp(6px,1.1vw,12px);
  height:calc(var(--th) * .07);margin-bottom:calc(var(--th) * .1);
  background:linear-gradient(#9aa4b0,#4a525c);border-radius:2px}

/* a gentle shudder as it pulls away */
.jrow.running .loco-img{animation:jchug .34s ease-in-out 8}
@keyframes jchug{50%{transform:translateY(-1.5px)}}

/* ---- steam, only while running ---- */
.jsteam{position:absolute;left:16%;top:-13%;width:15%;height:34%;
  pointer-events:none;opacity:0;transition:opacity .4s ease;z-index:2}
.jrow.running .jsteam{opacity:1}
.jsteam i{position:absolute;bottom:0;left:50%;width:78%;aspect-ratio:1;
  border-radius:50%;background:rgba(255,255,255,.7)}
.jrow.running .jsteam i{animation:jpuff 1.6s ease-out infinite}
.jsteam i:nth-child(2){animation-delay:.53s}
.jsteam i:nth-child(3){animation-delay:1.06s}
@keyframes jpuff{
  0%{transform:translate(-50%,0) scale(.35);opacity:.72}
  100%{transform:translate(-150%,-190%) scale(2.2);opacity:0}
}

/* -------------------------------------------------- the event coach ------ */
/* A full-height carriage, taller than the engine, with the details set into
   its side as a lit nameboard rather than laid over the train as a card. */
.jcoach{flex:0 0 auto;position:relative;
  /* 40vw, not 34: between about 700 and 1200px the coach was too narrow for
     its own type and the time clipped at 768. The 480px cap is unchanged,
     so the wide-desktop design is untouched. */
  width:clamp(168px,40vw,480px);height:calc(var(--th) * 1.45);
  display:flex;flex-direction:column;
  margin-bottom:calc(var(--th) * .02);
  background:none;border:0;padding:0;text-align:inherit;
  -webkit-tap-highlight-color:transparent;
  filter:drop-shadow(0 8px 14px rgba(30,18,6,.36));
  transition:transform .3s cubic-bezier(.2,.8,.3,1),filter .3s ease}
.jcoach:disabled{cursor:default}
.jcoach:not(:disabled){cursor:pointer}
.jcoach:not(:disabled):hover,.jcoach:not(:disabled):focus-visible{
  transform:translateY(-2px) scale(1.012);
  filter:drop-shadow(0 13px 20px rgba(30,18,6,.44)) brightness(1.05)}
.jcoach:focus-visible{outline:3px solid #e8c98a;outline-offset:4px;border-radius:7px}

.jc-roof{position:relative;display:block;height:calc(var(--th) * .075);
  border-radius:calc(var(--th) * .055) calc(var(--th) * .055) 0 0;
  background:linear-gradient(#424a58 0%,#242b36 46%,#141920 100%)}
.jc-roof i{position:absolute;top:calc(var(--th) * -.03);width:8%;
  height:calc(var(--th) * .034);border-radius:3px 3px 0 0;
  background:linear-gradient(#525b66,#2d333b)}
.jc-roof i:nth-child(1){left:18%} .jc-roof i:nth-child(2){left:46%}
.jc-roof i:nth-child(3){left:74%}

/* the cream bands above and below the window line */
.jc-cant,.jc-waist{display:block;height:calc(var(--th) * .045);
  background:linear-gradient(#f6e8c8,#e2cfa4);
  box-shadow:inset 0 0 0 1px rgba(201,169,97,.5)}

.jc-body{flex:1;min-height:0;display:flex;align-items:stretch;
  gap:1.6%;padding:calc(var(--th) * .02) 2.6%;
  background:linear-gradient(180deg,#a8402f 0%,#8e2f22 46%,#5d1a16 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16)}
.jc-door{flex:0 0 auto;width:4.5%;align-self:stretch;border-radius:2px;
  background:linear-gradient(#7d2519,#4d1310);
  box-shadow:inset 0 0 0 1px rgba(201,169,97,.45)}
.jc-win{flex:0 0 auto;width:9%;align-self:center;
  height:52%;border-radius:3px;
  background:linear-gradient(165deg,#eff7fc,#c4d7e6 62%,#e7eef4);
  box-shadow:inset 0 0 0 1.6px #cba85c,0 1px 3px rgba(40,14,0,.35)}

/* the nameboard set into the carriage side */
.jc-sign{flex:1 1 auto;min-width:0;align-self:center;
  display:flex;flex-direction:column;justify-content:center;
  text-align:center;padding:calc(var(--th) * .065) 4.5%;border-radius:3px;
  background:linear-gradient(#fdf7e7,#ecdfc0);
  box-shadow:inset 0 0 0 1.6px #cba85c,
             inset 0 0 0 3.2px rgba(141,47,34,.35),
             0 2px 6px rgba(40,14,0,.32)}
.jc-sign b{display:block;font-family:var(--serif);font-weight:600;
  font-size:clamp(23px,1.6vw + 17px,31px);line-height:1.15;letter-spacing:.015em;
  color:#7a2118;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.jc-rule{display:block;height:1px;margin:calc(var(--th) * .03) 14%;
  background:linear-gradient(90deg,transparent,#c9a24e 22%,#c9a24e 78%,transparent)}
.jc-date,.jc-time{display:block;font-style:normal;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;line-height:1.3}
.jc-date{font-size:clamp(17px,.9vw + 13.6px,22px);letter-spacing:.07em;color:#1d2b4a}
.jc-time{font-size:clamp(15px,.7vw + 12.4px,19px);letter-spacing:.03em;
  color:#5e4a22;opacity:.9}

.jc-skirt{display:block;height:calc(var(--th) * .055);
  background:linear-gradient(#4a1411,#300c0a)}
.jc-under{position:relative;display:flex;justify-content:space-around;
  height:calc(var(--th) * .17);padding:0 9%}
.jc-under::before{content:"";position:absolute;left:3%;right:3%;top:0;
  height:calc(var(--th) * .045);background:linear-gradient(#2d323a,#171b21)}
.jc-bogie{position:relative;display:flex;align-items:flex-end;
  gap:calc(var(--th) * .03)}
.jc-bogie i{width:calc(var(--th) * .125);aspect-ratio:1;border-radius:50%;
  background:repeating-conic-gradient(from 14deg,#4d545f 0 8deg,#262c34 8deg 45deg);
  box-shadow:inset 0 0 0 2px #10141a,inset 0 0 0 4px #838e9b,
             0 2px 5px rgba(0,0,0,.4)}

/* ------------------------------------------------------------- caption --- */
.jfoot{margin-top:11px;font-size:clamp(11.5px,.35vw + 10.2px,13.5px);
  letter-spacing:.13em;color:#8a7850;min-height:1.3em;line-height:1.35}
.jrow.arrived .jfoot{color:#2f7a45}

@media (max-width:620px){
  /* The carriage was a short tall box: 168x104, an aspect of 1.6 against the
     desktop design's 3.0, which is what made the train read as cramped and
     the coach as oversized next to the engine.

     The coach can only ever be (track - engine) wide — about 171px on a 375px
     phone — and that is fixed. So rather than shrink the engine, which would
     make the coach even more dominant, the carriage is made SHORTER: its
     chrome is trimmed to fixed small values instead of scaling off the
     engine, and the type is set tight. That pulls the coach-to-engine height
     ratio back to roughly the desktop 1.45 and the aspect up towards 2.0,
     with the whole carriage still on the platform. */
  .jc-door{display:none}
  /* The coach was (100vw - 208px), so it grew 1:1 with the screen while the
     engine stayed fixed — on a 430px phone that made it 222px and the train
     filled 99% of the track. Capped, it stops ballooning on wider handsets
     and leaves station visible around the train. */
  .jtrain{--th:54px}
  .jcoach{width:min(calc(100vw - 200px),170px);height:clamp(86px,21vw,112px)}
  .jc-body{gap:3px;padding-inline:4px}
  /* a real rectangle, not a slot: the width followed the flex box before, so
     the glass stretched to whatever was left over */
  .jc-win{width:auto;height:42%;aspect-ratio:.72;flex:0 0 auto}
  .jc-sign{flex:1 1 auto;padding:4px 5px}
  /* wrap rather than clip if a long time string outgrows the board */
  .jc-date,.jc-time{white-space:normal}

  /* carriage chrome at fixed small sizes, so the body keeps the height */
  .jc-roof{height:4px} .jc-cant,.jc-waist{height:2.5px}
  .jc-skirt{height:3px} .jc-under{height:12px}
  .jc-roof i{height:3px;top:-2.5px} .jc-bogie i{width:9px}

  .jc-sign b{font-size:clamp(18px,2.2vw + 9.7px,23px);line-height:1.05}
  .jc-date{font-size:clamp(14.5px,1.5vw + 8.9px,18px);line-height:1.12;letter-spacing:.02em}
  .jc-time{font-size:clamp(12.5px,1.3vw + 7.6px,16px);line-height:1.12;letter-spacing:-.01em}
  .jc-rule{margin-block:2.5px}
  .jfoot{letter-spacing:.08em}
  /* the train needs every pixel of track it can get on a phone, or there is
     nowhere left to travel once the engine and coach are on it */
  .jrow{padding:11px 8px 8px;border-radius:10px;
        margin-inline:calc(50% - 50vw + 8px)}
  .jline{gap:5px}
  .jsignal{width:26px}
  .jhead{margin-bottom:7px}
}
/* Below about 345px the coach is too short for the date to fit on one line,
   and an ellipsised date is worse than a smaller one. Reclaim the doors and
   tighten the tracking rather than truncate. */
/* Below about 360px there is genuinely not enough track for an engine, a
   coach and a 15px time on one line. Rather than clip the time — which would
   hide when the event starts — let it step down just on these widths. */
@media (max-width:360px){
  .jc-sign b{font-size:18.5px}
  .jc-date{font-size:14.5px}
  .jc-time{font-size:12.5px}
}

@media (prefers-reduced-motion:reduce){
  .jtrain{transition:transform .9s ease}
  .jrow.running .loco-svg{animation:none}
  .jrow.running .jsteam i{animation:none}
}
