/* TIMELESS — styles for the interactive pages: Cost calculator, Timeline
   calendar, Partners editor, Venue galleries, and the inline SVG charts.

   DARK-FIRST, like the rest of this build: the bare selector is the dark
   state and :root[data-theme="light"] .thing is the explicit override.
   Never the other way round. */

/* ================================================== shared form controls */

.text-input, .num-input, .select-input {
  font-family: inherit; font-size: var(--tl-fs-sm); line-height: var(--tl-lh-compact);
  padding: 7px var(--tl-sp-2-5); border-radius: var(--tl-radius-sm);
  border: 1px solid var(--tl-border-strong);
  background: var(--tl-bg-raised-2); color: var(--tl-text);
  min-width: 0; max-width: 100%;
}
.num-input { width: 110px; text-align: right; font-variant-numeric: tabular-nums; }
.num-input-sm { width: 80px; }
.select-input { cursor: pointer; }
.text-input:focus-visible, .num-input:focus-visible, .select-input:focus-visible { border-color: var(--tl-accent); }

.field { display: flex; flex-direction: column; gap: var(--tl-sp-1); min-width: 0; }
.field-wide { grid-column: 1 / -1; }
.field-label {
  font-size: var(--tl-fs-xs); font-weight: var(--tl-fw-bold); color: var(--tl-text-faint);
  letter-spacing: var(--tl-tracking-3); text-transform: uppercase;
}

.icon-btn {
  background: transparent; border: 1px solid transparent; border-radius: var(--tl-radius-sm);
  color: var(--tl-text-faint); cursor: pointer; font-size: var(--tl-fs-xs); line-height: var(--tl-lh-none);
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; font-family: inherit;
}
.icon-btn:hover { color: var(--tl-danger); border-color: color-mix(in srgb, var(--tl-danger) 45%, transparent); background: var(--tl-danger-bg); }

.inline-form { display: flex; flex-wrap: wrap; gap: var(--tl-sp-2); align-items: center; margin-top: var(--tl-sp-4); }

/* ================================================================ charts */

.tl-chart { width: 100%; display: block; overflow: visible; }
.tl-chart-bars { height: 120px; }
.tl-chart-donut { width: 190px; height: 190px; margin: 0 auto; }

.tl-chart-track { fill: var(--tl-bg-sunken); stroke: var(--tl-border); stroke-width: 0.4; vector-effect: non-scaling-stroke; }
/* The bar chart's track is a thin filled background bar (the rule above is
   right for that), but the donut's track is a <circle> charts.js draws as an
   EMPTY RING — fill="none" plus a big stroke-width equal to the ring's
   thickness. CSS presentation rules beat SVG presentation attributes
   regardless of specificity, so without this override the bar-chart styling
   above wins here too and the empty-state donut renders as a solid filled
   disc instead of a ring. 18 matches charts.js's own rOuter(52) - rInner(34). */
.tl-chart-donut .tl-chart-track { fill: none; stroke: var(--tl-border); stroke-width: 18; }
.tl-chart-label { font-size: 7px; font-weight: var(--tl-fw-bold); fill: var(--tl-text); font-family: var(--tl-font); }
.tl-chart-sublabel { font-size: 6px; fill: var(--tl-text-faint); font-family: var(--tl-font); }
.tl-chart-bars .tl-chart-label, .tl-chart-bars .tl-chart-sublabel { font-size: 6.5px; }
.tl-donut-centre { font-size: 15px; font-weight: var(--tl-fw-bold); fill: var(--tl-text); font-family: var(--tl-font); }
.tl-donut-caption { font-size: 8px; fill: var(--tl-text-faint); font-family: var(--tl-font); }

/* segment colours — brand-led, dark-first.
   transform-box/origin are here so js/motion.js can grow the bars from their
   left edge and scale the donut from its centre WITHOUT touching the width /
   path-data attributes charts.js computed — the figures in the DOM stay exact
   at every frame. */
