/* ============================================================================
   Blinda app.

   One spine. The trip is the interface.

   The traveller's day runs top to bottom as a single timeline. Committed events
   are quiet facts on a gutter rail. Openings (the free windows the parser found)
   are the lit thing on the page, and every suggestion lives inside the opening
   it fits rather than in a supplier bucket. Saving a suggestion does not move it
   to a sidebar: it snaps into the timeline as a real block, so the schedule
   becomes the itinerary as the traveller fills it.

   Visual language is carried over from landing.html, lightened for daily use:
   the deck's masks and letterforms on a bone-and-paper field, with a single
   accent that resolves through --brand so a client can make it theirs.
   Photography is never a rectangle in a card. It is cut by a torn-paper mask, a
   brush stroke, an aperture, or by the letterforms of the city's own name.
   ============================================================================ */

:root{
  /* ---- Brand -------------------------------------------------------------
     Three properties carry every accent in the app: the focus ring, the lit
     opening bands, the filled controls, the city cut out at the top. Nothing
     below hard-codes a hue, so a client rebrands the whole experience by
     overriding these and changing no rule at all.

       :root{ --brand:#0F62FE; --brand-lit:#5B96FF; --brand-dp:#0043CE; }

     --brand-dp is the darkened variant. --brand itself does not hold AA on
     paper, so anything set small uses the deep one instead. */
  --brand:      #F26722;
  --brand-lit:  #FF9552;
  --brand-dp:   #A93D0B;
  --brand-pale: #FFB273;
  --on-brand:   #24170F;   /* text sitting on a --brand fill */

  /* ---- Paper -------------------------------------------------------------
     A light room. Bone page, paper surfaces, white for the fields a traveller
     types into. The chrome carries no colour of its own, which is precisely
     what leaves room for the client's. */
  --bone:   #F2EFE9;
  --bone-2: #E3DED3;
  --bone-3: #D5CEC0;
  --paper:  #FBF9F6;
  --white:  #FFFFFF;

  /* ---- Ink ---------------------------------------------------------------
     Warm neutral rather than navy. A blue-grey text stack tints every surface
     it touches and quietly fights any brand colour that is not itself blue.
     Never pure black. */
  --ink:     #23211E;
  --ink-2:   #3C3833;
  --ink-3:   #565049;
  --slate:   #5C564D;
  --slate-2: #6B6459;
  --slate-3: #7C7568;
  --bad:     #B3261E;   /* the only other hue in the app */

  /* Event types. Desaturated so a full day of blocks never turns into bunting,
     and held apart from --brand so a classification never reads as an accent. */
  --t-travel:     #8C8579;
  --t-conference: #55605E;
  --t-client:     #A0644A;
  --t-dinner:     #8A5A3B;
  --t-hotel:      #6B6459;
  --t-meeting:    #5E5A6B;

  --rail: 76px;
  --gutter: 64px;          /* time column inside a day */
  --ease: cubic-bezier(.22,.68,.28,1);

  /* The two masks, lifted from the landing deck. Same paths mean the family
     resemblance is structural rather than approximate. */
  --torn: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpath fill='%23fff' d='M0,6 C14,1 26,9 40,5 C56,0 72,8 88,3 C96,1 100,4 100,11 L100,90 C100,96 95,99 87,97 C70,92 55,99 39,96 C25,93 12,99 4,96 C1,95 0,92 0,87 Z'/%3E%3C/svg%3E");
  --brush: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpath fill='%23fff' d='M5.4,9.1C20,1.6,37,7.4,54,3.9c13-2.7,29,1.2,38.6,7.9c4.6,3.2,4.3,12.4,4.8,22.6c0.7,14.4-1.7,29.6-0.4,41.9c1.1,10.7-6.9,18.5-20.6,20.6c-17.9,2.7-38.4-2.6-55.9,0.4C9.6,98.9,3,93.4,2.4,81.6C1.6,66.2,4.1,49.2,2.7,33.1C1.9,23.6,1.4,11.2,5.4,9.1z'/%3E%3C/svg%3E");
}

*{margin:0;padding:0;box-sizing:border-box}

html{background:var(--bone);scroll-behavior:smooth}

body{
  font-family:'Lexend',system-ui,-apple-system,sans-serif;
  background:var(--bone);
  color:var(--ink);
  font-size:14px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  min-height:100dvh;
}

img{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
a{color:inherit;text-decoration:none}
input,textarea{font:inherit}

/* Focus is restyled, never removed. The app is keyboard navigable end to end:
   the rail, the ribbon, every card and every save control. */
:focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:2px}

::selection{background:color-mix(in srgb,var(--brand) 22%,transparent)}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---------- Type ---------- */

.serif{font-family:'Instrument Serif',Georgia,serif;font-weight:400;letter-spacing:-.012em}
.display{font-family:'Archivo Black',Impact,sans-serif;font-weight:400;letter-spacing:-.03em;text-transform:uppercase;line-height:.86}

/* Small tracked label, for functional group headings only. */
.label{font-size:10px;letter-spacing:.2em;text-transform:uppercase;font-weight:500;color:var(--slate-3)}

.ph{line-height:1;vertical-align:-.1em}

/* ---------- Motion ----------
   Everything reveals per day rather than per page: an observer flags a day as it
   arrives, its children rise, the fit bars draw, the aperture opens. Return to a
   day and it plays again. */
.rise{opacity:0;transform:translateY(16px);transition:opacity .7s var(--ease),transform .8s var(--ease)}
.is-in .rise{opacity:1;transform:none}
.is-in .rise.s1{transition-delay:.06s}
.is-in .rise.s2{transition-delay:.12s}
.is-in .rise.s3{transition-delay:.18s}
.is-in .rise.s4{transition-delay:.24s}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;scroll-behavior:auto !important;
  }
  .rise{opacity:1;transform:none}
}

/* ============================================================================
   LOGIN
   ============================================================================ */

.login-screen{
  position:fixed;inset:0;z-index:9999;
  display:grid;place-items:center;padding:24px;
  background:var(--bone);
  transition:opacity .35s var(--ease);
}
.login-screen.is-gone{opacity:0;pointer-events:none}

.login-card{
  width:min(356px,100%);text-align:center;
  background:var(--paper);border:1px solid var(--bone-2);
  padding:36px 30px 32px;box-shadow:0 18px 50px rgba(35,33,30,.07);
}
/* The wordmark ships on an opaque white ground, which on a light page would
   read as a box drawn around it. Multiplying against the paper drops the white
   and leaves the mark's own colours alone, so the asset is never altered and a
   client's logo drops in the same way. */
.login-logo{width:184px;height:auto;margin:0 auto 20px;mix-blend-mode:multiply}
.login-sub{font-size:13px;color:var(--slate-2);margin-bottom:24px}
.login-form{display:grid;gap:10px}

.login-input{
  width:100%;padding:12px 14px;border-radius:2px;font-size:14px;color:var(--ink);
  background:var(--white);border:1px solid var(--bone-3);
  transition:border-color .2s,box-shadow .2s;
}
.login-input::placeholder{color:var(--slate-3)}
.login-input:focus{
  outline:none;border-color:var(--brand);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 15%,transparent);
}

