/* Hook v2 (hook-v2.html). hook-v2.js adds .h-drive (1), .h-race (2), .h-police (3), .h-park (4), .h-penn (5), .h-title (6).
   The map is drawn in the hook's own view (assets/stage-hook.json) on assets/basemap-hook.png. Lines and pills use
   the laminate style: a white casing under the reason's color. */

.hook { background: #F2F3EF; }
.hook.instant *, .hook.instant *::before, .hook.instant *::after {
  animation-duration: 0s !important; animation-delay: 0s !important; transition-duration: 0s !important; transition-delay: 0s !important; }
.hook .h-lens { position: absolute; inset: 0; transform-origin: 0 0; }
#h-basemap { position: absolute; inset: 0; width: 1920px; height: 1080px; display: block; }
#h-basemap-missing { position: absolute; left: 40px; bottom: 40px; display: none; }
.hook.no-basemap #h-basemap { display: none; }
.hook.no-basemap #h-basemap-missing { display: block; }
.hook.no-basemap .h-lens { background:
  repeating-linear-gradient(0deg, transparent 0 59px, rgba(27, 36, 51, .05) 59px 60px),
  repeating-linear-gradient(90deg, transparent 0 59px, rgba(27, 36, 51, .05) 59px 60px), #F2F3EF; }

.h-map { position: absolute; inset: 0; width: 1920px; height: 1080px; overflow: visible; }
.h-map path { fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* ---- step 1: the drive ---- */
.h-drive-casing { stroke: #fff; stroke-width: 16; }
.h-drive-line { stroke: #2F6FED; stroke-width: 9; }
.h-drive-casing, .h-drive-line { stroke-dasharray: var(--len) var(--len); stroke-dashoffset: var(--len); }
/* hook.js draws the line and moves the dot along it; stepping back or past shows it whole. */
#h-dot { position: absolute; left: 0; top: 0; width: 0; height: 0; opacity: 0; transition: opacity .3s; }
#h-dot::before { content: ""; position: absolute; left: -13px; top: -13px; width: 26px; height: 26px; border-radius: 50%;
  background: #2F6FED; border: 4px solid #fff; box-sizing: border-box;
  box-shadow: 0 0 0 6px rgba(47, 111, 237, .25), 0 0 26px 10px rgba(47, 111, 237, .55); }
#h-dot::after { content: ""; position: absolute; left: -13px; top: -13px; width: 26px; height: 26px; border-radius: 50%;
  border: 3px solid #2F6FED; opacity: 0; }
.hook.h-drive #h-dot { opacity: 1; }
.hook.h-dot-rest #h-dot::after { animation: h-ping 1.6s ease-out infinite; }
@keyframes h-ping { from { opacity: .8; transform: scale(1); } to { opacity: 0; transform: scale(3.2); } }

/* ---- step 2: the race closures ---- */
#h-closures .c { stroke: #fff; stroke-width: 17; }
#h-closures .l { stroke: var(--event); stroke-width: 10; }
#h-closures { opacity: 0; transition: opacity .6s ease; }
.hook.h-race #h-closures { opacity: 1; transition-delay: .1s; }

/* ---- step 3: the notice's detour ---- */
.h-detour-casing { stroke: #fff; stroke-width: 15; }
.h-detour-line { stroke: var(--sign); stroke-width: 8; }
.h-detour-casing, .h-detour-line { stroke-dasharray: var(--len) var(--len); stroke-dashoffset: var(--len); }
/* hook.js draws it behind a second dot (the route the notice offered), the same way as the drive. */
/* Dashes laid over the drawn line, once it has drawn: a suggestion on paper, not a road state. */
.h-detour-dash { stroke: #fff; stroke-width: 3; stroke-dasharray: 2 14; opacity: 0; }
.hook.h-detour-done .h-detour-dash { opacity: .9; transition: opacity .4s ease; }

/* ---- labels: pills on a point (hook.js places them from data-lon/lat in the hook's view) ---- */
.hook .h-geo { position: absolute; width: 0; height: 0; z-index: 2; }
.hook .h-geo .pill { position: absolute; left: var(--dx, 0px); top: var(--dy, 0px); transform: translate(-50%, -50%) scale(.6);
  white-space: nowrap; font: 600 24px/1 var(--ui); color: #fff; background: var(--c); padding: 10px 18px 11px; border-radius: 999px;
  box-shadow: 0 0 0 3px #fff, var(--lift); opacity: 0; transition: opacity .3s, transform .45s cubic-bezier(.3, 1.5, .5, 1); }
.hook .h-geo .pill small { font-weight: 400; opacity: .88; margin-left: 9px; font-size: 21px; }
.hook .h-geo .lead { position: absolute; left: 0; top: 0; width: var(--lw, 0px); height: 3px; background: var(--c);
  transform-origin: 0 50%; transform: rotate(var(--la, 0deg)) scaleX(0); box-shadow: 0 0 0 1.5px #fff; transition: transform .35s ease; }
.hook .h-geo .tip { position: absolute; left: -7px; top: -7px; width: 14px; height: 14px; border-radius: 50%; background: var(--c);
  box-shadow: 0 0 0 3px #fff; opacity: 0; transition: opacity .3s; }
.hook .h-geo.on .pill { opacity: 1; transform: translate(-50%, -50%); }
.hook .h-geo.on .lead { transform: rotate(var(--la, 0deg)) scaleX(1); }
.hook .h-geo.on .tip { opacity: 1; }
.hook .h-geo.on .pill, .hook .h-geo.on .lead, .hook .h-geo.on .tip { transition-delay: var(--d, 0s); }

/* ---- the cards: date, the race, the notice ---- */
.hook .h-card { position: absolute; left: 72px; top: 64px; padding: 22px 30px 24px; background: var(--surface); border-radius: 20px;
  box-shadow: var(--high); display: flex; flex-direction: column; gap: 8px; opacity: 0; transform: translateY(-14px);
  transition: opacity .45s, transform .45s cubic-bezier(.2, .8, .3, 1); max-width: 620px; }
.hook .h-card .k { font: 600 21px/1 var(--ui); color: var(--muted); letter-spacing: .02em; text-transform: uppercase; }
.hook .h-card .v { font: 600 40px/1.1 var(--display); color: var(--ink); }
.hook .h-card .s { font: 400 22px/1.3 var(--ui); color: var(--muted); }
.hook .h-card .sw { display: inline-block; width: 30px; height: 8px; border-radius: 4px; vertical-align: middle; margin-right: 10px; }
#h-card-date { opacity: 1; transform: none; }
#h-card-race { top: 196px; }
#h-card-notice { top: 362px; }
.hook.h-race #h-card-race { opacity: 1; transform: none; transition-delay: .9s; }
.hook.h-detour #h-card-notice { opacity: 1; transform: none; transition-delay: .2s; }

/* ---- step 4: the title ---- */
#h-title { position: absolute; inset: 0; z-index: 9; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 22px; background: rgba(27, 36, 51, .62); opacity: 0; pointer-events: none; transition: opacity .8s ease; }
.hook.h-title #h-title { opacity: 1; }
#h-title .e-row { display: flex; align-items: center; gap: 44px; transform: scale(.94); transition: transform .7s cubic-bezier(.3, 1.3, .5, 1) .25s; }
.hook.h-title #h-title .e-row { transform: none; }
#h-title .e-mark { width: 260px; height: 260px; border-radius: 36px; display: block; object-fit: cover;
  box-shadow: 0 0 0 6px rgba(255, 255, 255, .92), var(--high); }
#h-title .e-sign { height: 220px; padding: 0 56px 17px; display: flex; align-items: center; justify-content: center;
  font: 700 170px/1 var(--display); letter-spacing: .06em; text-indent: .06em; color: #fff; background: var(--sign);
  border-radius: 22px; box-shadow: inset 0 0 0 10px var(--sign), inset 0 0 0 17px rgba(255, 255, 255, .92), var(--high); }
#h-title .e-name { font: 600 50px/1.2 var(--display); letter-spacing: .02em; color: #fff; margin-top: 14px; }
#h-title .e-stack { font: 400 28px/1.3 var(--ui); color: rgba(255, 255, 255, .82); }

/* ---- step 2: blocked at the end of the drive ---- */
.hook .h-blocked .x { position: absolute; left: -22px; top: -22px; width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center; background: var(--todo); color: #fff; font: 700 26px/1 var(--ui);
  box-shadow: 0 0 0 4px #fff, var(--lift); opacity: 0; transform: scale(.3); transition: opacity .25s, transform .4s cubic-bezier(.3, 1.6, .5, 1); }
.hook .h-blocked.on .x { opacity: 1; transform: none; transition-delay: .3s; }
.hook.h-race #h-dot::after { animation: none; }

/* ---- step 3: the construction on my street and parking past it (drawn only when the data has them) ---- */
#h-local .c { stroke: #fff; stroke-width: 15; }
#h-local .l { stroke: var(--construction); stroke-width: 8; }
#h-local { opacity: 0; transition: opacity .5s ease; }
.hook.h-detour #h-local { opacity: 1; transition-delay: 2.9s; }
.hook:not(.has-local) .h-local-label, .hook:not(.has-park) .h-park { display: none; }
.hook .h-park .p { position: absolute; left: -24px; top: -24px; width: 48px; height: 48px; border-radius: 12px; display: grid;
  place-items: center; background: var(--sign); color: #fff; font: 700 30px/1 var(--ui); box-shadow: 0 0 0 4px #fff, var(--lift);
  opacity: 0; transform: scale(.4); transition: opacity .3s, transform .45s cubic-bezier(.3, 1.5, .5, 1); }
.hook .h-park.on .p { opacity: 1; transform: none; transition-delay: var(--d, 0s); }

/* The cards sit on the right, clear of the river corridor. */
.hook .h-card { left: auto; right: 64px; }
#h-card-notice { gap: 12px; }
#h-card-notice .k { color: var(--sign); }
/* The date card gives way to the title. */
.hook.h-title #h-card-date, .hook.h-title #h-card-race, .hook.h-title #h-card-notice { opacity: 0; transition-delay: 0s; }

/* The second dot: green, for the route in the City notice. */
#h-dot2 { position: absolute; left: 0; top: 0; width: 0; height: 0; opacity: 0; transition: opacity .3s; }
#h-dot2::before { content: ""; position: absolute; left: -13px; top: -13px; width: 26px; height: 26px; border-radius: 50%;
  background: var(--sign); border: 4px solid #fff; box-sizing: border-box;
  box-shadow: 0 0 0 6px rgba(30, 91, 68, .25), 0 0 26px 10px rgba(14, 159, 110, .5); }
.hook.h-detour #h-dot2 { opacity: 1; }
.hook.h-detour-done #h-dot2 { opacity: 0; transition-delay: .6s; }
/* The blue dot dims once the green one takes over. */
.hook.h-detour #h-dot { opacity: .35; }

/* A live map in place of basemap-hook.png, until that image is rendered (needs the network when it runs). */
#h-live { position: absolute; inset: 0; width: 1920px; height: 1080px; display: none; }
.hook.live-map #h-live { display: block; }
.hook.live-map #h-basemap-missing .todo-live { display: inline; }
#h-basemap-missing .todo-live { display: none; }


/* ================= v2 ================= */
#h-card-race { top: 196px; }
#h-card-park { top: 196px; }
#h-card-penn { top: 196px; gap: 12px; }
#h-card-penn .k { color: var(--sign); }
.hook.h-police #h-card-race { opacity: 0; transition-delay: 0s; }
.hook.h-park #h-card-park { opacity: 1; transform: none; transition-delay: 1.2s; }
.hook.h-penn #h-card-park { opacity: 0; transition-delay: 0s; }
.hook.h-penn #h-card-penn { opacity: 1; transform: none; transition-delay: .3s; }
.hook.h-title #h-card-date, .hook.h-title #h-card-penn { opacity: 0; transition-delay: 0s; }

/* 3: the police detour: dashed, drawn behind the dot, and labeled as not the recorded route. */
#h-police path { fill: none; stroke-linecap: round; }
#h-police .c { stroke: #fff; stroke-width: 13; stroke-dasharray: var(--len) var(--len); stroke-dashoffset: var(--len); }
#h-police .l { stroke: #2F6FED; stroke-width: 6; stroke-dasharray: var(--len) var(--len); stroke-dashoffset: var(--len); opacity: .85; }
#h-police .d { stroke: #fff; stroke-width: 3; stroke-dasharray: 3 13; opacity: 0; }
.hook.h-police-done #h-police .d { opacity: 1; transition: opacity .3s; }

/* 4: my usual parking (P), under construction; where I parked (a radius). */
#h-local { opacity: 0; transition: opacity .5s ease; }
.hook.h-park #h-local { opacity: 1; transition-delay: .2s; }
.h-pk { position: absolute; width: 0; height: 0; z-index: 2; }
.h-pk .p { position: absolute; left: -22px; top: -22px; width: 44px; height: 44px; border-radius: 11px; display: grid; place-items: center;
  background: #2F6FED; color: #fff; font: 700 28px/1 var(--ui); box-shadow: 0 0 0 4px #fff, var(--lift); opacity: 0; transform: scale(.4);
  transition: opacity .3s, transform .45s cubic-bezier(.3, 1.5, .5, 1); }
.h-pk .p::after { content: ""; position: absolute; left: -6px; right: -6px; top: 50%; height: 5px; margin-top: -2.5px; background: var(--construction);
  border-radius: 3px; box-shadow: 0 0 0 2px #fff; transform: rotate(-35deg) scaleX(0); transition: transform .35s ease; }
.hook.h-park .h-pk .p { opacity: 1; transform: none; transition-delay: calc(.5s + var(--i) * .12s); }
.hook.h-park .h-pk .p::after { transform: rotate(-35deg) scaleX(1); transition-delay: calc(1s + var(--i) * .12s); }
#h-radius circle { fill: rgba(47, 111, 237, .14); stroke: #2F6FED; stroke-width: 4; stroke-dasharray: 10 8; }
#h-radius { opacity: 0; transform-box: fill-box; transition: opacity .5s ease; }
.hook.h-park #h-radius { opacity: 1; transition-delay: 1.5s; }

/* Placeholders until hook-personal.geojson exists: everything in it is drawn pink and marked TODO. */
.hook.placeholder #h-local .l { stroke: var(--todo); }
.hook.placeholder .h-pk .p { background: var(--todo); }
.hook.placeholder #h-radius circle { stroke: var(--todo); fill: rgba(214, 36, 110, .1); }
.hook.placeholder #h-local-label, .hook.placeholder #h-radius-label { --c: var(--todo) !important; }
#h-placeholder-note { display: none; }
.hook.placeholder #h-placeholder-note { display: block; position: absolute; left: 40px; bottom: 84px; }

/* 5: had I had PENN: everything on the map gets the app's yellow highlight. */
.h-hl { stroke: var(--hl); stroke-linecap: round; stroke-linejoin: round; fill: none; opacity: 0; transition: opacity .6s ease; }
.hook.h-penn .h-hl { opacity: .9; transition-delay: .6s; }
.hook.h-penn #h-dot, .hook.h-penn #h-blocked { opacity: 0; transition: opacity .4s; }

/* ---- v2 layout: one card at a time, bottom-right, clear of the drawn data ---- */
.hook .h-card { top: 64px !important; bottom: auto; right: 64px; left: auto; }
#h-card-date { opacity: 1; transform: none; }
.hook.h-race #h-card-date { opacity: 0; transform: translateY(-14px); transition-delay: 0s; }
.hook.h-race #h-card-race { opacity: 1; transform: none; transition-delay: .9s; }
.hook.h-park #h-card-race { opacity: 0; transition-delay: 0s; }
/* The construction near my spot. */
#h-local .c { stroke: #fff; stroke-width: 15; }
#h-local .l { stroke: var(--construction); stroke-width: 8; }
/* The green notice detour and its dot, on step 5. */
#h-dot2 { position: absolute; left: 0; top: 0; width: 0; height: 0; opacity: 0; transition: opacity .3s; z-index: 1; }
#h-dot2::before { content: ""; position: absolute; left: -13px; top: -13px; width: 26px; height: 26px; border-radius: 50%;
  background: var(--sign); border: 4px solid #fff; box-sizing: border-box; box-shadow: 0 0 0 6px rgba(30, 91, 68, .25), 0 0 26px 10px rgba(14, 159, 110, .5); }
.hook.h-penn #h-dot2 { opacity: 1; }
.hook.notice-done #h-dot2 { opacity: 0; transition-delay: .5s; }
.hook.notice-done .h-detour-dash { opacity: .9; transition: opacity .4s ease; }
#h-notice { opacity: 0; }
.hook.h-penn #h-notice { opacity: 1; }
/* The blue dot: hidden before the drive; it rides the police detour on step 3 and rests at my spot. */
#h-dot { z-index: 3; }
.hook.h-drive #h-dot { opacity: 1; }
.hook.h-penn #h-dot { opacity: 0; }
#h-police { opacity: 1; }
.hook.h-penn #h-police { opacity: .25; transition: opacity .5s; }

/* The dot hands over to the P marker once I reach my block. */
.hook.h-park #h-dot { opacity: 0; transition: opacity .4s ease .3s; }
