/* ------------------------------------------------------------------ tokens */
:root {
  --paper: #f4f3ee;
  --card: #fdfcfa;
  --ink: #1d1b17;
  --muted: #6e695f;
  --line: #e0ddd3;
  --accent: #b43a2c;      /* hanko red — wordmark, verified stamp */
  --open: #176d47;
  --action: #8a5a00;
  --closed: #b3372c;
  --neutral: #6e695f;
  --badge-free-bg: #176d47;
  --badge-free-ink: #ffffff;
  --shadow: 0 1px 3px rgba(29, 27, 23, .07);
  --font-head: "Zen Kaku Gothic New", "Noto Sans JP", "Hiragino Kaku Gothic ProN", sans-serif;
  --font-body: "Noto Sans JP", "Hiragino Kaku Gothic ProN", "Yu Gothic", sans-serif;
  --font-mono: "IBM Plex Mono", "Osaka-Mono", "MS Gothic", monospace;
}
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #131215;
    --card: #1c1b1f;
    --ink: #eae7df;
    --muted: #99948a;
    --line: #2c2a31;
    --accent: #e05d4a;
    --open: #4cc08a;
    --action: #d9a13f;
    --closed: #e0685c;
    --neutral: #99948a;
    --badge-free-bg: #1b5c40;
    --badge-free-ink: #e9f5ee;
    --shadow: 0 1px 3px rgba(0, 0, 0, .35);
  }
}

/* ------------------------------------------------------------------- base */
* { box-sizing: border-box; }
/* author display values (e.g. .card{display:grid}) override the UA's
   [hidden] rule — restore it, or JS filtering silently does nothing */
[hidden] { display: none !important; }
.date-notice { padding: 1rem; border: 1px solid currentColor; border-radius: .5rem; }
.date-notice strong { display: block; margin-bottom: .35rem; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.65;
}
a { color: inherit; text-decoration-color: color-mix(in srgb, var(--ink) 35%, transparent); text-underline-offset: 2px; }
a:hover { text-decoration-color: var(--accent); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
main { max-width: 1000px; margin: 0 auto; padding: 0 16px 64px; }
h1, h2, h3 { font-family: var(--font-head); text-wrap: balance; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; scroll-behavior: auto !important; }
}

/* Each HTML document contains one interface language; no CSS language hiding. */

/* --------------------------------------------------------------- masthead */
/* Direction A of the masthead comps (Design review, 2026-09-07). On a wide screen the
   masthead is a two-row grid: the utility line top right on row 1, the
   wordmark and the tab group sharing row 2. The DOM order is wordmark, tabs,
   utility line — the order a phone shows them in — and the grid lifts the
   utility line above. */
.masthead {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  column-gap: 16px; row-gap: 4px;
  max-width: 1000px; margin: 0 auto; padding: 8px 16px 16px;
}
.wordmark { grid-row: 2; grid-column: 1; }
.tabs { grid-row: 2; grid-column: 2; }
.util { grid-row: 1; grid-column: 1 / -1; justify-self: end; }
.wordmark { display: flex; align-items: center; gap: 12px; text-decoration: none; }
/* Logo: cube design — こ on the front and
   back, ！ on the sides, resting at -40deg and surging round every 12 s.
   Each face holds the glyph (.f) and a faded mirror of it on its back (.g),
   so the far side of the cube shows through. Glyph outlines come from one
   cached file, /static/logo-glyphs.svg (tools/logo_glyphs.py); no font is
   loaded for the logo. The animation is a composited transform — the cost is
   the pipeline staying awake, not the pixels — and is off under
   prefers-reduced-motion. */
.cube-logo { display: block; --cs: 44px; --gs: calc(var(--cs) * 1.19); --rest: -40deg;
  flex: 0 0 auto; width: var(--cs); height: var(--cs); perspective: calc(var(--cs) * 4); }
.cube { display: block; position: relative; width: 100%; height: 100%; transform-style: preserve-3d;
  transform: rotateY(var(--rest)); animation: surge 12s linear infinite; }
.face { position: absolute; inset: 0; transform-style: preserve-3d; color: var(--ink); }
.face svg { position: absolute; inset: 0; margin: auto; backface-visibility: hidden;
  width: calc(var(--gs) * .95); height: calc(var(--gs) * .95); }
.face .f { transform: translateZ(.5px); }
.face .g { opacity: .18; transform: rotateY(180deg) translateZ(.5px) scaleX(-1); }
.face.side { color: var(--accent); }
.face.side svg { width: calc(var(--gs) * .62); height: calc(var(--gs) * .62); }
.front { transform: translateZ(calc(var(--cs) / 2)); }
.back  { transform: rotateY(180deg) translateZ(calc(var(--cs) / 2)); }
.right { transform: rotateY(90deg) translateZ(calc(var(--cs) / 2)); }
.left  { transform: rotateY(-90deg) translateZ(calc(var(--cs) / 2)); }
@keyframes surge {
  0%, 25% { transform: rotateY(var(--rest)); animation-timing-function: cubic-bezier(.5,0,.85,.35) }
  45%     { transform: rotateY(calc(720deg + var(--rest))); animation-timing-function: linear }
  70%     { transform: rotateY(calc(2880deg + var(--rest))); animation-timing-function: cubic-bezier(.15,.65,.35,1) }
  92%, 100% { transform: rotateY(calc(3600deg + var(--rest))) }
}
@media (prefers-reduced-motion: reduce) { .cube { animation: none; } }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.wm-tag { font-family: var(--font-head); font-weight: 700; font-size: 15px; letter-spacing: .04em; }
/* The three actions as one object: a pill group, the current tab filled the
   way the day page's selected chip is. Icons are line glyphs from
   /static/nav-icons.svg, drawn in the tab's own colour. */