.login-error{font-size:12px;color:var(--bad);min-height:17px;text-align:left}

.login-btn{
  padding:13px;background:var(--brand);color:var(--on-brand);font-weight:500;
  border-radius:100px;letter-spacing:.01em;
  box-shadow:0 6px 24px color-mix(in srgb,var(--brand) 28%,transparent);
  transition:transform .22s var(--ease),box-shadow .28s;
}
.login-btn:hover{
  transform:translateY(-2px);
  box-shadow:0 12px 34px color-mix(in srgb,var(--brand) 40%,transparent);
}

/* ============================================================================
   WELCOME
   The itinerary is the input. One field, one action, nothing to configure.
   ============================================================================ */

.welcome{
  position:fixed;inset:0;z-index:900;overflow-y:auto;
  background:var(--bone);
  display:grid;place-items:start center;padding:48px 24px;
  transition:opacity .5s var(--ease);
}
.welcome.is-gone{opacity:0;pointer-events:none}

/* A photograph under the copy, washed out by a paper scrim so it reads as
   ground rather than as a picture. The deck holds its hero down with midnight;
   the app holds it down with daylight, which is the whole difference between
   something you look at once and something you work in. */
.welcome-bed{position:absolute;inset:0;overflow:hidden}
.welcome-bed img{
  width:100%;height:100%;object-fit:cover;object-position:56% 44%;
  opacity:0;transform:scale(1.1);filter:saturate(.86);
  transition:transform 14s var(--ease),opacity 1.4s ease;
}
.welcome-bed img.is-loaded{opacity:1;transform:scale(1)}
.welcome-scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(100deg,rgba(242,239,233,.96) 0%,rgba(242,239,233,.9) 40%,rgba(242,239,233,.44) 100%),
    linear-gradient(0deg,rgba(242,239,233,.94) 0%,rgba(242,239,233,0) 54%);
}

.welcome-inner{position:relative;width:min(680px,100%);margin-block:auto}
.welcome-logo{width:158px;height:auto;margin-bottom:28px;mix-blend-mode:multiply}
.welcome-h{
  font-family:'Instrument Serif',Georgia,serif;
  font-size:clamp(34px,5.2vw,58px);line-height:1.04;letter-spacing:-.015em;
  color:var(--ink);margin-bottom:14px;max-width:17ch;
}
.welcome-h i{font-style:italic;color:var(--brand-dp)}
.welcome-sub{font-size:15px;font-weight:300;color:var(--slate);max-width:52ch;margin-bottom:28px}

.welcome-form{display:grid;gap:12px}
.welcome-name,.welcome-ta{
  width:100%;padding:14px 16px;border-radius:2px;font-size:14px;color:var(--ink);
  background:var(--white);border:1px solid var(--bone-3);
  transition:border-color .2s,box-shadow .2s,background .2s;
}
.welcome-ta{min-height:190px;resize:vertical;line-height:1.65}
.welcome-name::placeholder,.welcome-ta::placeholder{color:var(--slate-3)}
.welcome-name:focus,.welcome-ta:focus{
  outline:none;border-color:var(--brand);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 15%,transparent);
}
.welcome-ta.is-dropping{border-color:var(--brand);background:color-mix(in srgb,var(--brand) 8%,transparent)}

.welcome-row{display:flex;align-items:center;justify-content:space-between;gap:18px;flex-wrap:wrap;margin-top:4px}
.welcome-import{
  display:inline-flex;align-items:center;gap:8px;font-size:13px;color:var(--slate);
  border-bottom:1px solid var(--bone-3);padding-bottom:3px;
  transition:color .2s,border-color .2s;
}
.welcome-import:hover{color:var(--brand-dp);border-color:var(--brand)}
.welcome-import[disabled]{opacity:.5;cursor:default}
.welcome-note{font-size:12px;color:var(--slate-2);flex:1 1 100%;min-height:17px}
.welcome-note.is-ok{color:var(--brand-dp)}
.welcome-note.is-error{color:var(--bad)}

.welcome-go{
  display:inline-flex;align-items:center;gap:10px;
  padding:15px 30px;border-radius:100px;font-size:15px;font-weight:500;
  background:var(--brand);color:var(--on-brand);
  box-shadow:0 6px 26px color-mix(in srgb,var(--brand) 30%,transparent);
  transition:transform .22s var(--ease),box-shadow .28s,opacity .2s;
}
.welcome-go:hover{transform:translateY(-2px);box-shadow:0 12px 40px color-mix(in srgb,var(--brand) 46%,transparent)}
.welcome-go[disabled]{opacity:.55;transform:none;cursor:default;box-shadow:none}
.welcome-go .ph{transition:transform .3s var(--ease)}
.welcome-go:hover:not([disabled]) .ph{transform:translateX(4px)}

.welcome-error{margin-top:16px;font-size:13px;color:var(--bad);min-height:18px}

/* Reading the itinerary. Steps are named for the work actually happening, so
   the wait describes itself instead of spinning anonymously. */
.welcome-work{display:none;flex-direction:column;gap:15px;align-items:flex-start}
.welcome-work.is-on{display:flex}
.work-step{
  display:flex;align-items:center;gap:13px;font-size:14px;
  color:var(--slate-3);opacity:0;transform:translateY(8px);
  transition:opacity .5s var(--ease),transform .5s var(--ease),color .4s;
}
.work-step.is-shown{opacity:1;transform:none}
.work-step.is-active{color:var(--ink)}
.work-step.is-done{color:var(--slate)}
.work-step-icon{width:16px;display:grid;place-items:center;color:var(--brand);font-size:16px}

.spinner{
  width:15px;height:15px;flex:none;border-radius:50%;
  border:1.5px solid color-mix(in srgb,var(--brand) 26%,transparent);border-top-color:var(--brand);
  animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* ============================================================================
   GATE
   The pause between reading the trip and showing it.

   The suppliers are already working behind this screen, so the wait is spent
   on the one thing we can show immediately: what the schedule said about the
   person who wrote it. Marking a chip is a real act with a real record, and
   the sources report their own progress at the foot rather than hiding it
   behind a spinner that says nothing.
   ============================================================================ */

.gate{
  position:fixed;inset:0;z-index:920;overflow-y:auto;
  background:var(--bone);
  display:grid;place-items:start center;padding:40px 24px;
  opacity:0;pointer-events:none;
  transition:opacity .5s var(--ease);
}
.gate.is-on{opacity:1;pointer-events:auto}
.gate.is-gone{opacity:0;pointer-events:none}

.gate-bed{position:absolute;inset:0;overflow:hidden}
.gate-bed img{
  width:100%;height:100%;object-fit:cover;object-position:center 44%;
  opacity:0;transform:scale(1.08);filter:saturate(.9);
  transition:opacity 1.4s ease,transform 16s var(--ease);
}
.gate-bed img.is-loaded{opacity:1;transform:scale(1)}
.gate-scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(180deg,rgba(242,239,233,.62) 0%,rgba(242,239,233,.2) 46%,rgba(242,239,233,.6) 100%),
    linear-gradient(96deg,rgba(242,239,233,.34) 0%,rgba(242,239,233,0) 100%);
}

