/* The planner page, and the one button on the map that reaches it.
 *
 * Its own file rather than more of style.css: that stylesheet is the *map* —
 * every rule in it assumes a full-bleed map with chrome floating over it, and
 * this page is an ordinary scrolling document. Keeping them apart means the two
 * cannot break each other.
 *
 * It does borrow style.css for the pieces that must not drift — .icon-btn,
 * .save, .swatch — so the mark and the buttons are the same objects here as on
 * the map rather than a second set that looks nearly right.
 *
 * Everything the planner adds is in this file, planner.html, and the two blocks
 * marked "the plan" in index.html and sw.js. Dropping the feature is deleting
 * those; nothing else in the map knows it exists. See tickets#15.
 */

/* ── The way in, which lives on the map rather than on this page ─────────────
   Under the list button, on the left.

   It began under the *search* button on the right, which put it straight over
   the list panel: that panel docks right on a laptop and its row of sort
   buttons sits at exactly this height, so the calendar landed on top of the
   last sort. The left column has nothing below its one button, and the panel
   never reaches it.

   The offset is the list button's own top plus its height plus the gap .chrome
   uses between its children, so the two read as one column.

   It is here rather than in style.css so that removing the planner is removing
   files, not unpicking rules from the map's stylesheet. */
#btn-plan {
  position: fixed;
  top: calc(12px + env(safe-area-inset-top) + 44px + 10px);
  left: calc(12px + env(safe-area-inset-left));
  /* Below the list panel (550) rather than above it with the rest of the
     chrome (600), so the panel covers this on a phone, where it is full width
     and the screen is already busy. The list button above it stays at 600
     because it is what closes the panel again — this one only leads away, and
     an exit to another page does not need to sit on top of an open list.

     On a laptop nothing changes: the panel takes the right column and never
     reaches the left edge, so the button is visible either way. */
  z-index: 540;
}

/* ── The page itself ─────────────────────────────────────────────────────────*/

body.planner {
  /* style.css pins the body to the viewport height for the map, which would cut
     a long plan off at one screen. This is a document, so it grows instead.
     `overscroll-behavior: none` is left as it is — it stops the rubber-band, not
     the scroll. */
  height: auto;
  min-height: 100%;
  padding: 0 0 max(32px, env(safe-area-inset-bottom));
}

/* Sticky, so the way back to the map is reachable from anywhere down a long
   plan — which is the state this page is for. */
.plan-head {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; gap: 12px;
  padding: calc(12px + env(safe-area-inset-top)) 16px 12px;
  background: var(--chrome);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.plan-head h1 { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.plan-count { margin-left: auto; color: var(--muted); font-size: 13px; }

main#plan {
  max-width: 720px;
  margin: 0 auto;
  padding: 16px;
  display: flex; flex-direction: column; gap: 24px;
  /* A flex column stretches its items to the widest one by default, so a row
     that overflows drags the whole column past the viewport rather than being
     contained by it. This holds every child to the column's own width, which is
     what makes the min-width:0 floors below actually bite. */
  align-items: stretch;
  min-width: 0;
}

.plan-empty, .plan-note { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.6; }
.plan-empty { padding: 24px 4px; }

.plan-day > h2 {
  margin: 0 0 10px;
  font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted);
}
.plan-day ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }

/* Same 96px flyer column the map's cards use, so a row reads the same in both
   places. The mark keeps its own column at the end rather than overlaying the
   text, which it cannot do here: these rows have no fixed height. */
.plan-row {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  gap: 12px;
  align-items: start;
  padding: 10px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
}
/* A venue has no flyer, only a swatch — but it keeps the flyer column's width
   so the titles in both groups line up on one left edge. Centring the dot in
   that column is what stops it reading as a separate, narrower list. */
.plan-row.plan-place { align-items: center; }