.tabs { display: inline-flex; padding: 3px; border: 1px solid var(--line);
        border-radius: 999px; background: var(--card); }
.tabs a { display: inline-flex; align-items: center; gap: 7px; padding: 8px 18px;
          border-radius: 999px; text-decoration: none; white-space: nowrap;
          font-family: var(--font-head); font-weight: 700; font-size: 15px; }
.tabs a.is-here { background: var(--ink); color: var(--paper); }
.tabs a:not(.is-here):hover { color: var(--accent); }
.nav-ic { width: 17px; height: 17px; flex: 0 0 auto; stroke: currentColor; fill: none;
          stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* The quiet line: small, medium weight, the muted ink; the section this page
   belongs to (aria-current="page" from base.html.j2) gets the accent rule. */
.util { display: flex; align-items: center; gap: 22px;
        font-family: var(--font-head); font-weight: 500; font-size: 12.5px; color: var(--muted); }
.util a { text-decoration: none; white-space: nowrap; }
.util a:hover { color: var(--ink); }
.util a.is-here { color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent);
                  text-decoration-thickness: 2px; text-underline-offset: 5px; }
#langtoggle {
  font: inherit; font-family: var(--font-head); font-weight: 700; font-size: 12px; cursor: pointer;
  margin-left: 6px; padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
}
#langtoggle:hover { border-color: var(--accent); color: var(--accent); }

/* ------------------------------------------------------------------- hero */
.hero { padding: 28px 0 8px; }
.hero-tight { padding-bottom: 0; }
.hero h1 { font-size: clamp(26px, 5vw, 38px); font-weight: 900; margin: 0 0 6px; }
.hero-sub { color: var(--muted); margin: 0; }

/* --------------------------------------------------------------- date nav */
/* ------------------------------------------------------------ date picker */
/* Three nights, then — behind a fourth button — the month calendar. The grid
   used to be the whole control, which priced the commonest question (what is
   on tonight) at a scan of thirty boxes (2026-08-31). The grid is still
   WIDTH-CAPPED: stretched to the container it made 12px numbers float in
   138px boxes, and a calendar reads as a calendar only at roughly square
   cells. */
.datepick { margin: 8px 0 14px; }

/* The four ways in. Each of the three nights carries a count, so a shortcut
   answers part of the question before it is pressed. */
.dp-quick { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.dp-q {
  flex: 0 0 auto; cursor: pointer; font: inherit; font-size: 12.5px;
  padding: 5px 11px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper); color: var(--ink); text-decoration: none;
  display: inline-flex; align-items: center; gap: 5px;
}
.dp-q:hover { border-color: var(--accent); color: var(--accent); }
.dp-q.is-on { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.dp-q.is-on .dp-qn { color: var(--paper); opacity: .75; }
/* Solid means "this is the day you are looking at". A reveal button is only a
   switch for which panel is on screen, so it gets the selected-TAB treatment
   the month buttons already use — the same distinction, for the same reason:
   two identical black pills side by side, one a place and one a drawer, read
   as one control that has gone wrong. */
.dp-q.dp-reveal.is-on {
  background: var(--card); color: var(--ink); border-color: var(--ink); font-weight: 600;
}
.dp-qn { font-style: normal; font-size: 10px; color: var(--muted); }
/* A date we hold nothing for. Drawn, not hidden — "nothing on tonight" is an
   answer, and a shortcut that vanishes on quiet days looks broken. */
.dp-q.is-off { opacity: .38; cursor: default; pointer-events: none; }
.dp-caret { font-size: 9px; transition: transform .12s ease; }
.dp-q[aria-expanded="true"] .dp-caret { transform: rotate(180deg); }
.dp-any { margin-right: 3px; }

/* With JS off the calendar stays open and the page is one long calendar; the
   reveal button only ever hides, so nothing depends on scripting to work. */
.js-dp .dp-cal { display: none; }
.js-dp .dp-cal.is-open { display: block; }
/* And inside the open calendar, one month at a time. Without this the panel
   renders all seventeen months stacked — which is exactly the no-JS fallback,
   correct there and wrong here. */
.js-dp .dp-grid { display: none; }
.js-dp .dp-grid.is-open { display: block; }
.dp-cal { margin-top: 8px; }

.dp-months {
  display: flex; gap: 4px; overflow-x: auto; padding-bottom: 5px;
  scrollbar-width: thin;
}
.dp-months::-webkit-scrollbar { height: 4px; }
.dp-m {
  flex: 0 0 auto; cursor: pointer; font: inherit; font-size: 12px;
  padding: 4px 9px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--paper); color: var(--muted);
}
.dp-m:hover { border-color: var(--accent); color: var(--accent); }
/* A month reads as a selected tab, never as the solid pill a chosen DAY gets:
   one is a filter, the other only switches which grid is on screen. */
.dp-m.is-on {
  background: var(--card); color: var(--ink); border-color: var(--ink); font-weight: 600;
}