.gate-inner{position:relative;width:min(760px,100%);margin-block:auto}

.gate-card{
  background:var(--paper);border:1px solid var(--bone-2);
  box-shadow:0 30px 80px rgba(35,33,30,.10);
  padding:34px 38px 30px;
}

.gate-top{display:flex;align-items:center;gap:16px;margin-bottom:20px}
.gate-av{
  width:54px;height:54px;flex:none;border-radius:50%;display:grid;place-items:center;
  background:var(--brand);color:var(--on-brand);
  font-size:16px;font-weight:500;letter-spacing:.04em;
}
.gate-who{min-width:0}
.gate-name{font-family:'Instrument Serif',Georgia,serif;font-size:clamp(26px,3.4vw,34px);line-height:1.12;letter-spacing:-.012em}
.gate-ctx{font-size:13px;color:var(--slate-2);margin-top:2px}

/* The trip, read back in one sentence, before anything is asked of anybody. */
.gate-read{
  font-family:'Instrument Serif',Georgia,serif;
  font-size:clamp(17px,1.9vw,22px);line-height:1.4;letter-spacing:-.008em;
  color:var(--ink);max-width:52ch;
  padding-bottom:22px;border-bottom:1px solid var(--bone-2);
}
.gate-read i{font-style:italic;color:var(--brand-dp)}

.gate-sec{display:grid;gap:11px;padding-top:22px;margin-top:22px;border-top:1px solid var(--bone-2)}
.gate-sec:first-of-type{border-top:none;margin-top:0}
.gate-sec-head{display:flex;align-items:baseline;justify-content:space-between;gap:14px}
.gate-marked{font-size:11.5px;color:var(--brand-dp);font-variant-numeric:tabular-nums;white-space:nowrap;flex:none}
.gate-hint{font-size:12.5px;color:var(--slate-2);max-width:62ch;margin-top:-3px}
.gate-lede{font-size:14px;line-height:1.65;color:var(--slate);max-width:64ch}
.gate-lede b{font-weight:500;color:var(--ink)}

.gate-chips{display:flex;flex-wrap:wrap;gap:8px}

/* A chip is a control, not a label. It says what we think, and pressing it
   says whether we were right. */
.chip{
  display:inline-flex;align-items:center;gap:0;text-align:left;
  font-size:12.5px;color:var(--slate);
  border:1px solid var(--bone-3);border-radius:100px;padding:6px 14px;
  transition:border-color .2s,color .2s,background .2s,gap .2s,padding .2s;
}
.chip .ph{font-size:13px;width:0;overflow:hidden;opacity:0;transition:width .2s var(--ease),opacity .2s}
.chip:hover{border-color:var(--brand);color:var(--brand-dp)}
.chip.is-on{
  border-color:var(--brand);color:var(--brand-dp);
  background:color-mix(in srgb,var(--brand) 10%,transparent);
  gap:6px;padding-left:11px;
}
.chip.is-on .ph{width:13px;opacity:1}

.gate-foot{margin-top:26px;padding-top:20px;border-top:1px solid var(--bone-2);display:grid;gap:18px}

/* Each source reports itself. A traveller waiting on three suppliers should be
   able to see which one is slow, not just that something is. */
.gate-prog{list-style:none;display:grid;gap:9px}
.gate-prog li{display:flex;align-items:center;gap:11px;font-size:13px;color:var(--slate-2)}
.gate-prog-mark{width:28px;height:17px;flex:none;display:grid;place-items:center}
.gate-prog-mark img{max-width:28px;max-height:17px;object-fit:contain;mix-blend-mode:multiply}
.gate-prog-label{flex:1;min-width:0}
.gate-prog-state{display:inline-flex;align-items:center;gap:7px;font-size:12px;flex:none}
.gate-prog li.is-done .gate-prog-label{color:var(--ink)}
.gate-prog li.is-done .gate-prog-state{color:var(--brand-dp)}
.gate-prog li.is-error .gate-prog-state{color:var(--bad)}