.plan-open { display: block; border-radius: 8px; overflow: hidden; text-decoration: none; }
.plan-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.plan-open img { display: block; width: 96px; height: 72px; object-fit: cover; }
.plan-open .no-image {
  display: grid; place-items: center;
  width: 96px; height: 72px;
  background: var(--ground); color: var(--muted); font-size: 22px;
}
.plan-place .plan-open { display: grid; place-items: center; width: 96px; }
.plan-place .swatch { display: block; width: 12px; height: 12px; border-radius: 50%; }

.plan-row .body { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.plan-row .title { font-size: 15px; font-weight: 600; line-height: 1.3; }
/* Provider titles and venue names run long and have no spaces to break on. */
.plan-row .title, .plan-row .meta { overflow-wrap: anywhere; }
.plan-row .meta { color: var(--muted); font-size: 13px; }
.plan-row .meta b { color: var(--text); font-weight: 600; }
.plan-row .genre { color: var(--accent); font-size: 12px; }

/* Clamped rather than cut server-side: the blurb is already trimmed to a
   sentence by toSummary(), and this stops a long one crowding out the row
   below it while still opening up on a wide screen. */
.plan-summary {
  color: var(--muted); font-size: 13px; line-height: 1.5;
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}

/* The ticket and the play/search row beside it are style.css's own .pop-buy
   and .action-row — the same controls the map's card and expanded row use,
   borrowed whole rather than drawn again here. .action-row's own padding is
   tuned for sitting beside a card's edge; inside this row's .body flex column
   there is no edge to clear, so it is reset to nothing here. Every .pop-buy in
   a planner row now lives inside .action-row, so the old rule that put one on
   its own line under the text — align-self: start — no longer applies to
   anything and is gone rather than kept as dead weight. */
.plan-row .action-row { grid-column: auto; padding: 0; }

/* The mark is style.css's .save, which is positioned absolutely for the map's
   cards. Here it is a grid cell. */
.plan-row .save {
  position: static;
  color: var(--favourite);
}
/* Unmarked, the mark goes hollow and quiet like any unkept one — but it must
   stay bright enough to read as the way back, since it is the only undo. */
.plan-row.dropped .save { color: var(--muted); }
.plan-row.dropped .save:hover { color: var(--favourite); }

/* A dropped row stays where it was, faded and struck through, until the page is
   next built. It reads as on its way out rather than as still in the plan, and
   pressing the mark again puts it back — which is the point: an accidental tap
   should cost one tap, not a trip back to the map to find the thing again. */
.plan-row.dropped {
  opacity: .45;
  /* Not display:none on anything: the row has to keep its size, or the list
     jumps under the finger that just tapped it. */
}
.plan-row.dropped .title { text-decoration: line-through; }
/* The ticket link is the one thing that should not stay pressable on a row that
   is on its way out of the plan. */
.plan-row.dropped .pop-buy { pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  .plan-row { transition: opacity .15s ease; }
}


/* ── Finding more ────────────────────────────────────────────────────────────
   A week at a time, the map's own six sort glyphs, and its search field.
   Deliberately the same controls as the map rather than a form: this is the
   same application, and a page you fill in would be a different one wearing the
   same colours. */
.plan-find {
  /* The same measure as the plan below it, so the two halves of the page share
     one column rather than the controls running the full width of a laptop
     while the rows they filter sit in the middle. */
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 16px 0;
  display: flex; flex-direction: column; gap: 12px;
}

/* The week and the field on one line, wrapping to two only when there is
   genuinely no room. Both are flex items with a min-width floor, or the long
   date labels ("19 Oct – 25 Oct") push the row wider than its container and
   everything stacks. */
.find-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }

/* The week, with a step either side of it.
   
   Sized to its contents rather than stretched: given `flex: 1` it took half the
   row on a laptop and the arrows drifted apart, leaving "This week" adrift
   between them instead of reading as one control. The field takes the slack
   instead — it is the thing that benefits from being wider. */