.tl-seg { stroke: none; }
/* Every OTHER segment is a filled rect/path with no stroke — right, that's
   what the rule above is for. But charts.js draws a single-sponsor-only
   donut as one full <circle fill="none" stroke="currentColor"> instead of
   two degenerate arcs, i.e. a RING made of stroke, not fill. `.tl-seg{stroke:
   none}` was overriding that (CSS beats SVG presentation attributes on
   specificity alone), so the ring's stroke got switched off while
   `.tl-seg-*{fill:...}` painted the circle's interior solid instead — a
   single-segment donut rendered as a filled disc, not a ring. */
.tl-chart-donut circle.tl-seg { fill: none; stroke: currentColor; }
.tl-chart-bars rect.tl-seg { transform-box: fill-box; transform-origin: left center; }
.tl-chart-donut path.tl-seg, .tl-chart-donut circle.tl-seg { transform-box: fill-box; transform-origin: center; }
.tl-seg-covered { fill: var(--tl-light-blue); color: var(--tl-light-blue); }
.tl-seg-short { fill: var(--tl-danger); color: var(--tl-danger); }
.tl-seg-surplus { fill: var(--tl-ok); color: var(--tl-ok); }
.tl-seg-unalloc { fill: var(--tl-text-faint); color: var(--tl-text-faint); }
:root[data-theme="light"] .tl-seg-covered { fill: var(--tl-deep-blue); color: var(--tl-deep-blue); }

.tl-chart-legend { list-style: none; display: flex; flex-wrap: wrap; gap: var(--tl-sp-4); margin-top: var(--tl-sp-3); font-size: var(--tl-fs-xs); color: var(--tl-text-dim); }
.tl-chart-legend li { display: flex; align-items: center; gap: var(--tl-sp-1-5); }
.tl-swatch { width: 10px; height: 10px; border-radius: 2px; background: currentColor; flex-shrink: 0; }
.tl-legend-value { font-weight: var(--tl-fw-bold); color: var(--tl-text); font-variant-numeric: tabular-nums; }

/* ============================================================== search ==== */

.site-search {
  position: relative; display: flex; align-items: center;
  /* the box's own max footprint — see .site-search-input below for why this
     has to shrink at narrow widths rather than just the "visible" clip */
  --tl-search-box: 220px;
  --tl-search-visible: 150px;
}
.site-search-icon {
  /* --tl-text-faint passes AA for body text against the page background,
     but this is a small glyph sitting on --tl-bg-raised-2 (a lighter card
     surface), not page text on the page background — same token, weaker
     result: at icon size it read as barely-there, especially in the
     collapsed icon-only state where it's the ONLY visible affordance.
     --tl-text-dim carries enough contrast on that surface to actually read
     as a search icon rather than a smudge. */
  position: absolute; left: var(--tl-sp-2); font-size: var(--tl-fs-2xs); color: var(--tl-text-dim);
  pointer-events: none; transform: rotate(-45deg);
}
/*
 * This used to transition `width: 150px -> 220px` directly. `.site-search`
 * is a flex item inside `.header-controls`, so animating its width forced
 * the WHOLE header's flex layout to recalculate on every frame of every
 * focus/blur — `.brand` and the nav links included, for a control that only
 * needed to look bigger, not participate in twelve layout passes to get
 * there.
 *
 * Fixed here to the box's own LARGEST size (--tl-search-box) always, so
 * `.site-search` never changes size in the flex row again on focus — zero
 * layout impact on the header. The "collapsed" look is `clip-path` hiding
 * the right (box - visible) px, which is a compositor-only property: no
 * layout, no repaint of anything outside the element's own layer, just like
 * a transform or opacity change.
 *
 * THE BOX ITSELF still has to get smaller on a phone, though — clip-path
 * only hides paint, it never reduces the element's LAYOUT width, so at any
 * screen size this box reserves its full --tl-search-box worth of space in
 * the header's flex row whether or not it's focused. At 220px fixed, that
 * left no room for `.brand` and `.header-controls`' theme-toggle/hamburger
 * inside a 390px viewport — the two mobile breakpoints below shrink the
 * custom properties themselves (the ONLY numbers involved), so the same
 * clip-path technique keeps working, just against a smaller maximum.
 */
