/* ---------- App shell ---------- */

.app-shell {
  width: min(1560px, 100%);
  min-height: 100vh;
  margin: 0 auto;
  padding: 0 28px 56px;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  min-height: 64px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
}

/* Three rising bars; the tallest one carries the event accent. */
.brand-mark {
  display: flex;
  flex: 0 0 auto;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  width: 30px;
  height: 30px;
  padding: 7px 0;
  border-radius: 8px;
  background: var(--ink);
}

.brand-mark::before,
.brand-mark::after,
.brand-mark span {
  content: "";
  display: block;
  width: 4px;
  border-radius: 1.5px;
  background: #fff;
}

.brand-mark::before { height: 7px; opacity: 0.5; }
.brand-mark span { height: 11px; opacity: 0.78; }
.brand-mark::after { height: 16px; background: var(--event); }

.brand-copy {
  display: flex;
  flex-direction: column;
  gap: 4px;
  line-height: 1;
}

.brand-copy strong {
  font-family: var(--font-num);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.07em;
}

.brand-copy em {
  color: var(--ink-3);
  font-style: normal;
  font-weight: 400;
}

.brand-copy small {
  color: var(--ink-3);
  font-family: var(--font-num);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.24em;
}

.sync-area {
  display: flex;
  align-items: center;
  gap: 8px;
}

.sync-copy {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-right: 6px;
}

.sync-state {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--ink-2);
  font-size: var(--fs-control);
  font-weight: 700;
}

.sync-state::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #2f9e67;
  box-shadow: 0 0 0 3px rgba(47, 158, 103, 0.16);
}

.sync-state[data-state="error"]::before {
  background: #d6404a;
  box-shadow: 0 0 0 3px rgba(214, 64, 74, 0.16);
}

.sync-state[data-state="idle"]::before {
  background: var(--ink-4);
  box-shadow: 0 0 0 3px rgba(160, 168, 179, 0.2);
}

.sync-state[data-state="loading"]::before {
  background: var(--event);
  box-shadow: 0 0 0 3px rgba(232, 89, 12, 0.16);
  animation: pulse 1.15s ease-in-out infinite;
}

.sync-detail {
  color: var(--ink-3);
  font-size: var(--fs-control);
  font-variant-numeric: tabular-nums;
}

.icon-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
}

.icon-button > span:first-child {
  font-size: 14px;
  line-height: 1;
}

.reload-button.is-loading > span:first-child { animation: spin 850ms linear infinite; }

/* ---------- Command bar ---------- */

/* ---------- Sticky header stack ----------
   The command bar sticks 10px below the top; each long region's own bar sticks directly below
   it (--region-sticky-top, measured by app.js only when a bar changes size; 0 when the command
   bar scrolls away on phones and short landscape). Scrolling itself runs no script. */
:root { --region-sticky-top: 0px; }

html { scroll-padding-top: calc(var(--region-sticky-top) + 8px); }

/* The strip above the stuck command bar and the gap to a region bar repaint the stage, so rows
   pass under the bars instead of showing through. It fades in over the first scroll (a
   compositor-driven scroll timeline, no handler); without scroll timelines it simply stays. */