.gate-go-row{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.gate-count{font-size:12.5px;color:var(--slate-2)}
.gate-count b{font-weight:500;color:var(--ink)}
.gate-go{padding:13px 26px;font-size:14px}
.gate-go .ph{transition:transform .3s var(--ease)}
.gate-go:hover .ph{transform:translateX(4px)}

/* ============================================================================
   RAIL
   Day navigation, brand and traveller. The deck's rail, doing real work: it is
   the only persistent chrome, so the page itself never carries a second nav.
   Paper rather than a dark slab, because a full-height band of colour down the
   left is the heaviest thing an interface can own, and it is not the rail's
   job to be the heaviest thing here. The days are.
   ============================================================================ */

.rail{
  position:fixed;left:0;top:0;bottom:0;width:var(--rail);z-index:60;
  display:flex;flex-direction:column;align-items:center;
  padding:18px 0 16px;
  background:var(--paper);border-right:1px solid var(--bone-2);
}
.rail-logo{height:28px;width:28px;flex:none;object-fit:contain;mix-blend-mode:multiply}

.rail-days{
  flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  width:100%;padding:20px 0;scrollbar-width:none;
}
.rail-days::-webkit-scrollbar{display:none}

.rail-day{
  position:relative;width:100%;padding:7px 0;flex:none;
  display:grid;place-items:center;gap:3px;
  color:var(--slate-3);transition:color .3s var(--ease);
}
.rail-day:hover{color:var(--ink)}
.rail-day.is-current{color:var(--ink)}
.rail-day-d{font-size:9.5px;letter-spacing:.14em;text-transform:uppercase}
.rail-day-n{font-family:'Archivo Black',sans-serif;font-size:14px;letter-spacing:-.02em;line-height:1}

/* The mark on the left edge widens for the day in view. */
.rail-day::before{
  content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:2px;height:16px;background:var(--bone-3);
  transition:height .35s var(--ease),background .35s,width .35s;
}
.rail-day:hover::before{background:var(--brand-lit);height:24px}
.rail-day.is-current::before{background:var(--brand);height:30px;width:3px}

/* A dot when the day has openings still unfilled: real state, not decoration. */
.rail-day-open{
  width:4px;height:4px;border-radius:50%;background:var(--brand);
  opacity:0;transition:opacity .3s;
}
.rail-day.has-open .rail-day-open{opacity:1}

.rail-me{
  flex:none;width:38px;height:38px;border-radius:50%;
  display:grid;place-items:center;
  background:var(--bone);border:1px solid var(--bone-3);
  color:var(--slate);font-size:12px;font-weight:500;letter-spacing:.04em;
  transition:border-color .25s,background .25s,color .25s;
}
.rail-me:hover{
  border-color:var(--brand);color:var(--brand-dp);
  background:color-mix(in srgb,var(--brand) 12%,transparent);
}

/* ============================================================================
   TOP BAR
   Slim, and only what the traveller cannot get from the page: where they are,
   and the two things they can do to the whole trip.
   ============================================================================ */

.topbar{
  position:sticky;top:0;z-index:50;
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  height:58px;padding:0 34px;
  background:rgba(242,239,233,.86);backdrop-filter:blur(12px);
  border-bottom:1px solid transparent;
  transition:border-color .3s,box-shadow .3s;
}
.topbar.is-stuck{border-bottom-color:var(--bone-2);box-shadow:0 6px 24px rgba(35,33,30,.05)}

.topbar-where{display:flex;align-items:baseline;gap:12px;min-width:0}
.topbar-city{
  font-family:'Instrument Serif',Georgia,serif;font-size:21px;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.topbar-dates{font-size:12px;color:var(--slate-2);white-space:nowrap}

.topbar-acts{display:flex;align-items:center;gap:8px;flex:none}

.btn{
  display:inline-flex;align-items:center;gap:8px;
  padding:9px 17px;border-radius:100px;font-size:13px;white-space:nowrap;
  transition:transform .2s var(--ease),background .2s,border-color .2s,color .2s,box-shadow .26s,opacity .2s;
}
.btn .ph{font-size:15px}
.btn-line{border:1px solid var(--bone-3);color:var(--slate)}
.btn-line:hover{border-color:var(--brand-dp);color:var(--brand-dp)}
.btn-line.is-on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.btn-solid{background:var(--ink);color:var(--paper)}
.btn-solid:hover{transform:translateY(-1px);box-shadow:0 10px 26px rgba(35,33,30,.22)}
.btn-brand{background:var(--brand);color:var(--on-brand);font-weight:500;box-shadow:0 4px 18px color-mix(in srgb,var(--brand) 28%,transparent)}
.btn-brand:hover{transform:translateY(-1px);box-shadow:0 10px 30px color-mix(in srgb,var(--brand) 44%,transparent)}
.btn[disabled]{opacity:.5;cursor:default;transform:none;box-shadow:none}
.btn-count{
  min-width:19px;height:19px;padding:0 5px;border-radius:100px;
  display:inline-grid;place-items:center;
  background:var(--brand);color:var(--on-brand);font-size:11px;font-weight:500;
}
.btn-solid .btn-count{background:var(--brand);color:var(--on-brand)}

/* ============================================================================
   STAGE
   ============================================================================ */

.stage{margin-left:var(--rail);min-height:100dvh;display:none}
.stage.is-on{display:block}

.wrap{width:100%;max-width:1080px;margin:0 auto;padding:0 34px}

/* ============================================================================
   TRIP HEAD
   The city's name cut out of a photograph of it, and one sentence reading the
   trip back to the traveller so the parse is visible rather than implied.
   ============================================================================ */

.triphead{position:relative;padding:28px 0 0;overflow:hidden}

.cutwrap{position:relative;overflow:hidden;padding-bottom:6px}
/* background-clip:text turns the letterforms into a window on to the
   destination. The photograph is blended over the brand gradient rather than
   used alone: a cut-out only reads as a window if what shows through is
   brighter than the paper around it, and the gradient guarantees that
   regardless of which photo loads. */
.cutword{
  display:block;white-space:nowrap;line-height:.82;
  font-family:'Archivo Black',Impact,sans-serif;font-weight:400;
  text-transform:uppercase;letter-spacing:-.072em;word-spacing:.08em;
  font-size:clamp(56px,13.5vw,168px);
  color:transparent;-webkit-background-clip:text;background-clip:text;
  background-image:linear-gradient(102deg,var(--brand) 0%,var(--brand-lit) 46%,var(--brand-pale) 100%);
  background-size:cover;background-position:center 46%;
  filter:saturate(1.04) brightness(1.04);
  transition:opacity .9s var(--ease),transform 1s var(--ease);
  opacity:0;transform:translateY(20px);
}
.cutword.is-in{opacity:1;transform:none}
.cutword.has-photo{
  background-image:var(--photo),linear-gradient(102deg,var(--brand) 0%,var(--brand-lit) 46%,var(--brand-pale) 100%);
  background-size:cover,100% 100%;
  background-position:center 46%,center;
  background-blend-mode:soft-light;
  filter:saturate(1.06) brightness(1.12);
}

.readback{
  display:grid;gap:16px;padding:20px 0 30px;
  border-bottom:1px solid var(--bone-2);
}
.readback-line{
  font-family:'Instrument Serif',Georgia,serif;
  font-size:clamp(19px,2.1vw,27px);line-height:1.34;letter-spacing:-.01em;
  max-width:40ch;color:var(--ink);
}
.readback-line i{font-style:italic;color:var(--brand-dp)}
.readback-tags{display:flex;flex-wrap:wrap;gap:7px}
.tag{
  font-size:11.5px;color:var(--slate);
  border:1px solid var(--bone-3);border-radius:100px;padding:5px 12px;
  transition:border-color .2s,color .2s;
}
.tag-dim{color:var(--slate-3)}
.tag-live{border-color:color-mix(in srgb,var(--brand) 42%,transparent);color:var(--brand-dp)}

/* ---------- Ribbon ----------
   The whole trip in one look. Each day is a column of real proportions:
   committed time as ticks, openings in the brand colour, at real duration.
   This answers "when am I free" before the traveller has scrolled anywhere. */

.ribbon{padding:26px 0 30px;border-bottom:1px solid var(--bone-2)}
.ribbon-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin-bottom:16px}
.ribbon-sum{font-size:13px;color:var(--slate-2)}
.ribbon-sum b{color:var(--brand-dp);font-weight:400}

.ribbon-days{display:grid;gap:10px;grid-auto-flow:column;grid-auto-columns:1fr}

.rday{
  display:grid;gap:9px;text-align:left;padding:0;
  transition:opacity .25s;
}
.rday:hover{opacity:1}
.ribbon-days:hover .rday:not(:hover){opacity:.62}

.rday-top{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.rday-d{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--slate-3)}
.rday-n{font-family:'Instrument Serif',Georgia,serif;font-size:19px;line-height:1}

/* The bar spans the day's waking hours (07:00 to 23:00) so two days can be
   compared by eye without reading a number.

   Nothing on it is invented. A brand band is a window the parser measured and
   gave real start and end times for. An ink tick is the moment something
   committed begins: the parse carries no end times for events, so drawing them
   as blocks of guessed length would be a lie told in a nice colour. */
.rday-bar{position:relative;display:block;height:64px;width:100%;background:var(--bone-2);overflow:hidden}

/* Left-anchored, not full width: a rule spanning the bar reads as a divider and
   turns a fully committed day into something that looks like an empty table. */
.rday-tick{position:absolute;left:0;width:46%;height:2px;background:var(--ink-2);opacity:.5}

.rday-band{
  position:absolute;left:0;right:0;background:var(--brand);
  transform:scaleY(0);transform-origin:top;
  transition:transform .7s var(--ease),background .3s;
}
.is-in .rday-band{transform:scaleY(1)}
/* Hatched once something has been added into that window. */
.rday-band.is-filled{background:repeating-linear-gradient(135deg,var(--brand) 0 3px,var(--brand-lit) 3px 6px)}

.rday-foot{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--slate-2);flex-wrap:wrap}
.rday-free{color:var(--brand-dp)}

/* ============================================================================
   SPINE
   ============================================================================ */

.spine{padding:0 0 60px}

.day{padding:44px 0 10px;scroll-margin-top:72px}
.day + .day{border-top:1px solid var(--bone-2)}