.site-search-input {
  font-family: inherit; font-size: var(--tl-fs-xs); width: var(--tl-search-box);
  padding: 5px var(--tl-sp-2) 5px var(--tl-sp-5); border-radius: var(--tl-radius-pill);
  border: 1px solid var(--tl-border); background: var(--tl-bg-raised-2); color: var(--tl-text);
  clip-path: inset(0 calc(var(--tl-search-box) - var(--tl-search-visible)) 0 0 round var(--tl-radius-pill));
  transition: clip-path var(--tl-dur-3) var(--tl-ease), border-color var(--tl-dur-2) var(--tl-ease);
}
.site-search-input::placeholder { color: var(--tl-text-faint); }
.site-search-input:focus { clip-path: inset(0 0 0 0 round var(--tl-radius-pill)); border-color: var(--tl-accent); outline: none; }
.site-search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

/* --tl-bp-xl (860px) — nav has already collapsed to the hamburger by here,
   but brand + search + theme-toggle + nav-toggle still have to fit in one
   row with no shrink on any of them. */
@media (max-width: 860px) {
  .site-search { --tl-search-box: 160px; --tl-search-visible: 96px; }
}
/* --tl-bp-xs (520px) — icon-only until focused, so a 390px phone always has
   the theme toggle and hamburger fully on screen, focused or not. */
@media (max-width: 520px) {
  .site-search { --tl-search-box: 150px; --tl-search-visible: 30px; }
  /* At 30px only the icon should show. That's just wide enough for the
     placeholder's first letter to peek past the clip edge before it gets
     cut off — reading as a stray mark next to the icon rather than a label.
     Hide the placeholder entirely until focused; the icon alone is the
     affordance at this width. */
  .site-search-input:not(:focus)::placeholder { color: transparent; }
}

.site-search-results {
  position: absolute; top: calc(100% + var(--tl-sp-2)); right: 0; z-index: var(--tl-z-search-results);
  width: min(360px, calc(100vw - var(--tl-sp-6)));
  max-height: 60vh; overflow-y: auto;
  background: var(--tl-bg-raised); border: 1px solid var(--tl-border-strong);
  border-radius: var(--tl-radius-md); box-shadow: var(--tl-shadow-md); padding: var(--tl-sp-2);
}
/* --tl-bp-xl (860px) — anchored `right: 0` on `.site-search`, whose OWN left
   edge can sit well into the right half of a narrow header (brand pushes it
   over) — a fixed 360px-wide panel hung off that anchor ran off the left
   edge of the viewport by as much as 60px, invisible past `body{overflow-x:
   hidden}`. Anchoring to the header's own edges instead of the search box's
   guarantees the panel's left edge is never less than --tl-sp-3 from 0. */
@media (max-width: 860px) {
  .site-search-results { position: fixed; top: calc(var(--tl-header-h) + var(--tl-sp-2)); left: var(--tl-sp-3); right: var(--tl-sp-3); width: auto; max-height: calc(100vh - var(--tl-header-h) - var(--tl-sp-5)); max-height: calc(100dvh - var(--tl-header-h) - var(--tl-sp-5)); }
}
.site-search-results[hidden] { display: none; }
.search-group {
  font-size: var(--tl-fs-3xs); font-weight: var(--tl-fw-bold); text-transform: uppercase; letter-spacing: var(--tl-tracking-5);
  color: var(--tl-text-faint); padding: var(--tl-sp-2) var(--tl-sp-3) var(--tl-sp-1);
}
.search-hit {
  display: flex; flex-direction: column; gap: var(--tl-sp-0-5); width: 100%; text-align: left;
  background: transparent; border: none; border-radius: var(--tl-radius-sm);
  padding: var(--tl-sp-2) var(--tl-sp-3); cursor: pointer; font-family: inherit;
}
.search-hit:hover, .search-hit.is-active { background: var(--tl-bg-raised-2); }
.search-hit-label { font-size: var(--tl-fs-sm); font-weight: var(--tl-fw-semibold); color: var(--tl-text); }
.search-hit-sub { font-size: var(--tl-fs-xs); color: var(--tl-text-dim); }
.search-hit-sub em { color: var(--tl-accent); font-style: normal; font-weight: var(--tl-fw-bold); }
.search-empty { padding: var(--tl-sp-3); margin: 0; font-size: var(--tl-fs-sm); color: var(--tl-text-faint); }