.weeks {
  display: flex; align-items: center; gap: 8px;
  flex: 0 0 auto; min-width: 0;
}
.week-step { width: 40px; height: 40px; flex: none; border-radius: 10px; }
.week-step:disabled { opacity: .3; cursor: default; }
/* The week itself: the loudest thing here, because it is what everything below
   is answering. */
.week-strip {
  /* A floor wide enough for the longest label ("19 Oct – 25 Oct") so the arrows
     do not shuffle as the weeks are stepped through — a control that moves
     under the thumb pressing it is hard to press twice. */
  min-width: 11ch;
  text-align: center;
  font-size: 16px; font-weight: 600; letter-spacing: -0.01em;
  /* One line: a wrapped date range would push the arrows apart and out of
     reach of the thumb that is stepping through weeks. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The search field, which is the map's.
   
   .chrome is borrowed for its blur and border but must NOT keep its
   `position: fixed` — that pins it to the viewport and pulls it out of this
   row, the same trap #filters hit in style.css. */
.find-search {
  position: static;
  flex: 1 1 220px; min-width: 0;
  gap: 0;
}
/* Always open here, unlike the map, where it grows out of its own button: this
   page has room for it and searching is half of what the page is for. The
   glyph beside it is a label, not a control — there is nothing to toggle. */
.find-search input {
  flex: 1; min-width: 0;
  height: 40px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-right: none;
  border-radius: 10px 0 0 10px;
  background: var(--card);
  color: var(--text);
  font: inherit; font-size: 14px;
  -webkit-appearance: none; appearance: none;
  outline: none;
}
.find-search input:focus { border-color: var(--accent); }
.find-search-glyph {
  width: 40px; height: 40px; flex: none;
  border-radius: 0 10px 10px 0;
  border-left: none;
  color: var(--muted);
  background: var(--card);
  cursor: default;
}
/* The pair reads as one control, so the focus ring belongs to both halves. */
.find-search:focus-within input,
.find-search:focus-within .find-search-glyph { border-color: var(--accent); }

/* The sort row is style.css's own .categories, borrowed whole. Only the border
   it carries for the map's list panel is undone — here it sits in open space
   rather than atop a list. */
.plan-find .categories { padding: 0; border-bottom: none; }

/* On is on, off is off — the map's own rule, and no cleverness on top of it.
   
   This once drew the row quiet while every sort was on, reasoning that "all
   selected" means "nothing narrowed" and so should not shout. It made the
   control unreadable: six selected buttons looked deselected, so turning one
   off appeared to turn the other five *on*, and the row seemed to be doing
   something other than what it was. A button that is on has to look on. */

.find-where { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.find-where a { color: var(--accent); }
.find-note { margin: 12px 0 0; color: var(--muted); font-size: 14px; }

/* Results reuse the plan's own day sections and rows, so a found event and a
   kept one are the same object — which is the point, since keeping one is how
   it moves from the top half of the page to the bottom. */
#find-results { display: flex; flex-direction: column; gap: 24px; }
/* A search in flight dims what is already there rather than replacing it, so
   the page keeps its shape and its scroll position while the answer arrives.
   Not hidden and not collapsed: the rows underneath are still the last true
   answer until a newer one lands. */
#find-results.searching { opacity: .45; }
@media (prefers-reduced-motion: no-preference) {
  #find-results { transition: opacity .15s ease; }
}
#find-results .plan-day { margin: 0; }

/* ── The line between finding and having ─────────────────────────────────────
   Above it is what you are looking for, below it what you have already chosen.
   The two halves were running together — results and kept rows are the same
   object by design, which is what made a divider necessary rather than
   optional. */
.plan-rule {
  max-width: 720px;
  margin: 28px auto 0;
  border: none;
  border-top: 1px solid var(--line);
}
.plan-heading {
  max-width: 720px;
  margin: 16px auto 0;
  padding: 0 16px;
  font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted);
}
/* The plan's own first day heading would otherwise sit a full gap below this
   one, reading as a stray label rather than as the section's title. */
.plan-heading + #plan { padding-top: 10px; }