/* ---------- Day head ----------
   A brush stroke of photography behind the date. A different frame per day, so
   the trip reads as a journey instead of a list of headings.

   The stroke is deliberately bigger than the heading that sits on it. It runs
   past the head on three sides and carries on down behind the first hours of
   the timeline, so the day reads as one thing photographed rather than as a
   band of picture with a list bolted underneath it. .day-bed is the clip, not
   .day-head, which is what lets it break out while still being contained. */
.day-head{position:relative;min-height:148px;display:flex;align-items:flex-end;padding:22px 0 20px}

.day-bed{
  position:absolute;top:-16px;right:-26px;bottom:-58px;left:0;
  z-index:0;pointer-events:none;overflow:hidden;
}
.day-bed img{
  width:100%;height:100%;object-fit:cover;object-position:center 42%;
  -webkit-mask-image:var(--brush);mask-image:var(--brush);
  -webkit-mask-size:78% 100%;mask-size:78% 100%;
  -webkit-mask-position:right center;mask-position:right center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  opacity:0;transform:scale(1.07);
  transition:opacity 1.3s ease,transform 11s var(--ease);
}
.day-bed img.is-loaded{opacity:.82;transform:scale(1)}
/* Two washes, each doing one job. Across, the copy side stays solid paper and
   lets go early, so the far end of the stroke keeps its actual photograph
   instead of a tint of one. Up, the tail dissolves into the page before it
   reaches the times and event names it passes behind. */
.day-bed::after{
  content:"";position:absolute;inset:0;
  background:
    linear-gradient(94deg,var(--bone) 0%,var(--bone) 24%,rgba(242,239,233,.66) 44%,rgba(242,239,233,.16) 74%,rgba(242,239,233,0) 100%),
    linear-gradient(0deg,var(--bone) 4%,rgba(242,239,233,.72) 22%,rgba(242,239,233,0) 46%);
}

.day-head-inner{position:relative;z-index:1;display:grid;gap:9px}
.day-when{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap}
.day-name{font-family:'Instrument Serif',Georgia,serif;font-size:clamp(32px,4.2vw,50px);line-height:1;letter-spacing:-.015em}
.day-date{font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--slate-2)}
.day-facts{display:flex;align-items:center;gap:16px;flex-wrap:wrap;font-size:13px;color:var(--slate)}
.day-fact{display:inline-flex;align-items:center;gap:7px}
.day-fact .ph{font-size:15px;color:var(--slate-3)}
.day-fact.is-open{color:var(--brand-dp)}
.day-fact.is-open .ph{color:var(--brand)}

/* ---------- Blocks ----------
   The gutter rail runs the height of the day. Committed events hang off it and
   stay quiet: they are facts, not decisions. */

.day-body{position:relative;padding:14px 0 0 var(--gutter)}
.day-body::before{
  content:"";position:absolute;left:calc(var(--gutter) - 21px);top:0;bottom:18px;
  width:1px;background:var(--bone-2);
}

.block{position:relative;display:grid;gap:2px;padding:11px 0 11px 18px;margin-bottom:2px}
.block::before{
  content:"";position:absolute;left:-21px;top:19px;
  width:7px;height:7px;border-radius:50%;
  background:var(--bone);border:1.5px solid var(--type,var(--slate-3));
  transform:translateX(-3px);
}
.block-time{
  position:absolute;left:calc(-1 * var(--gutter));top:11px;width:calc(var(--gutter) - 26px);
  text-align:right;font-size:11.5px;color:var(--slate-3);letter-spacing:.02em;
  font-variant-numeric:tabular-nums;
}
.block-name{font-size:14px;color:var(--slate);font-weight:400}
.block-loc{font-size:12px;color:var(--slate-3)}

.block.type-travel{--type:var(--t-travel)}
.block.type-conference{--type:var(--t-conference)}
.block.type-client{--type:var(--t-client)}
.block.type-dinner{--type:var(--t-dinner)}
.block.type-hotel{--type:var(--t-hotel)}
.block.type-meeting{--type:var(--t-meeting)}

/* A saved suggestion, now a real part of the day. This is the payoff: the
   schedule became the itinerary in place, with no second panel to reconcile. */
.block-added{
  --type:var(--brand);
  background:var(--paper);border:1px solid color-mix(in srgb,var(--brand) 30%,transparent);
  border-left:2px solid var(--brand);
  padding:13px 44px 13px 16px;margin:6px 0 8px;
  animation:snapIn .5s var(--ease);
}
@keyframes snapIn{
  from{opacity:0;transform:translateY(-6px) scaleY(.9);transform-origin:top}
  to{opacity:1;transform:none}
}
.block-added::before{background:var(--brand);border-color:var(--brand)}
.block-added .block-name{color:var(--ink);font-weight:500}
.block-added-src{
  display:inline-flex;align-items:center;gap:6px;margin-top:5px;
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--brand-dp);
}
.block-drop{
  position:absolute;right:12px;top:12px;
  width:26px;height:26px;display:grid;place-items:center;border-radius:50%;
  color:var(--slate-3);transition:color .2s,background .2s;
}
.block-drop:hover{color:var(--brand-dp);background:color-mix(in srgb,var(--brand) 10%,transparent)}

/* ============================================================================
   OPENING
   The one lit thing on the page.
   ============================================================================ */

.opening{
  position:relative;margin:20px 0 26px -18px;
  background:var(--paper);
  border:1px solid var(--bone-2);border-left:2px solid var(--brand);
  padding:20px 22px 22px;
}
.opening::before{
  content:"";position:absolute;left:-24px;top:26px;
  width:9px;height:9px;border-radius:50%;background:var(--brand);
  box-shadow:0 0 0 4px color-mix(in srgb,var(--brand) 16%,transparent);
}

.opening-head{display:grid;gap:10px;padding-bottom:16px;border-bottom:1px solid var(--bone-2)}
.opening-when{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.opening-win{
  font-family:'Archivo Black',sans-serif;font-size:17px;letter-spacing:-.02em;
  color:var(--ink);font-variant-numeric:tabular-nums;
}
.opening-dur{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--brand-dp)}
.opening-left{font-size:12px;color:var(--slate-2)}

.opening-ctx{font-size:13px;color:var(--slate);max-width:64ch}
.opening-ctx b{font-weight:400;color:var(--ink)}

.opening-chips{display:flex;gap:8px;flex-wrap:wrap}
.chip{
  display:inline-flex;align-items:center;gap:6px;
  font-size:11.5px;color:var(--slate-2);
  border:1px solid var(--bone-2);border-radius:100px;padding:4px 11px;
}
.chip .ph{font-size:13px;color:var(--slate-3)}
.chip.is-warn{border-color:rgba(169,61,11,.34);color:var(--brand-dp)}
.chip.is-warn .ph{color:var(--brand-dp)}

.opening-body{padding-top:18px;display:grid;gap:22px}

/* ---------- Lanes ----------
   Suppliers still group the shortlist, but quietly: a hairline, a small label
   and the supplier's own mark. The traveller reads the day, not the plumbing.
   The mark stays because the commercial relationship requires attribution. */