/* the day a search result points at */
.cal-day.is-focused {
  border-color: var(--tl-accent);
  box-shadow: var(--tl-focus-ring-shadow);
}

/* ==================================================== vault sync pill ====
   Only ever visible when the local helper app is running. Opened straight off
   disk (the normal case), it stays hidden and the header looks exactly as it
   did before — no nagging about a feature that isn't in use. */

.vault-pill {
  display: inline-flex; align-items: center; gap: var(--tl-sp-1-5);
  padding: 3px var(--tl-sp-2-5) 3px var(--tl-sp-2); border-radius: var(--tl-radius-pill);
  background: var(--tl-ok-bg); color: var(--tl-ok);
  border: 1px solid color-mix(in srgb, var(--tl-ok) 35%, transparent);
  font-size: var(--tl-fs-3xs); font-weight: var(--tl-fw-bold); letter-spacing: var(--tl-tracking-2); white-space: nowrap;
}
.vault-pill[hidden] { display: none; }
.vault-pill-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.vault-pill[data-mode="saving"] { background: var(--tl-info-bg); color: var(--tl-info); border-color: color-mix(in srgb, var(--tl-info) 35%, transparent); }
.vault-pill[data-mode="error"] { background: var(--tl-danger-bg); color: var(--tl-danger); border-color: color-mix(in srgb, var(--tl-danger) 35%, transparent); }
/* --tl-bp-xl (860px) */
@media (max-width: 860px) { .vault-pill .vault-pill-label { display: none; } }

/* ================================================================== cost */

/* Three zones, each a clearly separated answer to one question, rather than
   one dense stack. Spacing is all --tl-sp-* tokens, on the same generous
   rhythm as the rest of the site. */
.cost-zone { padding-top: var(--tl-sp-7); margin-top: var(--tl-sp-7); border-top: 1px solid var(--tl-border); }
.cost-zone:first-of-type { padding-top: 0; margin-top: 0; border-top: none; }
.cost-zone-head { display: flex; gap: var(--tl-sp-4); align-items: flex-start; margin-bottom: var(--tl-sp-5); }
.cost-zone-num {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%;
  background: var(--tl-bg-raised-2); border: 1px solid var(--tl-border);
  color: var(--tl-accent); font-weight: var(--tl-fw-bold); font-size: var(--tl-fs-sm);
  display: flex; align-items: center; justify-content: center; margin-top: 3px;
}
.cost-zone-title { font-size: var(--tl-fs-h2); margin: 0 0 var(--tl-sp-2); }
.cost-zone-lede { color: var(--tl-text-dim); max-width: 62ch; margin: 0; font-size: var(--tl-fs-sm); }

.cost-toolbar {
  display: flex; flex-wrap: wrap; gap: var(--tl-sp-5); align-items: center;
  padding: var(--tl-sp-4) var(--tl-sp-5); margin-bottom: var(--tl-sp-5);
  background: var(--tl-bg-raised); border: 1px solid var(--tl-border); border-radius: var(--tl-radius-md);
}
.cost-toolbar-group { display: flex; align-items: center; gap: var(--tl-sp-2); font-size: var(--tl-fs-xs); }
.cost-toolbar-right { margin-left: auto; gap: var(--tl-sp-3); }
.cost-toolbar .field-label { margin: 0; }