.dp-grid { margin-top: 6px; width: 100%; max-width: 336px; }
.dp-head, .dp-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp-wd { font-size: 10px; color: var(--muted); text-align: center; padding-bottom: 1px; }
.dp-d {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 34px; gap: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 5px; background: var(--paper);
  color: inherit; text-decoration: none; font: inherit;
}
.dp-d b { font-size: 12.5px; font-weight: 600; line-height: 1.1; }
.dp-d i { font-style: normal; font-size: 9px; color: var(--muted); line-height: 1; }
.dp-d:hover { border-color: var(--accent); color: var(--accent); }
.dp-d.wd-5, .dp-d.wd-6 { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.dp-d.is-active, .dp-d.is-on {
  background: var(--ink); color: var(--paper); border-color: var(--ink);
}
.dp-d.is-active i, .dp-d.is-on i { color: var(--paper); opacity: .75; }
/* A day with nothing on is still drawn: a gap in a calendar is an answer. */
.dp-d.is-empty { border-color: transparent; color: var(--muted); opacity: .3; cursor: default; }
.dp-d.is-empty i { display: none; }
.dp-pad { min-height: 34px; }

/* ------------------------------------------------------- grouped areas */
/* Thirty-six chips in one blob is a wall. Grouped by rail geography, busiest
   first inside each group, counted. */
.areagroups { margin: 4px 0 6px; display: flex; flex-direction: column; gap: 5px; }
.areagroups.is-collapsed { display: none; }
.ag-row { display: flex; gap: 8px; align-items: baseline; }
.ag-label {
  flex: 0 0 auto; width: 9.5em; font-size: 11px; color: var(--muted);
  text-align: right; padding-top: 3px;
}
.ag-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.ch-n { font-size: 10px; opacity: .65; }
@media (max-width: 640px) {
  .ag-row { flex-direction: column; gap: 2px; }
  .ag-label { width: auto; text-align: left; }
}

/* ---------------------------------------------------------------- filters */
.filters { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.chip {
  font: inherit; font-size: 13px; cursor: pointer;
  padding: 5px 12px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
}
/* A chip is one token: it wraps between chips, never inside one. Without this
   a narrow row broke 渋谷 into 渋/谷 and ロック into ロッ/ク on the venue header,
   where the flex row has no wrap and squeezes its items instead. Every chip
   label we hold — インディーズ（ミックス） is the longest — fits one line at
   358px, so nothing legitimately needs the break. */
.chip, .area-chip, .cap-chip, .badge { white-space: nowrap; }

/* The area filter is two wrappers over one wrapping row: display:contents
   means the desktop layout is exactly the flat row it always was, while a
   phone can turn the areas into a scrolling line and leave 無料・当日OK on a
   line of its own. */
.areafilter { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.filters-area, .filters-free { display: contents; }
.filters-area .areagroups { flex: 0 0 100%; }
.chip:hover { border-color: var(--accent); }
.chip.is-on { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.chip-free.is-on { background: var(--badge-free-bg); color: var(--badge-free-ink); border-color: var(--badge-free-bg); }
.filters-genre { margin-top: 0; }
/* "Free walk-in" is a different kind of filter from geography — give it a rule
   so it stops reading as the 29th area. */
.filter-sep { width: 1px; align-self: stretch; background: var(--line); margin: 2px 4px; }
/* Desktop has room for the whole set: reveal it and drop the toggle. The
   collapse exists for phones, where 26 areas is eight rows of furniture. */
@media (min-width: 701px) {
  /* The expander stays visible on desktop: the grouped areas below it are
     collapsed until clicked (site.js setAreasOpen). A rule for the old
     .area-rest class hid it here and left 49 areas unreachable (2026-09-04). */
}
/* The phone's filter dropdowns. Above 700px the wrapper generates no box and
   the buttons are not rendered at all, so every row below is exactly the row
   it was; the mobile half of this lives in the phone block at the end. */
.fgroup { display: contents; }
.fbar { display: none; }
.chip-quiet { color: var(--muted); }
.areas-toggle { cursor: pointer; }
.maplink + .sep { color: var(--muted); margin: 0 6px; }
a.chip, a.chip-link, .area-chip.chip-link { text-decoration: none; }
.chip-link:hover { border-color: var(--accent); color: var(--accent); }
.d-genres { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin: 8px 0 0; }

/* ----------------------------------------------------------------- search */
.searchbox { margin: 14px 0 6px; }
.searchbox input {
  width: 100%; max-width: 520px; font: inherit; font-size: 16px;
  padding: 10px 14px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
}
.searchbox input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.s-results h2 { margin: 22px 0 8px; font-size: 15px; }
.s-events { list-style: none; padding: 0; margin: 0; }
.s-events li { padding: 5px 0; border-bottom: 1px solid var(--line); }
.s-date { color: var(--muted); margin-right: 8px; font-size: 12.5px; }
.s-venue { color: var(--muted); font-size: 12.5px; margin-left: 8px; }

/* ------------------------------------------------------------- day blocks */
.day { margin-top: 30px; scroll-margin-top: 64px; }
.dayhead {
  display: flex; align-items: baseline; gap: 12px;
  border-bottom: 2px solid var(--ink);
  padding-bottom: 6px; margin: 0 0 12px;
  font-size: 20px; font-weight: 900;
}
.d-num { font-size: 30px; font-weight: 600; }
.d-count { margin-left: auto; font-size: 13px; color: var(--muted); }
.day-empty, .day-empty-static { color: var(--muted); font-size: 14px; padding: 8px 2px; }
/* Halls sit in their own block at the end of the day page, not mixed into
   the live-house list (ROADMAP Decisions § 3) — same card grid, a quieter
   rule above it instead of the ink-black one so it doesn't read as "more of
   the same night" cut in half. */
.day-halls { margin-top: 40px; }
.day-halls .dayhead { border-bottom-color: var(--line); }
.day-halls-note { margin: -6px 0 12px; font-size: 12px; color: var(--muted); }

/* ------------------------------------------------------------------ cards */
.cards { display: flex; flex-direction: column; gap: 8px; }
.card {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) 230px;
  gap: 4px 16px;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 12px 14px;
}
.card.cancelled .c-title { text-decoration: line-through; }
/* Past does not mean cancelled or disabled. Keep contrast and links intact. */
.card.is-past { filter: grayscale(1); background: var(--paper); }
.card.is-past .c-title, .card.is-past .c-start { color: var(--muted); }
.c-past-label { color: var(--ink); font-size: .85rem; font-weight: 700; margin: 0 0 .4rem; }
.c-time { display: flex; flex-direction: column; }
.c-date { font-size: 12px; font-weight: 700; color: var(--accent); white-space: nowrap; }
.c-start { font-size: 19px; font-weight: 600; }
.c-doors { font-size: 11px; color: var(--muted); }
/* Long unbroken source billing must wrap inside the card's text column,
   not widen a narrow page. Keep the complete text rather than clipping it. */
.c-main { min-width: 0; overflow-wrap: anywhere; }
.c-title { margin: 0; font-size: 15.5px; font-weight: 700; line-height: 1.45; }
.c-title a { text-decoration: none; }
.c-title a:hover { color: var(--accent); }
.c-lineup { margin: 2px 0 0; font-size: 13px; color: var(--muted); }
.c-venue { margin: 4px 0 0; font-size: 13px; }
.c-venue a { text-decoration: none; font-weight: 500; }
.c-venue a:hover { text-decoration: underline; }
.area-chip {
  display: inline-block; margin-left: 6px;
  font-size: 11px; color: var(--muted);
  border: 1px solid var(--line); border-radius: 4px; padding: 0 6px;
}
/* Capacity band chip: the same quiet box as an area chip, tabular numerals
   because the label is number-shaped. Many live houses are under 100 seats,
   so tiny wants its own mark as much as hall does — tiny and hall both get a
   one-step lift (existing tokens only, no new colour) so a scan of the list
   catches them without either reading as an alert. */
.cap-chip { font-family: var(--font-mono); }
.cap-chip-tiny { color: var(--accent); border-color: var(--accent); }
.cap-chip-hall { color: var(--ink); border-color: var(--ink); font-weight: 700; }
.c-side { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.c-price { margin: 0; font-size: 12.5px; }
.c-paynote { margin: 0; font-size: 12px; color: var(--action); }
.c-prov { margin: 2px 0 0; font-size: 11px; color: var(--muted); }
.c-prov a { color: inherit; }

.card.has-flyer { grid-template-columns: 72px 72px minmax(0, 1fr) 230px; }
.c-thumb {
  display: block; width: 72px; height: 72px; overflow: hidden;
  border-radius: 6px; border: 1px solid var(--line); background: var(--paper);
}
.c-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (max-width: 700px) {
  /* flex-wrap:wrap is inherited from the rule above, and turning the masthead
     on its side made it a MULTI-line column flex container — whose line takes
     the cross size of its widest item's max-content, the nav's 462px, and
     stretches every child to it. On a 390px phone the document came out 494px
     wide (measured in Chromium, 2026-09-04): the whole page scrolled sideways
     and the EN pill sat 120px short of the window edge. nowrap puts the line
     back at the container's own width, and the nav wraps inside it. */
  .masthead { display: flex; flex-direction: column; align-items: stretch;
              flex-wrap: nowrap; gap: 10px; padding: 14px 16px 6px; }
  /* Direction A on a phone (Design review, 2026-09-07): the logo row with the language
     pill lifted onto it (below), the tab group across the full width like an
     app's tab bar, then the utility line centred in one quiet row — nothing
     wraps by accident any more (Design review, 2026-09-04, had chosen "wrap" over a
     hamburger; this keeps the no-JavaScript, nothing-hidden part). */
  .tabs { display: flex; width: 100%; }
  .tabs a { flex: 1; justify-content: center; padding: 9px 6px; font-size: 14.5px; }
  .util { justify-content: center; flex-wrap: wrap; gap: 6px 18px; padding: 2px 0 4px; }
  .hero { padding: 16px 0 6px; }
  .card { grid-template-columns: 56px minmax(0, 1fr); }
  /* Design review, 2026-09-04: a third column for the flyer left the title, the lineup
     and the venue about 186px to live in. On a phone the thumbnail wraps UNDER
     the time instead, so a card with artwork has the same two columns as one
     without and the text column runs the full height beside both. Placed by
     hand: auto-placement would put the thumb beside the time (DOM order is
     time, thumb, main, side), which is the layout being replaced. */
  .card.has-flyer { grid-template-columns: 56px minmax(0, 1fr); }
  .card.has-flyer .c-time  { grid-area: 1 / 1 / 2 / 2; }
  .card.has-flyer .c-thumb { grid-area: 2 / 1 / 3 / 2; }
  .card.has-flyer .c-main  { grid-area: 1 / 2 / 3 / 3; }
  .card.has-flyer .c-side  { grid-row: 3; grid-column: 1 / -1; }
  .c-thumb { width: 56px; height: 56px; }
  .c-side { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
  .c-start { font-size: 16px; }
}

/* ----------------------------------------------------------------- badges */
.badge {
  display: inline-block;
  font-size: 11.5px; font-weight: 700; letter-spacing: .02em;
  padding: 2px 9px; border-radius: 999px;
  border: 1.5px solid;
}
.b-open    { color: var(--open); border-color: var(--open); }
.b-action  { color: var(--action); border-color: var(--action); }
.b-closed  { color: var(--closed); border-color: var(--closed); }
.b-neutral { color: var(--neutral); border-color: var(--neutral); border-style: dashed; }
.b-free    { background: var(--badge-free-bg); color: var(--badge-free-ink); border-color: var(--badge-free-bg); }

/* -------------------------------------------------------------------- cta */
.cta {
  display: inline-block;
  font-size: 13px; font-weight: 700; text-decoration: none;
  padding: 5px 13px; border-radius: 7px;
  border: 1.5px solid var(--ink);
}
.cta small { font-weight: 500; opacity: .75; font-size: 11px; }
.cta:hover { background: var(--ink); color: var(--paper); }
.cta-open { border-color: var(--open); color: var(--open); }
.cta-open:hover { background: var(--open); color: #fff; }
.cta-action { border-color: var(--action); color: var(--action); }
.cta-action:hover { background: var(--action); color: #fff; }
.cta-closed, .cta-neutral { border-color: var(--line); color: var(--muted); }
.cta-closed:hover, .cta-neutral:hover { background: var(--muted); color: var(--paper); }

/* ------------------------------------------------------------ detail page */
.crumbs { font-size: 13px; color: var(--muted); padding: 14px 0 0; }
.detail { max-width: 720px; }
.d-head { padding: 18px 0 6px; }
.d-date { color: var(--muted); font-size: 14px; margin: 0 0 4px; }
.d-head h1 { font-size: clamp(22px, 4.5vw, 32px); font-weight: 900; margin: 0 0 10px; line-height: 1.35; }
.d-sec { margin-top: 26px; }
.d-sec h2 {
  font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); border-bottom: 1px solid var(--line);
  padding-bottom: 4px; margin: 0 0 10px;
}
.d-sec h3 { font-size: 14px; margin: 0 0 6px; }
.lineup { list-style: none; margin: 0; padding: 0; }
.lineup li { padding: 2px 0; }
.role { font-size: 11px; color: var(--muted); border: 1px solid var(--line); border-radius: 4px; padding: 0 5px; margin-left: 6px; }
/* The instrument sits closer to the name than the billing role does, and is
   the venue's own abbreviation (as.ss. / vib. / 津軽三味線.), so it reads as an
   annotation rather than a tag: no border, monospace to line up in a list. */
.inst { font-size: 11px; color: var(--muted); font-family: var(--font-mono); margin-left: 6px; }
.d-price { font-size: 16px; font-weight: 600; margin: 0 0 8px; }
.unstated { color: var(--muted); font-style: normal; }
.notes { font-size: 13px; color: var(--muted); }
.tablewrap { overflow-x: auto; }
.tiers-h { font-size: 12.5px; font-weight: 600; color: var(--muted);
           margin: 10px 0 4px; }
.tiers { border-collapse: collapse; width: 100%; font-size: 13.5px; }
.tiers th { text-align: left; font-size: 12px; color: var(--muted); font-weight: 600; }
.tiers th, .tiers td { padding: 6px 12px 6px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.tier-en { font-size: 12px; color: var(--muted); display: block; }
.streaming {
  margin-top: 14px; padding: 10px 14px;
  border: 1px dashed var(--line); border-radius: 8px;
  font-size: 13.5px; color: var(--muted);
}
.d-flyer { margin: 0; }
.d-flyer img {
  max-width: min(100%, 480px); height: auto;
  border-radius: 8px; border: 1px solid var(--line); box-shadow: var(--shadow);
}
.d-flyer figcaption { font-size: 12px; color: var(--muted); margin-top: 6px; }
.access-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.paynote { color: var(--action); font-weight: 500; }
.deadline { font-size: 13px; color: var(--muted); }
.instructions {
  margin-top: 10px; padding: 10px 14px;
  background: color-mix(in srgb, var(--card) 60%, var(--paper));
  border-left: 3px solid var(--line); border-radius: 0 8px 8px 0;
  font-size: 13.5px;
}
.instructions p { margin: 0; }
.mt-mark { font-size: 10.5px; color: var(--muted); border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; }
.note-box {
  margin-top: 12px; padding: 10px 14px;
  border: 1px solid color-mix(in srgb, var(--action) 40%, var(--line));
  border-radius: 8px; font-size: 13.5px;
}
.note-box p { margin: 0 0 6px; }
.note-box ul { margin: 0; padding-left: 18px; }
.v-name a { font-weight: 700; font-size: 16px; text-decoration: none; }
.v-en { color: var(--muted); margin-left: 8px; font-size: 13px; }
.v-addr, .v-station, .v-cap { margin: 2px 0; font-size: 13.5px; }
.v-cap-estimated { color: var(--muted); }
.v-lines { color: var(--muted); font-size: 12px; }
.maplink { font-weight: 600; }
.pagelinks { list-style: none; margin: 0; padding: 0; }
.pagelinks li { padding: 3px 0; }
.pl-host { font-size: 11.5px; color: var(--muted); margin-left: 8px; }
.prov-box {
  margin-top: 30px; padding: 12px 16px;
  border: 1px solid var(--line); border-radius: 10px;
  font-size: 12.5px; color: var(--muted);
}
.prov-box p { margin: 0 0 4px; }
.prov-hint { font-size: 12px; }
.verified { color: var(--accent); font-weight: 700; }

/* ------------------------------------------------------------- venue page */
.v-head { padding: 18px 0 4px; }
.v-head h1 { font-size: clamp(24px, 5vw, 34px); font-weight: 900; margin: 0; }
.v-head-en { color: var(--muted); margin: 2px 0 8px; font-size: 15px; }
.v-meta { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 6px 0; font-size: 13px; color: var(--muted); }
.v-meta .area-chip { margin-left: 0; }
.v-links { display: flex; flex-wrap: wrap; gap: 14px; margin: 10px 0 0; font-size: 13.5px; }

/* -------------------------------------------------------- venue directory */
.area-sec { margin-top: 30px; }
.venue-list { list-style: none; margin: 0; padding: 0; }
.venue-row {
  display: flex; align-items: baseline; gap: 14px;
  padding: 9px 2px; border-bottom: 1px solid var(--line);
  font-size: 14.5px;
}
.vr-name { text-decoration: none; flex: 1; min-width: 0; }
.vr-name:hover .vr-ja { color: var(--accent); }
.vr-ja { font-weight: 700; }
.vr-en { color: var(--muted); font-size: 12.5px; margin-left: 8px; }
.venue-row .area-chip { margin-left: 0; }      /* .venue-row's own gap already spaces it */
.vr-count { font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.venue-row .maplink { font-size: 12.5px; white-space: nowrap; }

/* -------------------------------------------------------------------- map */
.mapbox { height: min(72vh, 640px); border-radius: 12px; border: 1px solid var(--line); margin-top: 16px; }
@media (prefers-color-scheme: dark) {
  .mapbox .leaflet-tile { filter: brightness(.82) contrast(1.05); }
}

/* ------------------------------------------------------------------ about */
.prose .lede { font-size: 16.5px; line-height: 1.75; }
.prose p { max-width: 64ch; }
.legend td:first-child { white-space: nowrap; }

/* ------------------------------------------------------------------ QA page */
.qa-progress { color: var(--muted); font-size: 13px; margin: 4px 0 0; }
.qa-hint { color: var(--muted); font-size: 13px; margin: 0 0 8px; }
.qa-list { list-style: none; margin: 0; padding: 0; }
.qa-row {
  display: flex; gap: 12px; align-items: baseline;
  padding: 7px 6px; border-bottom: 1px solid var(--line); font-size: 13.5px;
}
.qa-row.is-done { opacity: .45; }
.qa-row.is-done .qa-main a { text-decoration: line-through; }
.qa-check input { width: 16px; height: 16px; accent-color: var(--accent); }
.qa-date { color: var(--muted); font-size: 12px; white-space: nowrap; }
.qa-main { flex: 1; min-width: 0; }
.qa-main a { font-weight: 700; text-decoration: none; }
.qa-main a:hover { color: var(--accent); }
.qa-venue { color: var(--muted); font-size: 12.5px; margin-left: 8px; }
.qa-reason { display: block; font-size: 12.5px; color: var(--action); }
.qa-links { display: flex; gap: 10px; align-items: center; white-space: nowrap; font-size: 12.5px; }
.qa-links a { font-weight: 600; }

/* ----------------------------------------------------------------- footer */
.footer {
  max-width: 1000px; margin: 0 auto; padding: 22px 16px 34px;
  border-top: 1px solid var(--line);
  font-size: 12.5px; color: var(--muted);
}
/* One line: About · Licence (Design review, 2026-09-03, cut further 2026-09-04 — the
   contact address lives on /about/ now and the "no ads" claim line is gone;
   the language switch stays in the nav). The provenance paragraph and the
   build stamp that used to live under it are gone; .foot-meta went with them. */
.foot-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px;
  margin: 0; max-width: none;
}
.foot-line a { text-decoration: none; }
.foot-line a:hover { color: var(--accent); }
.foot-qa { font-family: var(--font-mono); }
/* The address on /about/. No href or text until site.js assembles them, so
   give the link the pointer it is about to have; the <noscript> spelling
   stands in for it with JS off. */
.contact-addr a, .contact-addr noscript { font-family: var(--font-mono); }
.contact-addr a { cursor: pointer; }

/* ------------------------------------------------------ artist layer */
.a-genres { display:flex; gap:6px; align-items:center; flex-wrap:wrap; margin:6px 0 0; }
.a-genres .chip { cursor:pointer; }
.a-inferred { color:var(--muted); font-size:11.5px; }
.a-links { display:flex; flex-wrap:wrap; gap:6px; margin:8px 0 0; }
.a-links a { color: var(--accent); text-decoration:none; margin-right:0;
  border:1px solid var(--line); border-radius:999px; padding:3px 10px;
  font-size:12.5px; line-height:1.5; }
.a-links a:hover { text-decoration:none; border-color:var(--accent); }
.a-links a small { color:var(--muted); font-weight:400; }
/* A venue's own profile page for its house players is not the artist's site —
   label it as what it is rather than dressing it up as an official channel. */
.a-links .a-venue_profile { color:var(--muted); }
.a-imgcred { color:var(--muted); font-size:11.5px; margin:6px 0 0; }
.v-usually { color: var(--muted); font-size: 13px; margin: 4px 0 8px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

/* ------------------------------------------------------- venue index jump */
.mapfilters { margin-bottom: 6px; }
.mapcount { color: var(--muted); font-size: 12.5px; margin: 4px 0 8px; }
.chip-open.is-on { background: var(--open); color: var(--paper); border-color: var(--open); }
.areajump { display:flex; flex-wrap:wrap; gap:6px; margin:14px 0 6px; }
.areajump .chip { text-decoration:none; }
.areajump .aj-n { color:var(--muted); font-size:11.5px; margin-left:5px; }
.area-sec { scroll-margin-top: 12px; }
.venue-row.is-empty .vr-name { color: var(--muted); }
.venue-row.is-empty .vr-count { color: var(--muted); font-style: italic; }

/* ------------------------------------------------- event detail two-column */
.d-actionbar { display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px;
  margin:12px 0 4px; }
.d-actionprice { font-size:14px; }
/* Below 940 the aside is just the next block after the header, which puts the
   artwork early on a phone instead of below admission and ticketing. */
.d-aside { margin:14px 0 4px; }
.d-aside .d-flyer { margin:0; }
@media (min-width: 940px) {
  /* .detail caps at 720px for readable line length. With a sidebar we widen the
     container by exactly the sidebar, so the text column keeps its 720px and the
     flyer occupies space that was empty margin. */
  .detail.has-aside { max-width:1056px;
    display:grid; grid-template-columns:minmax(0,720px) 300px;
    column-gap:36px; align-items:start; }
  .detail.has-aside > *:not(.d-aside) { grid-column:1; min-width:0; }
  .d-aside { grid-column:2; grid-row:1 / span 99; position:sticky; top:16px;
    margin:0; }
  .d-aside .d-flyer img { width:100%; height:auto; }
}
.d-head.has-portrait { display:grid; grid-template-columns:auto 1fr;
  gap:0 16px; align-items:start; }
.d-head.has-portrait > :not(.a-portrait) { grid-column:2; }
.a-portrait { grid-row:1 / span 3; width:88px; height:88px; border-radius:50%;
  object-fit:cover; background:var(--line); }
@media (max-width:520px) { .a-portrait { width:64px; height:64px; } }
/* A 3:1 header banner keeps its own ratio. aspect-ratio + object-fit:cover
   means the box never dictates a different shape to the image. */
.a-banner { margin:12px 0 0; border-radius:10px; overflow:hidden;
  background:var(--line); line-height:0; }
.a-banner img { width:100%; height:auto; aspect-ratio:3 / 1; object-fit:cover;
  display:block; }
/* With a banner above it the portrait overlaps the strip, as profiles do. */
.d-head.under-banner { padding-top:0; }
.d-head.under-banner .a-portrait { margin-top:-34px; border:3px solid var(--bg);
  width:94px; height:94px; }
@media (max-width:520px) {
  .d-head.under-banner .a-portrait { margin-top:-24px; width:68px; height:68px; }
}
/* A row-major grid, not page-height columns: with three thousand names a
   column ran the length of the page and a heading's neighbours were whoever
   the other columns had reached. Now each heading spans the width and its
   names read across then down beneath it, and a jump lands on a full row. */
.a-index { list-style:none; margin:8px 0 0; padding:0;
  display:grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); column-gap: 28px; }
.a-index li { break-inside: avoid; display:flex; justify-content:space-between;
  gap:8px; padding:3px 0; border-bottom:1px solid var(--line); font-size:14px; }
.a-index a { text-decoration:none; overflow-wrap:anywhere; }
.a-index a:hover { color: var(--accent); }
.a-count { color:var(--muted); font-size:12px; flex:0 0 auto; }
/* One alphabet (Design review, 2026-09-07: grouped by show count, an act could not be
   found by scrolling). The headings sit in the column flow — あ…わ, 漢字, A…Z,
   0–9 — each kept with its first entry; the jump row above the list is the
   same set, one link per group that exists. */
.a-jump { display:flex; flex-wrap:wrap; gap:2px 4px; margin:14px 0 0;
  font-family:var(--font-head); font-weight:700; font-size:14px; }
.a-jump a { text-decoration:none; padding:3px 6px; border-radius:4px; }
.a-jump a:hover { color:var(--accent); background:var(--card); }
.a-index li.a-head { display:block; padding:16px 0 3px; border-bottom:2px solid var(--ink);
  font-family:var(--font-head); font-weight:700; font-size:15px;
  grid-column: 1 / -1; scroll-margin-top:12px; }
.a-index li.a-head:first-child { padding-top:4px; }

/* ---------------------------------------------- ticket routes & confidence */
/* The route split is a stacked bar in list form: the reader should see at a
   glance that "we can name the seller" is a minority of shows, because it is. */
.route-split { list-style: none; margin: 10px 0 0; padding: 0;
  display: grid; gap: 6px; }
.rt { display: grid; grid-template-columns: 4.5rem minmax(0, 12rem) 1fr;
  gap: 10px; align-items: baseline; padding: 8px 10px;
  border: 1px solid var(--line); border-left-width: 3px; background: var(--card); }
.rt-vendor  { border-left-color: var(--accent); }
.rt-venue   { border-left-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.rt-door    { border-left-color: color-mix(in srgb, var(--accent) 25%, var(--line)); }
.rt-unknown { border-left-color: var(--line); }
.rt-n { font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; }
.rt-note { color: var(--muted); font-size: 12px; }
@media (max-width: 560px) {
  .rt { grid-template-columns: 4rem 1fr; }
  .rt-note { grid-column: 2; }
}
.fineprint { color: var(--muted); font-size: 12px; margin-top: 14px; max-width: 62ch; }
/* Only the weakest band earns space on a card, and it names the field rather
   than printing a score nobody can act on. */
.c-caveat { margin: 4px 0 0; font-size: 11px; color: var(--muted);
  border-left: 2px solid color-mix(in srgb, var(--accent) 50%, transparent);
  padding-left: 6px; }
.prov-conf { margin: 6px 0 0; font-size: 12px; color: var(--muted);
  border-left: 2px solid color-mix(in srgb, var(--accent) 55%, transparent);
  padding-left: 8px; }
.prov-conf.conf-weak { color: var(--ink); }
.rt-unnamed { border-left-color: color-mix(in srgb, var(--accent) 35%, var(--line)); border-left-style: dashed; }

/* ==================================================================== phone
   One block, at the end of the file so it wins over the rules that come
   after the earlier max-width:700px block (.areajump's flex-wrap:wrap was
   silently undoing the scroll row it was already given). The design review approved the
   phone layout on 2026-09-03 and signed off on every rule below; nothing
   here fires above 700px. */
@media (max-width: 700px) {

  /* ------------------------------------------------ language switch
     Design review, 2026-09-04: "The language button should be aligned to the right side
     of the window." It stays where it belongs in the DOM — inside the nav,
     next to the links it is a peer of — and is lifted onto the logo row, the
     one strip of the masthead with space to spare. 16px is .masthead's own
     padding and main's, so the pill's right edge is the right edge of the
     cards below it. Nothing else is needed now the page is no longer wider
     than the window; the two edge-fade overlays that used to sit here went
     with the scrolling row they were fading. */
  .masthead { position: relative; }
  #langtoggle { position: absolute; top: 22px; right: 16px; z-index: 2;
                margin: 0; font-size: 13px; padding: 5px 12px; }

  /* ------------------------------------------------- filters as dropdowns
     Design review, 2026-09-04: "I'm not a fan of the horizontal scrolling. I would
     prefer a dropdown that is expanded on click." One wrapping row — エリア,
     入場方法, ジャンル and the free chip — and the chip rows themselves are
     the panels: the very elements site.js and map.js already wire, lifted
     into place by flex order rather than copied. The wrappers in between go
     display:contents so every control is a child of the one flex row and
     `order` can put it where it belongs. */
  .fgroup { display: flex; flex-wrap: wrap; align-items: flex-start;
            gap: 6px; margin: 10px 0 4px; }
  .js .fbar { display: contents; }
  .fgroup .areafilter, .fgroup .filters-free { display: contents; }
  .fgroup .filter-sep { display: none; }
  .fb { order: 1; padding: 8px 14px; }
  .fb.is-open { border-color: var(--ink); }
  .fb-caret { display: inline-block; }
  .fb.is-open .fb-caret { transform: rotate(180deg); }
  /* 無料・当日OK is not geography: it keeps its place on the button row
     rather than hiding inside the エリア panel. */
  .fgroup .chip-free { order: 2; padding: 8px 14px; }
  [data-fpanelbody] { order: 3; flex: 0 0 100%;
                      display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 4px; }
  .js [data-fpanelbody] { display: none; }
  .js [data-fpanelbody].is-openpanel {
    display: flex; padding: 10px;
    border: 1px solid var(--line); border-radius: 10px;
    background: color-mix(in srgb, var(--card) 70%, var(--paper));
  }
  /* Inside the panel every area is visible at once and wrapped: the grouped
     list is flattened into the same wrap, the expander goes with it, and so
     does every group chip that repeats one already above — the same area
     twice in one panel is a bug, not a shortcut. */
  .filters-area .areagroups,
  .filters-area .areagroups.is-collapsed,
  .filters-area .ag-row,
  .filters-area .ag-chips { display: contents; }
  .filters-area .ag-label { display: none; }
  .areas-toggle, .chip-dupe { display: none; }

  /* ----------------------------------------------------- the stats line
     "148 shows tonight" is the answer; the corpus total and the listing
     window are context a phone has no room for. */
  .stat-rest { display: none; }

  /* --------------------------------------------------- card action block
     Two lines instead of one wrapping jumble: state and price, then what to
     do about it. The zero-height full-width pseudo-item is the line break;
     order puts the button ahead of the note it qualifies. */
  .c-side { flex-wrap: wrap; }
  .c-side::before { content: ""; flex: 0 0 100%; height: 0; order: 2; }
  .c-side .badge, .c-side .c-price { order: 1; }
  .c-side .cta { order: 3; }
  .c-side .c-paynote { order: 4; }
  .c-side .c-caveat { order: 5; }
  .c-side .c-prov { order: 6; flex: 0 0 100%; }

  /* ------------------------------------------------------- venue directory
     Name, then the English name under it, then the meta — 14.5px Japanese
     and a 12.5px romanisation on one line left the capacity chip and the
     show count fighting for forty pixels. */
  .venue-row { flex-wrap: wrap; gap: 2px 10px; }
  .venue-row .vr-name { flex: 0 0 100%; }
  .vr-en { display: block; margin-left: 0; }

  /* ------------------------------------------------------------- flyer
     A portrait flyer at full width is a screen and a half of artwork before
     the admission line. The link and the credit stay. */
  .d-flyer img {
    max-height: 60vh; width: auto; max-width: 100%;
    display: block; margin: 0 auto;
  }

  /* --------------------------------------------------------------- map
     min(72vh, 640px) is a sensible cap on a desktop and a squat letterbox
     on a phone, where the map IS the page. */
  .mapbox { height: 72vh; }
}