.lane{display:grid;gap:14px}
.lane-head{
  display:flex;align-items:center;gap:12px;
  padding-bottom:9px;border-bottom:1px solid var(--bone-2);
}
.lane-label{font-size:10px;letter-spacing:.2em;text-transform:uppercase;font-weight:500;color:var(--slate-3);flex:none}
.lane-rule{flex:1;height:1px}
.lane-mark{display:flex;align-items:center;gap:7px;flex:none}
.lane-mark img{height:13px;width:auto;opacity:.62;transition:opacity .25s}
.lane:hover .lane-mark img{opacity:.9}
.lane-mark-txt{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--slate-3)}

.lane-cards{display:grid;gap:12px}

.lane-more{
  justify-self:start;display:inline-flex;align-items:center;gap:7px;
  font-size:12px;color:var(--slate-2);padding:5px 0;
  border-bottom:1px solid var(--bone-3);transition:color .2s,border-color .2s;
}
.lane-more:hover{color:var(--brand-dp);border-color:var(--brand-dp)}

/* ---------- Card ---------- */

.card{
  position:relative;display:grid;grid-template-columns:124px 1fr;gap:16px;
  padding:14px;background:var(--white);border:1px solid var(--bone-2);
  transition:border-color .3s var(--ease),box-shadow .4s var(--ease),transform .3s var(--ease);
}
.card:hover{border-color:var(--bone-3);box-shadow:0 14px 34px rgba(35,33,30,.07);transform:translateY(-2px)}
.card.is-saved{border-color:color-mix(in srgb,var(--brand) 42%,transparent);background:var(--paper)}

.card-fig{position:relative;aspect-ratio:4/3.4;overflow:hidden}
.card-fig img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  -webkit-mask-image:var(--torn);mask-image:var(--torn);
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  transform:scale(1.04);transition:transform 1.1s var(--ease),filter .6s;
  filter:saturate(.96);
}
.card:hover .card-fig img{transform:scale(1)}

/* The concierge lane names venues rather than shipping stock photography of
   them, so a good proportion of the strongest suggestions arrive with no image
   at all. Borrowing a generic city shot would imply it pictures the venue, and
   a grey rectangle reads as a failed load, so the slot becomes a deliberate
   cut mark instead: same torn shape, the category set in it. */
.fig-mark{
  display:none;position:absolute;inset:0;
  place-items:center;align-content:center;gap:7px;
  background:var(--bone-2);color:var(--slate-2);
  -webkit-mask-image:var(--torn);mask-image:var(--torn);
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
}
.card-fig.is-blank .fig-mark{display:grid}
.fig-mark .ph{font-size:24px;color:var(--slate-3)}
.fig-mark span{
  font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;
  text-align:center;padding:0 8px;line-height:1.3;
}

.card-main{display:grid;gap:9px;align-content:start;min-width:0}
.card-name{font-size:15px;font-weight:500;line-height:1.32;letter-spacing:-.005em;max-width:46ch}
/* Capped for the reading eye, not for the container: at full card width these
   run past a hundred characters a line, which is where prose stops scanning. */
.card-why{font-size:13px;color:var(--slate);line-height:1.6;max-width:66ch}

.card-meta{display:flex;gap:7px;flex-wrap:wrap}
.meta{
  display:inline-flex;align-items:center;gap:5px;
  font-size:11.5px;color:var(--slate-2);
  background:var(--bone);border-radius:2px;padding:3px 8px;
}
.meta .ph{font-size:12.5px;color:var(--slate-3)}
.meta.is-price{color:var(--ink)}
.meta.is-far{background:color-mix(in srgb,var(--brand) 10%,transparent);color:var(--brand-dp)}
.meta.is-far .ph{color:var(--brand-dp)}

.card-acts{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:2px}

.act{
  display:inline-flex;align-items:center;gap:7px;
  padding:7px 14px;border-radius:100px;font-size:12.5px;
  transition:background .2s,border-color .2s,color .2s,transform .2s var(--ease);
}
.act .ph{font-size:14px}
.act-save{border:1px solid var(--bone-3);color:var(--slate)}
.act-save:hover{border-color:var(--brand-dp);color:var(--brand-dp)}
.act-save.is-on{background:var(--brand);border-color:var(--brand);color:var(--on-brand);font-weight:500}
.act-book{color:var(--ink);border-bottom:1px solid var(--bone-3);border-radius:0;padding:6px 0}
.act-book:hover{color:var(--brand-dp);border-color:var(--brand-dp)}
.act-book .ph{transition:transform .3s var(--ease)}
.act-book:hover .ph{transform:translateX(3px)}

/* ---------- Hero card ----------
   The aperture. One suggestion per opening resolves as a disc rather than a
   rectangle, opening from a point as the day arrives. The crop is the graphic,
   so the picture never settles into another photo-in-a-card. */

.card-hero{grid-template-columns:216px 1fr;gap:26px;padding:22px;align-items:center}
.card-hero .card-fig{
  aspect-ratio:1;background:none;overflow:visible;
  display:grid;place-items:center;
}
.card-hero .card-fig img{
  border-radius:50%;-webkit-mask-image:none;mask-image:none;
  clip-path:circle(6% at 50% 50%);transition:clip-path 1.2s var(--ease),transform 1.1s var(--ease);
  transform:none;
}
.is-in .card-hero .card-fig img{clip-path:circle(50% at 50% 50%)}
.card-hero:hover .card-fig img{transform:scale(1.02)}
.card-hero .card-fig::before{
  content:"";position:absolute;inset:-13px;border-radius:50%;
  border:1px solid color-mix(in srgb,var(--brand) 34%,transparent);
  transform:scale(.72);opacity:0;
  transition:transform 1.1s var(--ease) .2s,opacity .8s .2s;
}
.is-in .card-hero .card-fig::before{transform:scale(1);opacity:1}
.card-hero .fig-mark{
  border-radius:50%;-webkit-mask-image:none;mask-image:none;
}
.card-hero .fig-mark .ph{font-size:34px}
.card-hero .card-name{font-family:'Instrument Serif',Georgia,serif;font-size:26px;font-weight:400;line-height:1.16;letter-spacing:-.012em}
.card-hero .card-why{font-size:14px;max-width:52ch}

/* ---------- Fit bar ----------
   The thing nobody else shows: proof it fits. Travel out, time at the venue,
   travel back, drawn inside the opening's real width, with whatever is left
   over marked as buffer. Rendered only when the distance and the duration are
   both real, because a fabricated guarantee is worse than none.  */

.fit{display:grid;gap:7px;margin-top:3px}
.fit-track{
  position:relative;display:flex;height:5px;width:100%;
  background:linear-gradient(var(--bone-2),var(--bone-2)) left center/100% 1px no-repeat;
}
.fit-seg{
  height:5px;transform:scaleX(0);transform-origin:left;
  transition:transform .85s var(--ease);
}
.is-in .fit-seg{transform:scaleX(1)}
.is-in .fit-seg.seg-act{transition-delay:.12s}
.is-in .fit-seg.seg-back{transition-delay:.24s}
.seg-out,.seg-back{background:repeating-linear-gradient(90deg,var(--brand-lit) 0 2px,transparent 2px 4px)}
.seg-act{background:var(--brand)}
.seg-buf{background:none;border-top:1px solid var(--bone-3);margin-top:2px;height:3px}