.cost-summary { margin-bottom: var(--tl-sp-6); }

.cost-charts { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: var(--tl-sp-5); }
.cost-chart-card { display: flex; flex-direction: column; }
.cost-chart-card h4 { margin-bottom: var(--tl-sp-1); }
.cost-chart-note { font-size: var(--tl-fs-xs); margin-bottom: var(--tl-sp-5); }
.cost-chart-host { min-height: 40px; }
.cost-chart-host-donut { display: flex; justify-content: center; flex: 1; align-items: center; }

.cost-pools { align-items: start; }
.cost-pool { display: flex; flex-direction: column; gap: var(--tl-sp-4); padding: var(--tl-sp-5); }
.cost-pool-head { display: flex; flex-direction: column; gap: var(--tl-sp-0-5); padding-bottom: var(--tl-sp-3); border-bottom: 1px solid var(--tl-border); }
.cost-pool-head h3 { margin: 0; font-size: var(--tl-fs-h3); }
.cost-pool-head .muted { font-size: var(--tl-fs-xs); }
.cost-rows { display: flex; flex-direction: column; gap: var(--tl-sp-2); }
.cost-row { display: grid; grid-template-columns: minmax(0, 1fr) 110px 130px 26px; gap: var(--tl-sp-2); align-items: center; }
.cost-shared { border-top: 1px dashed var(--tl-border); padding-top: var(--tl-sp-2); font-size: var(--tl-fs-sm); }
.cost-shared-row { display: flex; justify-content: space-between; gap: var(--tl-sp-3); color: var(--tl-text-dim); }
.cost-add-row { align-self: flex-start; }
.cost-pool-total { border-top: 1px solid var(--tl-border); padding-top: var(--tl-sp-3); font-size: var(--tl-fs-sm); }
.cost-total-line { display: flex; justify-content: space-between; gap: var(--tl-sp-3); padding: var(--tl-sp-0-5) 0; color: var(--tl-text-dim); }
.cost-total-line-strong { font-weight: var(--tl-fw-bold); color: var(--tl-text); }
.cost-total-line.is-short { color: var(--tl-danger); font-weight: var(--tl-fw-bold); }
.cost-total-line.is-covered { color: var(--tl-ok); font-weight: var(--tl-fw-bold); }
.cost-caption { font-size: var(--tl-fs-xs); margin-top: var(--tl-sp-5); }
.cost-caption div { color: var(--tl-text-dim); }

/* the sponsor ledger reads as a table: a column header row, then aligned rows */
.cost-sponsor-head {
  display: grid; grid-template-columns: minmax(0, 1fr) 120px 170px 26px; gap: var(--tl-sp-3);
  padding: 0 var(--tl-sp-3) var(--tl-sp-2); font-size: var(--tl-fs-xs); font-weight: var(--tl-fw-bold);
  text-transform: uppercase; letter-spacing: var(--tl-tracking-4); color: var(--tl-text-faint);
}
.cost-sponsor-list { display: flex; flex-direction: column; gap: var(--tl-sp-2); }
.cost-sponsor-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 120px 170px 26px; gap: var(--tl-sp-3); align-items: center;
  padding: var(--tl-sp-3); border: 1px solid var(--tl-border); border-radius: var(--tl-radius-sm); background: var(--tl-bg-raised);
}
.cost-sponsor-row:hover { border-color: var(--tl-border-strong); }
.cost-sponsor-name { font-weight: var(--tl-fw-semibold); font-size: var(--tl-fs-sm); min-width: 0; overflow-wrap: anywhere; }
.cost-sponsor-note { grid-column: 1 / -1; font-size: var(--tl-fs-xs); }
#cost-zone-sponsors .inline-form { margin-top: var(--tl-sp-5); padding-top: var(--tl-sp-5); border-top: 1px dashed var(--tl-border); }