.sticky-veil {
  position: fixed;
  z-index: 18;
  top: 0;
  left: 0;
  right: 0;
  height: var(--region-sticky-top);
  background:
    radial-gradient(rgba(38, 58, 102, 0.06) 1px, transparent 1.2px) 0 0 / 22px 22px,
    radial-gradient(1100px 520px at 6% -10%, rgba(58, 116, 255, 0.13), transparent 64%) 0 0 / 100vw 100vh no-repeat,
    radial-gradient(900px 520px at 98% -4%, rgba(160, 104, 255, 0.1), transparent 62%) 0 0 / 100vw 100vh no-repeat,
    linear-gradient(180deg, #e9edf4 0%, var(--bg) 42%, #edeef2 100%) 0 0 / 100vw 100vh no-repeat;
  pointer-events: none;
}

@supports (animation-timeline: scroll()) {
  .sticky-veil {
    opacity: 0;
    animation: sticky-veil-in linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 48px;
  }
}

@keyframes sticky-veil-in { to { opacity: 1; } }

/* While a region is read further down, the command bar slides out above the viewport and the
   region bars move up into its place (app.js sets the slot to 0); scrolling back up returns
   both. The bars ease their sticky offset together with the slide; reduced motion snaps. */
.command-bar {
  transition: transform 220ms cubic-bezier(0.22, 0.8, 0.3, 1), opacity 160ms ease-out;
}

.command-bar.is-nav-collapsed {
  transform: translateY(calc(-100% - 14px));
  opacity: 0;
  pointer-events: none;
}

.sticky-veil { transition: height 220ms cubic-bezier(0.22, 0.8, 0.3, 1); }

.updates-heading,
.tier-panel[open] > .tier-summary,
.songs-heading,
.updates-panel .achievement-sticky-unit,
.tier-panel[open] .tier-body > .tier-controls,
.songs-table thead th,
.score-tier-label { transition: top 220ms cubic-bezier(0.22, 0.8, 0.3, 1); }

@media (prefers-reduced-motion: reduce) {
  .command-bar,
  .sticky-veil,
  .updates-heading,
  .tier-panel[open] > .tier-summary,
  .songs-heading,
  .updates-panel .achievement-sticky-unit,
  .tier-panel[open] .tier-body > .tier-controls,
  .songs-table thead th,
  .score-tier-label { transition: none; }
}

/* Region bars: the same objects as at rest, opaque, stacked directly under the command bar.
   --region-head-h is the region's first sticky row (set on the panel by app.js). */
.updates-heading,
.tier-panel[open] > .tier-summary,
.songs-heading {
  position: sticky;
  z-index: 6;
  top: var(--region-sticky-top);
  background: var(--surface);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.updates-panel .achievement-sticky-unit {
  position: sticky;
  z-index: 5;
  top: calc(var(--region-sticky-top) + var(--region-head-h, 0px));
  background: var(--surface);
}

/* The column's 絞り込み toggle rides on its header row; while closed it follows that row. */
.updates-panel .achievement-filter-details {
  position: static;
}

.updates-panel .achievement-filter-details > summary { top: 4px; }
.achievement-filter-details .achievement-filterbar {
  max-height: max(80px, calc(100dvh - var(--region-sticky-top) - var(--region-head-h, 0px) - 60px));
  overflow: auto;
  overscroll-behavior: contain;
}

.tier-panel[open] .tier-body > .tier-controls {
  position: sticky;
  z-index: 5;
  top: calc(var(--region-sticky-top) + var(--region-head-h, 0px));
  padding-bottom: 10px;
  border-bottom: 1px solid transparent;
  background: var(--surface);
}

.tier-panel[open] .tier-body > .tier-controls + * { padding-top: 0; }

/* Narrow screens and short landscape: keep the controls on one horizontally
   scrolling line, including the AC scope chooser (nothing is hidden). */
@media (max-width: 1280px), (max-height: 480px) {
  .tier-panel[open] .tier-body > .tier-controls {
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding-top: 6px;
    padding-bottom: 6px;
    scrollbar-width: none;
  }
  .tier-panel[open] .tier-body > .tier-controls::-webkit-scrollbar { display: none; }
  .tier-panel[open] .tier-body > .tier-controls > * { flex: 0 0 auto; }
  .tier-panel[open] .tier-controls .tier-lamp-progress { flex-basis: auto; flex-wrap: nowrap; }
  .tier-panel[open] .tier-controls .tier-lamp-scope { flex-basis: auto; white-space: nowrap; }
  /* While 表示設定 is open the line wraps back in place, so its panel opens unclipped. */
  .tier-panel[open] .tier-body > .tier-controls:has(.tier-options[open]) { flex-wrap: wrap; justify-content: flex-end; overflow: visible; }
  .tier-panel[open] .tier-body > .tier-controls:has(.tier-options[open]) > * { flex: 0 1 auto; }
  .tier-panel[open] .tier-body > .tier-controls:has(.tier-options[open]) .tier-lamp-progress { flex-basis: 100%; flex-wrap: wrap; }
}

/* The filter menu shares the songs title/search/sort bar; its contents float over rows. */
.song-filter-bar { display: contents; }
.songs-heading:has(.song-filter-menu[open]) { z-index: 20; }

.song-filter-menu > .song-filter-panel {
  right: 0;
  left: auto;
  gap: 0;
  width: min(620px, calc(100vw - 32px));
  max-height: max(160px, calc(100dvh - var(--region-sticky-top) - var(--region-head-h, 0px) - 60px));
  padding: 4px 12px 10px;
  overflow: auto;
  overscroll-behavior: contain;
}

/* Stuck: the bar keeps the panel's own top — the hairline frame runs over the panel's side
   borders and round its 12px corners — and a hairline shadow marks the stack's lowest row.
   Outside each corner the stage itself is repainted (the same layers as body::before and the
   sticky veil, attached to the viewport, so they line up with what is really behind), clipped
   to the corner by a mask: rows passing underneath never show through, and no flat-coloured
   patch can differ from the lit stage around it. */
.is-region-stuck :is(.updates-heading, .songs-heading),
.tier-panel.is-region-stuck[open] > .tier-summary {
  margin-right: -1px;
  margin-left: -1px;
  border: 1px solid var(--line);
  border-bottom: 0;
}

.is-region-stuck :is(.updates-heading, .songs-heading)::before,
.tier-panel.is-region-stuck[open] > .tier-summary::before {
  content: "";
  position: absolute;
  top: -1px;
  left: -1px;
  right: -1px;
  height: var(--radius-lg);
  background:
    radial-gradient(rgba(38, 58, 102, 0.06) 1px, transparent 1.2px) 0 0 / 22px 22px fixed,
    radial-gradient(1100px 520px at 6% -10%, rgba(58, 116, 255, 0.13), transparent 64%) 0 0 / 100vw 100vh no-repeat fixed,
    radial-gradient(900px 520px at 98% -4%, rgba(160, 104, 255, 0.1), transparent 62%) 0 0 / 100vw 100vh no-repeat fixed,
    linear-gradient(180deg, #e9edf4 0%, var(--bg) 42%, #edeef2 100%) 0 0 / 100vw 100vh no-repeat fixed;
  -webkit-mask:
    radial-gradient(circle at 100% 100%, transparent calc(var(--radius-lg) - 0.5px), #000 var(--radius-lg)) left top / var(--radius-lg) var(--radius-lg) no-repeat,
    radial-gradient(circle at 0 100%, transparent calc(var(--radius-lg) - 0.5px), #000 var(--radius-lg)) right top / var(--radius-lg) var(--radius-lg) no-repeat;
  mask:
    radial-gradient(circle at 100% 100%, transparent calc(var(--radius-lg) - 0.5px), #000 var(--radius-lg)) left top / var(--radius-lg) var(--radius-lg) no-repeat,
    radial-gradient(circle at 0 100%, transparent calc(var(--radius-lg) - 0.5px), #000 var(--radius-lg)) right top / var(--radius-lg) var(--radius-lg) no-repeat;
  pointer-events: none;
}
.is-region-stuck .achievement-column-header,
.tier-panel.is-region-stuck[open] .tier-body > .tier-controls,
.songs-panel.is-region-stuck .songs-table thead th { box-shadow: 0 1px 0 var(--line), 0 6px 10px -8px rgba(21, 27, 36, 0.28); }
.tier-panel.is-region-stuck[open] .tier-body > .tier-controls { border-bottom-color: var(--line); }

/* Anchors and focus land below the command bar and the region's bar. */
.updates-panel,
.tier-panel,
.songs-panel { scroll-margin-top: calc(var(--region-sticky-top) + 8px); }

.achievement-list > *,
.tier-row { scroll-margin-top: calc(var(--region-sticky-top) + var(--region-head-h, 0px) + 96px); }

.songs-table tbody tr { scroll-margin-top: calc(var(--region-sticky-top) + var(--region-head-h, 0px) + var(--songs-filter-h, 0px) + 40px); }

.command-bar {
  position: sticky;
  z-index: 20;
  top: 10px;
  display: flex;
  /* When the period and filter clusters cannot share one row (laptop/half-screen widths,
     long custom ranges), the filters move to a second row instead of squeezing the controls. */
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin: 2px 0 14px;
  padding: 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, 0.9);
  box-shadow: var(--shadow-card);
  backdrop-filter: saturate(1.4) blur(14px);
}

.period-cluster {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.period-cluster > .segmented-control,
.date-navigator > button { flex-shrink: 0; }

.segmented-control button[data-period="recent"] { min-width: 104px; }

.date-navigator {
  display: flex;
  align-items: center;
  gap: 4px;
}

.nav-button {
  width: 30px;
  min-height: 30px;
  padding: 0;
  font-size: 18px;
  line-height: 1;
}

.date-heading {
  min-width: 160px;
  padding: 0 8px;
  line-height: 1.15;
}

.eyebrow { display: block; }

/* Before any data exists the range is hidden but keeps its box, so nothing jumps when data arrives. */
.command-bar.is-unloaded .date-heading strong { visibility: hidden; }

.date-heading strong {
  display: block;
  margin-top: 2px;
  font-size: 14px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  /* One line whenever it fits; when squeezed, break only at the spaces around "〜". */
  word-break: keep-all;
  overflow-wrap: anywhere;
}

.text-button {
  min-height: 30px;
  padding: 0 11px;
  white-space: nowrap;
}

.filter-cluster {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}

.select-field {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  height: 34px;
  padding: 0 0 0 11px;
  border: 1px solid var(--line-2);
  border-radius: 8px;
  background: var(--surface);
  transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}

.select-field:hover { border-color: var(--ink-4); }

.select-field:focus-within {
  border-color: var(--ink-3);
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
}

.select-field span {
  color: var(--ink-3);
  font-size: var(--fs-meta);
  font-weight: 700;
  white-space: nowrap;
}

.select-field select {
  min-width: 0;
  height: 100%;
  padding: 0 28px 0 0;
  border: 0;
  border-radius: 0 8px 8px 0;
  outline: 0;
  background-color: transparent;
  font-size: var(--fs-control);
  font-weight: 800;
}

.filter-reset {
  min-height: 34px;
  padding: 0 12px;
  white-space: nowrap;
}

.custom-range-form {
  position: absolute;
  z-index: 30;
  top: calc(100% + 12px);
  left: 0;
  display: grid;
  grid-template-columns: minmax(205px, 1fr) auto minmax(205px, 1fr) auto;
  align-items: end;
  gap: 8px;
  width: min(650px, calc(100vw - 48px));
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-pop);
}

.custom-range-form label {
  display: grid;
  gap: 4px;
  color: var(--ink-3);
  font-size: var(--fs-meta);
  font-weight: 700;
}

.custom-range-form > span {
  padding-bottom: 8px;
  color: var(--ink-4);
}

.custom-range-form input {
  min-height: 34px;
  padding: 4px 8px;
  border: 1px solid var(--line-2);
  border-radius: 7px;
  color: var(--ink);
  background: var(--surface);
  font-family: var(--font-num);
  font-size: var(--fs-body);
}

.custom-range-form button {
  min-height: 34px;
  padding: 0 16px;
  border: 0;
  border-radius: 8px;
  color: #fff;
  background: var(--ink);
  font-weight: 800;
}

.custom-range-error {
  grid-column: 1 / -1;
  margin: 0;
  color: #b3262f;
  font-size: var(--fs-control);
}

.source-warning {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: -2px 0 12px;
  padding: 8px 14px;
  border: 1px solid #efd3a6;
  border-radius: var(--radius);
  color: #744609;
  background: #fff8ec;
  font-size: var(--fs-control);
}

.source-warning p { margin: 0; }

.warning-mark {
  display: grid;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  background: #c47414;
  font-size: var(--fs-meta);
  font-weight: 800;
}


/* Web source selection uses the same stable header tools as local options. */
.source-change-button, .help-link { white-space: nowrap; }
.help-link { text-decoration: none; }
#web-source-chooser { text-align: left; margin-block: 24px; }
#web-source-chooser > div { width: min(640px, 100%); }
#web-source-chooser details { margin-block: 12px; padding: 10px; border: 1px solid var(--line); border-radius: 8px; }
#web-source-chooser summary { cursor: pointer; font-weight: 700; }
.web-source-primary { padding: 14px; border: 1px solid var(--line-2); border-radius: 10px; background: var(--surface-2); }
.web-source-row strong { display: block; margin-bottom: 8px; }
.web-source-row > strong { line-height: 1.65; padding-bottom: 2px; overflow: visible; }
.web-recorder-name { font-family: var(--font-num); }
/* First run: one primary folder action, a small setup link, other recorders folded. */
.web-first-intro { margin-bottom: 14px; }
.web-counter-guide, .web-recorder-others-note, .web-first-note { color: var(--ink-3); font-size: var(--fs-meta); }
.web-counter-guide { margin: 8px 0 0; }
.web-recorder-others-note { margin: 4px 0 8px; }
.web-recorder-others-note a { margin-left: 4px; }
.web-first-note { margin: 0; }
#web-source-chooser .web-source-row > strong { font-size: 15px; }
#web-recorder-others .web-source-row { padding-top: 10px; border-top: 1px solid var(--line); }
#web-recorder-input #web-select-inf-daken { min-height: 44px; margin-top: 4px; padding-inline: 20px; font-size: 1rem; font-weight: 800; }
.web-file-button { display: inline-flex; align-items: center; margin: 4px 6px 4px 0; cursor: pointer; }
.web-source-row .local-file-drop { margin-block: 8px; }
#settings-sources-results, #settings-sources-keystrokes { display: grid; min-width: 0; }
.settings-dialog.web-source-settings { overflow: clip; }
#settings-sources-results fieldset, #settings-sources-keystrokes fieldset { min-inline-size: 0; }
#settings-sources-results small, #settings-sources-keystrokes small { overflow-wrap: anywhere; }
#settings-sources-keystrokes .web-source-row { padding-block: 12px; border-bottom: 1px solid var(--line); }
.web-source-row strong { font-size: var(--fs-control); overflow-wrap: anywhere; }
#web-recorder-input .web-source-row { padding: 14px; border: 1px solid var(--line-2); border-radius: 10px; }
#web-settings-sources .web-source-row { padding-block: 12px; border-bottom: 1px solid var(--line); }
#web-settings-sources .web-source-row small, #web-recorder-input .web-source-row small { display: block; margin-top: 8px; overflow-wrap: anywhere; }
#web-settings-sources input[type="file"], #settings-sources-keystrokes input[type="file"] { min-width: 0; max-width: 100%; }
#web-settings-sources button { margin: 3px 5px 3px 0; }
#web-settings-sources #web-load-sources { display: block; margin-block: 12px; }
.web-source-recommended { display: block; color: var(--ink-3); font-weight: 700; margin-bottom: 4px; }
#web-source-chooser button { margin: 3px 5px 3px 0; }
#web-source-chooser .web-erase-button { margin-top: 12px; }
.web-load-action { margin: 12px 0 20px; }
#web-source-note { margin: 0 0 8px; }
#web-source-note:empty { display: none; }
#web-source-chooser .web-load-cta { display: block; width: 100%; min-height: 48px; margin: 0; font-size: 1.06rem; font-weight: 800; }
#web-source-chooser .web-load-cta:disabled { opacity: .55; cursor: not-allowed; }
@media (max-width: 600px) {
  .topbar { flex-wrap: wrap; gap: 8px; padding-block: 12px; }
  .sync-area { width: 100%; flex-wrap: wrap; }
  .sync-copy { flex-basis: 100%; }
  .song-tools { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
  .song-tools .search-field { grid-column: 1 / -1; }
  .song-tools .sort-field select { width: 100%; max-width: 100%; }
  #web-source-chooser input[type="file"] { max-width: 100%; }
}