.fit-note{font-size:11.5px;color:var(--slate-2);line-height:1.5;max-width:72ch}
.fit-note b{font-weight:400;color:var(--ink)}
.fit.is-tight .seg-act{background:var(--brand-dp)}
.fit.is-tight .fit-note{color:var(--brand-dp)}

/* Ticketmaster events have a start time rather than a duration, so the honest
   drawing is a single marker on the opening, not a fabricated block. */
.fit-mark{position:relative;height:5px;background:linear-gradient(var(--bone-2),var(--bone-2)) left center/100% 1px no-repeat}
.fit-mark i{
  position:absolute;top:-3px;width:2px;height:11px;background:var(--brand);
  left:var(--at,50%);transform:scaleY(0);transform-origin:center;
  transition:transform .6s var(--ease) .1s;
}
.is-in .fit-mark i{transform:scaleY(1)}

/* ---------- Lane states ---------- */

.lane-wait{display:grid;gap:12px}
.skel{
  display:grid;grid-template-columns:124px 1fr;gap:16px;padding:14px;
  border:1px solid var(--bone-2);background:var(--white);
}
.skel-fig{aspect-ratio:4/3.4;background:var(--bone-2)}
.skel-lines{display:grid;gap:9px;align-content:start}
.skel-line{height:10px;background:var(--bone-2);border-radius:2px}
.skel-line:nth-child(1){width:58%}
.skel-line:nth-child(2){width:92%}
.skel-line:nth-child(3){width:74%}
.skel-fig,.skel-line{animation:pulse 1.5s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.48}}

.lane-note{font-size:12.5px;color:var(--slate-3);padding:2px 0}

/* ---------- Source notice ----------
   A supplier that failed is one failure. It is stated once, above the spine,
   with the reason and a retry, instead of the same red line repeated inside
   every window on the page. */
.notices{display:grid;gap:8px;padding:18px 0 0}
.notices:empty{padding:0}
.notice{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:12px 16px;background:var(--paper);
  border:1px solid var(--bone-2);border-left:2px solid var(--brand-dp);
}
.notice > .ph{font-size:17px;color:var(--brand-dp);flex:none}
.notice-text{flex:1;min-width:14ch;font-size:12.5px;color:var(--slate);line-height:1.5}
.notice-text b{font-weight:500;color:var(--ink)}
.notice-retry{
  display:inline-flex;align-items:center;gap:7px;flex:none;
  font-size:12.5px;color:var(--slate);
  border:1px solid var(--bone-3);border-radius:100px;padding:6px 14px;
  transition:border-color .2s,color .2s,opacity .2s;
}
.notice-retry:hover{border-color:var(--brand-dp);color:var(--brand-dp)}
.notice-retry[disabled]{opacity:.5;cursor:default}

.opening-empty{
  padding:18px 0 4px;font-size:13px;color:var(--slate-2);max-width:56ch;
}

/* ============================================================================
   TUNE
   Real client-side reordering with stated rules, not a mood setting.
   ============================================================================ */

.tune{
  position:sticky;top:58px;z-index:40;
  display:none;align-items:center;gap:12px;flex-wrap:wrap;
  padding:12px 0;margin-bottom:-1px;
  background:rgba(242,239,233,.92);backdrop-filter:blur(10px);
  border-bottom:1px solid var(--bone-2);
}
.tune.is-on{display:flex}
.tune-label{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--slate-3)}
.tune-chip{
  display:inline-flex;align-items:center;gap:7px;
  font-size:12.5px;color:var(--slate);
  border:1px solid var(--bone-3);border-radius:100px;padding:6px 14px;
  transition:border-color .2s,color .2s,background .2s;
}
.tune-chip:hover{border-color:var(--brand-dp);color:var(--brand-dp)}
.tune-chip.is-on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.tune-chip.is-on .ph{color:var(--brand-lit)}
.tune-why{flex:1 1 100%;font-size:11.5px;color:var(--slate-3)}

/* ============================================================================
   TRIP FOOT
   ============================================================================ */

.tripfoot{
  padding:40px 0 60px;border-top:1px solid var(--bone-2);
  display:grid;gap:18px;
}
.tripfoot-h{font-family:'Instrument Serif',Georgia,serif;font-size:clamp(24px,3vw,36px);line-height:1.16}
.tripfoot-sub{font-size:14px;color:var(--slate);max-width:56ch}
.tripfoot-acts{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
.tripfoot-credit{font-size:11px;color:var(--slate-2);line-height:1.6;max-width:60ch;padding-top:8px}
.tripfoot-credit a{border-bottom:1px solid var(--bone-3)}
.tripfoot-credit a:hover{color:var(--brand-dp);border-color:var(--brand-dp)}

/* ============================================================================
   CHAT
   Demoted to a drawer. The tune chips handle the common case; this is for the
   things a chip cannot say.
   ============================================================================ */

.chat{
  position:fixed;right:22px;bottom:22px;z-index:80;
  width:min(376px,calc(100vw - 44px));max-height:min(560px,calc(100dvh - 44px));
  display:flex;flex-direction:column;
  background:var(--paper);border:1px solid var(--bone-2);
  box-shadow:0 22px 60px rgba(35,33,30,.14);
  transform:translateY(calc(100% + 32px));opacity:0;pointer-events:none;
  transition:transform .4s var(--ease),opacity .3s;
}
.chat.is-on{transform:none;opacity:1;pointer-events:auto}

.chat-head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:15px 18px;border-bottom:1px solid var(--bone-2);flex:none;
}
.chat-title{display:flex;align-items:center;gap:9px;font-size:13px;color:var(--ink)}
.chat-title .ph{color:var(--brand);font-size:16px}
.chat-x{width:28px;height:28px;display:grid;place-items:center;border-radius:50%;color:var(--slate-3);transition:color .2s,background .2s}
.chat-x:hover{color:var(--ink);background:var(--bone-2)}

.chat-log{flex:1;min-height:0;overflow-y:auto;padding:16px 18px;display:grid;gap:12px;align-content:start}
.msg{max-width:88%;padding:10px 13px;font-size:13px;line-height:1.6;border-radius:2px}
.msg.from-bot{background:var(--bone);color:var(--slate);justify-self:start}
.msg.from-me{background:var(--brand);color:var(--on-brand);justify-self:end}
.msg.is-wait{color:var(--slate-3);font-style:italic}

.chat-row{display:flex;gap:9px;padding:14px 18px;border-top:1px solid var(--bone-2);flex:none}
.chat-in{
  flex:1;min-width:0;padding:10px 13px;border-radius:2px;font-size:13px;color:var(--ink);
  background:var(--white);border:1px solid var(--bone-3);
}
.chat-in::placeholder{color:var(--slate-3)}
.chat-in:focus{outline:none;border-color:var(--brand)}
.chat-send{
  width:38px;flex:none;display:grid;place-items:center;border-radius:2px;
  background:var(--brand);color:var(--on-brand);transition:opacity .2s;
}
.chat-send[disabled]{opacity:.5;cursor:default}