.cost-reference { margin-top: var(--tl-sp-9); border-top: 1px solid var(--tl-border); padding-top: var(--tl-sp-7); }
.cost-ref-title { margin-bottom: var(--tl-sp-2); }

/* ============================================================== calendar */

.cal-head { display: flex; align-items: center; gap: var(--tl-sp-3); margin-bottom: var(--tl-sp-3); flex-wrap: wrap; }
.cal-month-label { margin: 0; font-size: var(--tl-fs-h3); min-width: 190px; }
.cal-legend { display: flex; flex-wrap: wrap; gap: var(--tl-sp-4); font-size: var(--tl-fs-xs); color: var(--tl-text-dim); margin-bottom: var(--tl-sp-3); }
.cal-key { display: inline-flex; align-items: center; gap: var(--tl-sp-1-5); }

.cal-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; display: inline-block; background: var(--tl-text-faint); }
.cal-dot-task { background: var(--tl-light-blue); }
.cal-dot-gate { background: var(--tl-warn); }
.cal-dot-event-day { background: var(--tl-ok); }
.cal-dot-custom-event { background: var(--tl-info); }
:root[data-theme="light"] .cal-dot-task { background: var(--tl-deep-blue); }

.cal-dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--tl-sp-1); margin-bottom: var(--tl-sp-1); }
.cal-dow span { font-size: var(--tl-fs-xs); font-weight: var(--tl-fw-bold); color: var(--tl-text-faint); text-transform: uppercase; letter-spacing: var(--tl-tracking-4); padding-left: var(--tl-sp-1); }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--tl-sp-1); }
.cal-day {
  min-height: 96px; border: 1px solid var(--tl-border); border-radius: var(--tl-radius-sm);
  background: var(--tl-bg-raised); padding: var(--tl-sp-1); display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.cal-day-blank { background: transparent; border-color: transparent; min-height: 0; }
.cal-day-event { border-color: var(--tl-ok); background: var(--tl-ok-bg); }
.cal-day-top { display: flex; align-items: center; justify-content: space-between; }
.cal-day-num { font-size: var(--tl-fs-xs); font-weight: var(--tl-fw-bold); color: var(--tl-text-dim); }
.cal-day-add {
  background: transparent; border: none; color: var(--tl-text-faint); cursor: pointer;
  font-size: 0.9rem; line-height: var(--tl-lh-none); padding: 0 3px; font-family: inherit; border-radius: var(--tl-radius-xs);
}
.cal-day-add:hover { color: var(--tl-accent); background: var(--tl-muted-bg); }
.cal-items { display: flex; flex-direction: column; gap: var(--tl-sp-0-5); min-width: 0; }
.cal-item {
  display: flex; align-items: center; gap: var(--tl-sp-1); width: 100%; text-align: left;
  background: var(--tl-bg-raised-2); border: 1px solid transparent; border-radius: var(--tl-radius-xs);
  padding: var(--tl-sp-0-5) var(--tl-sp-1); cursor: pointer; font-family: inherit; font-size: var(--tl-fs-3xs); color: var(--tl-text-dim);
  min-width: 0;
}
.cal-item:hover { border-color: var(--tl-border-strong); color: var(--tl-text); }
.cal-item.is-selected { border-color: var(--tl-accent); color: var(--tl-text); background: var(--tl-info-bg); }
.cal-item.is-overdue { color: var(--tl-danger); }
.cal-item-time { font-weight: var(--tl-fw-bold); flex-shrink: 0; font-variant-numeric: tabular-nums; }
.cal-item-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.cal-item[data-locked="true"] { background: var(--tl-ok-bg); color: var(--tl-ok); font-weight: var(--tl-fw-bold); }

.cal-inspector {
  margin-top: var(--tl-sp-4); background: var(--tl-bg-raised); border: 1px solid var(--tl-accent);
  border-radius: var(--tl-radius-md); padding: var(--tl-sp-4);
}
.cal-inspector-head { display: flex; align-items: center; gap: var(--tl-sp-2); margin-bottom: var(--tl-sp-3); }
.cal-inspector-head .icon-btn { margin-left: auto; }
.cal-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--tl-sp-3); }
.cal-inspector-note { margin-top: var(--tl-sp-3); font-size: var(--tl-fs-sm); }
.cal-inspector-actions { margin-top: var(--tl-sp-4); }
.cal-badge-task { background: var(--tl-info-bg); color: var(--tl-info); }
.cal-badge-gate { background: var(--tl-warn-bg); color: var(--tl-warn); }
.cal-badge-event-day { background: var(--tl-ok-bg); color: var(--tl-ok); }
.cal-badge-custom-event { background: var(--tl-muted-bg); color: var(--tl-text-dim); }

.timeline-item { cursor: pointer; border-radius: var(--tl-radius-sm); }
.timeline-item:hover { background: var(--tl-bg-raised); }
.timeline-item.is-selected { background: var(--tl-info-bg); }

/* ============================================================== partners */

.partner-add { margin-bottom: var(--tl-sp-6); }
.partner-add h3 { margin-bottom: var(--tl-sp-4); }
.partner-add-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--tl-sp-3); margin-bottom: var(--tl-sp-4); }

.tier-tally { display: flex; flex-wrap: wrap; gap: var(--tl-sp-2); margin-bottom: var(--tl-sp-5); }

.sponsor-card-head { display: flex; align-items: flex-start; gap: var(--tl-sp-2); }
.sponsor-card-head strong { flex: 1; overflow-wrap: anywhere; }
.sponsor-controls { display: grid; grid-template-columns: 1fr; gap: var(--tl-sp-2); margin: var(--tl-sp-3) 0; }
.sponsor-controls .num-input { width: 100%; text-align: left; }
.sponsor-amount-display { font-weight: var(--tl-fw-bold); color: var(--tl-text); }
.sponsor-custom { border-left-color: var(--tl-info); }

/* ================================================================ venues */

.venue-list { display: flex; flex-direction: column; gap: var(--tl-sp-6); }
.venue-docs { margin: var(--tl-sp-4) 0; }
.venue-docs h4 { margin-bottom: var(--tl-sp-2); }

/* Carousel: one scroll-snapping strip holding every photo, a handful in view
   at a time. Prev/next page through it; it's swipeable for free on touch and
   trackpads. "Show all" reveals the complete set as a grid underneath. */
.venue-carousel { margin-top: var(--tl-sp-5); }
.venue-carousel-head { display: flex; align-items: center; gap: var(--tl-sp-3); flex-wrap: wrap; margin-bottom: var(--tl-sp-3); }
.venue-carousel-head h4 { margin: 0; flex: 1; }
.venue-carousel-controls { display: flex; align-items: center; gap: var(--tl-sp-2); }
.venue-nav { border-color: var(--tl-border); font-size: var(--tl-fs-base); }
.venue-nav:hover { color: var(--tl-accent); border-color: var(--tl-accent); background: var(--tl-bg-raised-2); }

.venue-track {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(190px, 1fr);
  grid-template-columns: repeat(4, minmax(190px, 1fr));
  gap: var(--tl-sp-2); overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-behavior: smooth; padding-bottom: var(--tl-sp-2); scrollbar-width: thin;
}
.venue-track::-webkit-scrollbar { height: 6px; }
.venue-track::-webkit-scrollbar-thumb { background: var(--tl-border-strong); border-radius: 3px; }
.venue-track .venue-shot { scroll-snap-align: start; }

.venue-all {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--tl-sp-1-5);
  margin-top: var(--tl-sp-4); padding-top: var(--tl-sp-4); border-top: 1px dashed var(--tl-border);
}
.venue-all[hidden] { display: none; }