/* A pale pill, not a dark one. It floats over the timeline, and the timeline
   is the thing being read. */
.chat-fab{
  position:fixed;right:22px;bottom:22px;z-index:79;
  display:inline-flex;align-items:center;gap:9px;
  padding:11px 19px;border-radius:100px;font-size:13px;
  background:var(--paper);color:var(--ink);border:1px solid var(--bone-3);
  box-shadow:0 10px 30px rgba(35,33,30,.11);
  transition:transform .22s var(--ease),box-shadow .3s,opacity .25s,border-color .2s;
}
.chat-fab .ph{color:var(--brand);font-size:16px}
.chat-fab:hover{transform:translateY(-2px);box-shadow:0 16px 40px rgba(35,33,30,.16);border-color:var(--brand)}
.chat-fab.is-gone{opacity:0;pointer-events:none;transform:translateY(10px)}

/* ============================================================================
   PROFILE SHEET
   What the parser inferred, on demand from the rail, and honest that it is an
   inference rather than something the traveller told us.
   ============================================================================ */

.sheet{
  position:fixed;inset:0;z-index:95;display:grid;place-items:center;padding:24px;
  background:rgba(35,33,30,.5);backdrop-filter:blur(3px);
  opacity:0;pointer-events:none;transition:opacity .3s;
}
.sheet.is-on{opacity:1;pointer-events:auto}
.sheet-card{
  width:min(430px,100%);background:var(--paper);
  border:1px solid var(--bone-2);padding:28px;
  transform:translateY(12px);transition:transform .35s var(--ease);
  max-height:calc(100dvh - 48px);overflow-y:auto;
}
.sheet.is-on .sheet-card{transform:none}
.sheet-top{display:flex;align-items:center;gap:14px;margin-bottom:22px}
.sheet-av{
  width:46px;height:46px;flex:none;border-radius:50%;display:grid;place-items:center;
  background:var(--brand);color:var(--on-brand);font-size:14px;letter-spacing:.04em;
}
.sheet-name{font-family:'Instrument Serif',Georgia,serif;font-size:22px;line-height:1.2}
.sheet-ctx{font-size:12.5px;color:var(--slate-2)}
.sheet-sec{display:grid;gap:10px;padding-top:18px;border-top:1px solid var(--bone-2);margin-top:18px}
.sheet-foot{
  display:flex;align-items:center;gap:8px;margin-top:20px;padding-top:16px;
  border-top:1px solid var(--bone-2);font-size:11.5px;color:var(--slate-3);
}
.sheet-foot .ph{color:var(--brand)}
.sheet-close{position:absolute;top:0;right:0;width:100%;height:100%;cursor:default}

/* ============================================================================
   RESPONSIVE
   The rail becomes a strip, the timeline stays exactly what it was. One
   layout, one codebase, phone to desktop.
   ============================================================================ */

@media (max-width:1024px){
  .card-hero{grid-template-columns:170px 1fr;gap:20px}
  .card-hero .card-name{font-size:23px}
  .ribbon-days{grid-auto-flow:row;grid-auto-columns:auto;grid-template-columns:repeat(auto-fit,minmax(96px,1fr))}
}

@media (max-width:768px){
  :root{--rail:0px;--gutter:52px}

  .rail{
    top:auto;bottom:0;right:0;width:auto;height:60px;flex-direction:row;
    padding:0 12px;gap:10px;
    border-right:none;border-top:1px solid var(--bone-2);
  }
  .rail-logo{height:20px}
  .rail-days{
    flex-direction:row;justify-content:flex-start;gap:2px;padding:0 4px;
    overflow-x:auto;overflow-y:hidden;
  }
  .rail-day{width:auto;min-width:44px;padding:6px 4px}
  .rail-day::before{
    left:50%;top:auto;bottom:2px;transform:translateX(-50%);
    width:16px;height:2px;
  }
  .rail-day:hover::before{width:24px;height:2px}
  .rail-day.is-current::before{width:28px;height:3px}
  .rail-me{width:34px;height:34px;font-size:11px}

  .stage{padding-bottom:60px}
  .wrap{padding:0 20px}
  .topbar{padding:0 20px;height:54px}
  .topbar-dates{display:none}
  .tune{top:54px}

  .day-head{min-height:124px}
  .day-bed{top:-12px;right:-14px;bottom:-40px}
  .day-bed img{-webkit-mask-size:96% 100%;mask-size:96% 100%}
  .day-bed::after{
    background:
      linear-gradient(94deg,var(--bone) 0%,rgba(242,239,233,.78) 38%,rgba(242,239,233,.3) 72%,rgba(242,239,233,.1) 100%),
      linear-gradient(0deg,var(--bone) 8%,rgba(242,239,233,.86) 32%,rgba(242,239,233,.34) 58%,rgba(242,239,233,0) 76%);
  }

  .opening{margin-left:-14px;padding:18px 16px}
  .opening::before{left:-19px}

  .card{grid-template-columns:1fr;gap:13px}
  .card-fig{aspect-ratio:16/9}
  .card-hero{grid-template-columns:1fr;gap:18px;padding:16px}
  .card-hero .card-fig{aspect-ratio:1;max-width:210px;margin:0 auto}
  .card-hero .card-name{font-size:21px}
  .skel{grid-template-columns:1fr}
  .skel-fig{aspect-ratio:16/9}

  /* The gate is the whole screen on a phone, so it gives up its frame and the
     one action stays within reach of a thumb however far down the reading
     goes. */
  .gate{padding:0}
  /* The photograph becomes a band the panel slides up over, rather than a
     surround there is no room for. The city is still the first thing seen. */
  .gate-bed,.gate-scrim{bottom:auto;height:38dvh}
  .gate-scrim{background:linear-gradient(180deg,rgba(242,239,233,.26) 0%,rgba(242,239,233,.08) 44%,var(--bone) 100%)}
  .gate-inner{width:100%}
  .gate-card{
    margin-top:25dvh;min-height:75dvh;padding:26px 20px 0;
    border:none;box-shadow:0 -18px 40px rgba(35,33,30,.12);
  }
  .gate-top{gap:13px}
  .gate-av{width:46px;height:46px;font-size:14px}
  .gate-foot{
    position:sticky;bottom:0;margin-top:22px;
    background:var(--paper);box-shadow:0 -14px 22px var(--paper);
  }
  .gate-go-row{padding-bottom:18px}
  .gate-go{flex:1}
  .gate-go-wrap,.gate-count{min-width:0}

  .chat,.chat-fab{right:14px;bottom:74px}
  .chat{max-height:min(500px,calc(100dvh - 150px))}
  /* A pill this wide sits across the card underneath it on a phone. The label
     collapses to the mark; the accessible name is carried separately. */
  .chat-fab{width:50px;height:50px;padding:0;justify-content:center;border-radius:50%}
  .chat-fab span{display:none}
  .chat-fab .ph{font-size:20px}
}

@media (max-width:480px){
  .cutword{font-size:clamp(44px,15vw,80px)}
  .day-name{font-size:30px}
  .opening-win{font-size:15px}
  .card-acts{gap:7px}
}