.venue-shot {
  padding: 0; border: 1px solid var(--tl-border); border-radius: var(--tl-radius-sm);
  overflow: hidden; background: var(--tl-bg-raised-2); cursor: zoom-in; aspect-ratio: 4 / 3;
}
.venue-shot:hover { border-color: var(--tl-accent); }
.venue-shot img { width: 100%; height: 100%; object-fit: cover; }

.lightbox {
  position: fixed; inset: 0; z-index: var(--tl-z-lightbox); background: rgba(0, 0, 0, 0.88);
  display: flex; align-items: center; justify-content: center; padding: var(--tl-sp-5);
}
.lightbox[hidden] { display: none; }
.lightbox img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--tl-radius-sm); }
.lightbox-close {
  position: absolute; top: var(--tl-sp-4); right: var(--tl-sp-4); z-index: 1;
  background: rgba(255, 255, 255, 0.12); border: none; color: #fff; cursor: pointer;
  width: 40px; height: 40px; border-radius: 50%; font-size: 1.1rem; font-family: inherit;
}
:root[data-theme="light"] .lightbox { background: rgba(255, 255, 255, 0.94); }
:root[data-theme="light"] .lightbox-close { background: rgba(0, 0, 0, 0.12); color: var(--tl-text); }

/* =========================================================== responsive */

/* --tl-bp-2xl (900px) */
@media (max-width: 900px) {
  .cost-charts { grid-template-columns: 1fr; }
}
/* --tl-bp-md (700px) */
@media (max-width: 700px) {
  .cost-zone { padding-top: var(--tl-sp-6); margin-top: var(--tl-sp-6); }
  .cost-zone-head { gap: var(--tl-sp-3); margin-bottom: var(--tl-sp-4); }
  .cost-zone-num { width: 26px; height: 26px; font-size: var(--tl-fs-xs); }
  .cost-toolbar { gap: var(--tl-sp-3); padding: var(--tl-sp-4); }
  .cost-toolbar-right { margin-left: 0; width: 100%; justify-content: space-between; }
  .cost-pool { padding: var(--tl-sp-4); }
  .cost-row { grid-template-columns: minmax(0, 1fr) 90px 26px; }
  .cost-row .cost-row-pool { grid-column: 1 / -1; }
  .cost-sponsor-head { display: none; }
  .cost-sponsor-row { grid-template-columns: minmax(0, 1fr) 90px 26px; }
  .cost-sponsor-row .cost-sp-alloc { grid-column: 1 / -1; }
  /*
   * The old fix here was `display: none` on .cal-item-title below 700px —
   * every day cell dropped to showing a coloured dot and a time with NO
   * indication of what the thing actually was. Cells are genuinely narrow at
   * phone width (a 7-column grid inside a 390px viewport leaves ~45px per
   * cell after gaps), so full titles still don't fit — but a few truncated
   * characters plus the existing tap-to-open-inspector flow (which always
   * showed the full title) is real information instead of none. Below
   * 480px the time is dropped first, since the truncated title is worth
   * more of that little space than "14:30" is.
   */
  .cal-day { min-height: 60px; padding: 3px; gap: 2px; }
  .cal-day-num { font-size: 0.65rem; }
  .cal-dow span { font-size: 0.6rem; letter-spacing: var(--tl-tracking-2); }
  .cal-item { padding: 1px 3px; gap: 2px; }
  .cal-item-title { display: block; font-size: 0.5625rem; line-height: var(--tl-lh-snug); }
  .cal-item-time { font-size: 0.5rem; }
  .venue-track { grid-template-columns: repeat(2, minmax(140px, 1fr)); grid-auto-columns: minmax(140px, 1fr); }
  .venue-carousel-head h4 { flex: 1 1 100%; }
}
/* --tl-bp-xs (520px) */
@media (max-width: 520px) {
  .cal-grid, .cal-dow { gap: 3px; }
  .cal-day { min-height: 52px; }
  .cal-item-time { display: none; }
}
