/* Settings (16.10.2026 rebuild): the sidebar shell (public/settings.js), the Effects page
   (public/effects.js) and the look cards (public/lookpick.js).

   Loaded after styles.css and BEFORE theme-boot.js, so a theme sheet still wins (themes/README.md).
   Built from the app's own tokens and components (.modal, .btn, .vw-sw, .seg) so every theme
   dresses it without having to know it exists. Sizes are a fixed frame on the desktop — the
   dialog does not change size from page to page, so the sidebar never jumps under the pointer —
   and the whole screen on a phone. */

/* ================= the frame ================= */
.modal.stg-modal {
  width: min(980px, calc(100vw - 32px));
  display: flex; flex-direction: column;
  height: min(calc(720px), calc(88vh / var(--ui-z, 1)));
}
.modal.stg-modal > .modal-head { flex: none; }
.modal.stg-modal > .modal-body { flex: 1 1 auto; min-height: 0; max-height: none; padding: 0; overflow: hidden; }
.stg { display: grid; grid-template-columns: 232px minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); height: 100%; min-height: 0; }

/* ---- the sidebar ---- */
.stg-side {
  display: flex; flex-direction: column; min-height: 0; overflow: auto;
  padding: calc(14 * var(--sp)) calc(10 * var(--sp));
  border-right: 1px solid var(--line);
}
.stg-search {
  position: relative; display: flex; align-items: center; gap: 8px; margin: 0 2px calc(12 * var(--sp));
  padding: 0 calc(10 * var(--sp)); height: 34px;
  background: var(--input); border: 1px solid var(--line); border-radius: var(--r-sm);
}
.stg-search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.stg-search > svg { width: 15px; height: 15px; flex: none; color: var(--dim); }
.stg-q {
  flex: 1; min-width: 0; height: 100%; border: 0; outline: 0; background: none; padding: 0;
  color: var(--text); font: inherit; font-size: var(--fs-base);
}
.stg-q::-webkit-search-cancel-button { display: none; }
/* Exactly one focus ring: the box's. Every theme styles `input` (and its :focus) at a higher
   specificity than .stg-q, which gave the field its own border, shadow or outline inside the
   box's ring: a double focus box in Lucid, Kirameki, Millennium, Gloss and Phosphor (N41). */
html[data-theme] .stg .stg-search input.stg-q,
html[data-theme] .stg .stg-search input.stg-q:is(:hover, :focus, :focus-visible) {
  border: 0; outline: 0; box-shadow: none; background: none; border-radius: 0;
  height: 100%; padding: 0; margin: 0;
}
.stg-slash { flex: none; }
.stg-search:focus-within .stg-slash { display: none; }

.stg-nav { display: grid; gap: 1px; }
.stg-item {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 34px;
  padding: calc(6 * var(--sp)) calc(10 * var(--sp)); border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text2); font: inherit; font-size: var(--fs-base); text-align: left; cursor: pointer;
}
.stg-item > i { display: grid; place-items: center; width: 16px; height: 16px; flex: none; color: var(--dim); }
.stg-item > i > svg { width: 16px; height: 16px; }
.stg-item > span { flex: 1; min-width: 0; }
.stg-item:hover { background: var(--glass); color: var(--text); }
.stg-item.on { background: var(--accent-tint); color: var(--accent-text); font-weight: var(--fw-semi); }
.stg-item.on > i { color: var(--accent-text); }
.stg-chev { display: none; }
.stg-sep { height: 1px; margin: calc(8 * var(--sp)) calc(10 * var(--sp)); background: var(--line); }

.stg-results { display: grid; gap: 1px; }
.stg-results[hidden], .stg-nav[hidden] { display: none; }
.stg-hit {
  display: grid; gap: 1px; width: 100%; padding: calc(7 * var(--sp)) calc(10 * var(--sp));
  border: 0; border-radius: var(--r-sm); background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.stg-hit > span { font-size: var(--fs-base); }
.stg-hit > em { font-style: normal; font-size: calc(var(--fs-sm) + var(--fs-half)); color: var(--mut); }
.stg-hit:hover, .stg-hit.on { background: var(--glass); }
.stg-hit.on { box-shadow: inset 2px 0 0 var(--accent); }
.stg-none { padding: calc(8 * var(--sp)) calc(10 * var(--sp)); color: var(--mut); font-size: var(--fs-base); line-height: 1.45; }

/* ---- the page ---- */
.stg-page { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.stg-ph { flex: none; display: flex; align-items: center; gap: 6px; padding: calc(16 * var(--sp)) calc(24 * var(--sp)) calc(4 * var(--sp)); }
.stg-title { font-size: var(--fs-xl, 17px); font-weight: var(--fw-bold, 700); }
.stg-back { display: none; }
.stg-body { flex: 1; min-height: 0; overflow: auto; padding: calc(6 * var(--sp)) calc(24 * var(--sp)) calc(24 * var(--sp)); overscroll-behavior: contain; }
.stg-lede { margin: 0 0 calc(10 * var(--sp)); color: var(--mut); font-size: var(--fs-base); }

.stg-grp { padding: calc(8 * var(--sp)) 0; border-bottom: 1px solid var(--line-soft, var(--line)); }
.stg-grp:last-child { border-bottom: 0; }
.stg-h {
  margin: calc(4 * var(--sp)) 0 calc(6 * var(--sp));
  font-size: calc(var(--fs-sm) + var(--fs-half)); font-weight: var(--fw-semi); color: var(--mut);
}
.stg-row {
  display: flex; align-items: center; gap: 16px; min-height: 40px;
  padding: calc(4 * var(--sp)) calc(8 * var(--sp)); margin: 0 calc(-8 * var(--sp));
  border-radius: var(--r-sm);
}
.stg-nm { flex: 1; min-width: 0; display: grid; gap: 2px; }
.stg-l { font-size: var(--fs-base); color: var(--text); }
.stg-hint { font-style: normal; font-size: calc(var(--fs-sm) + var(--fs-half)); color: var(--mut); line-height: 1.4; }
.stg-ctl { flex: none; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.stg-block { padding: calc(4 * var(--sp)) 0; }
.stg-bh { display: flex; align-items: baseline; gap: 10px; margin-bottom: calc(8 * var(--sp)); }
.stg-foot { display: flex; justify-content: flex-end; gap: 8px; padding-top: calc(10 * var(--sp)); }
.stg-av { display: inline-flex; }

/* The switch keeps its drawn size; its target is 34px tall (themes/README: 24px floor). */
.stg-sw { position: relative; }
.stg-sw::before { content: ''; position: absolute; inset: -8px -6px; }

/* A segmented control, the same shape as the rail's .rs-seg. */
.stg-seg { display: inline-flex; padding: 2px; gap: 2px; background: var(--input); border: 1px solid var(--line); border-radius: var(--r-sm); }
.stg-seg > button {
  min-height: 28px; padding: 0 calc(11 * var(--sp)); border: 0; border-radius: calc(var(--r-sm) - 3px);
  background: none; color: var(--text2); font: inherit; font-size: var(--fs-base); cursor: pointer; white-space: nowrap;
}
.stg-seg > button:hover { color: var(--text); background: var(--glass); }
.stg-seg > button.on { background: var(--accent); color: var(--accent-ink); font-weight: var(--fw-semi); }

/* The one ring a search lands on: one fade, no bounce (PM §3.3). */
/* Drawn on its own layer (N40): a deep theme that gives its rows a box-shadow, or a scroller
   that clips what hangs outside them, hid the old outset shadow, so in Millennium, Gloss and
   Phosphor a search went to the page and seemed to ring nothing. Inset, on ::after, held a
   little longer. */
.stg-ring { position: relative; }
.stg-ring::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border: 2px solid var(--accent); border-radius: inherit;
  animation: stg-ring 2.1s ease-out 1;
}
/* No fill: a theme that zeroes animation durations (Millennium) would jump to the faded end
   state and draw nothing. The base state is the ring; settings.js takes the class off at 2 s,
   before the fade has finished. */
@keyframes stg-ring {
  0%, 45% { opacity: 1; }
  90%, 100% { opacity: 0; }
}

/* Settings ▸ File list borrows the rail's controls; only their spacing changes here. */
.stg-rs .vw-fields { display: grid; gap: 2px; }
.stg-rs .rs-shapes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.stg-looks .lk-accents { display: flex; flex-wrap: wrap; gap: 6px; }
.stg-looks .ic-cards, .stg-looks .ch-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.stg-looks .ch-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 360px; }

/* ================= the look cards ================= */
.lp-themes { display: grid; grid-template-columns: repeat(auto-fill, minmax(124px, 1fr)); gap: 8px; }
.lp-card {
  display: grid; gap: 3px; padding: 5px 5px 7px; text-align: left; cursor: pointer;
  background: none; border: 1px solid var(--line); border-radius: var(--r-sm); color: var(--text); font: inherit;
}
.lp-card:hover { border-color: var(--line2); background: var(--glass); }
.lp-card.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.lp-nm { font-size: var(--fs-base); font-weight: var(--fw-semi); padding: 0 2px; }
.lp-flags { min-height: 1.3em; padding: 0 2px; font-size: var(--fs-sm); color: var(--mut); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The miniature: drawn from the registry's own colours, so it cannot be wrong about them. */
.lp-mini {
  position: relative; display: grid; grid-template-columns: 26% 1fr; aspect-ratio: 16 / 10;
  border-radius: calc(var(--r-sm) - 3px); overflow: hidden; background: var(--lp-bg);
  border: 1px solid var(--lp-line);
}
.lp-mini i, .lp-mini b, .lp-mini s { display: block; text-decoration: none; }
.lp-side { background: var(--lp-side); padding: 14% 10%; display: grid; align-content: start; gap: 9%; border-right: 1px solid var(--lp-line); }
.lp-side > b { height: 5px; border-radius: 3px; background: var(--lp-line); }
.lp-side > b.on { background: var(--lp-a); }
.lp-main { display: grid; align-content: start; gap: 6%; padding: 8% 8%; }
.lp-top { display: flex; align-items: center; justify-content: space-between; height: 9px; margin-bottom: 4%; }
.lp-top > b { width: 40%; height: 5px; border-radius: 3px; background: var(--lp-line); }
.lp-top > s { width: 22%; height: 9px; border-radius: 3px; background: var(--lp-a); }
.lp-row { height: 9px; border-radius: 2px; background: var(--lp-p1); border: 1px solid var(--lp-line); }
.lp-row.on { background: color-mix(in srgb, var(--lp-a) 28%, var(--lp-p1)); border-color: var(--lp-a); }

/* Calm / Tactile / Lively. The small button on each answers a press at its own amplitude. */
.lp-presets { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; }
.lp-pre {
  display: grid; gap: 3px; padding: calc(9 * var(--sp)) calc(10 * var(--sp)); text-align: left; cursor: pointer;
  background: var(--glass); border: 1px solid var(--line); border-radius: var(--r-sm); color: var(--text); font: inherit;
}
.lp-pre:hover { border-color: var(--line2); }
.lp-pre.on { border-color: var(--accent); background: var(--accent-tint); box-shadow: inset 0 0 0 1px var(--accent); }
.lp-tag { font-size: calc(var(--fs-sm) + var(--fs-half)); color: var(--mut); line-height: 1.35; }
.lp-press { display: grid; place-items: center; height: 34px; margin-bottom: 4px; border-radius: var(--r-xs); background: var(--input); }
.lp-press > s { width: 56%; height: 16px; border-radius: 5px; background: var(--line2); text-decoration: none; transition: scale .3s cubic-bezier(.3, 1.6, .5, 1); }
.lp-pre:active .lp-press-tactile > s { scale: .95; transition-duration: .12s; }
.lp-pre:active .lp-press-lively > s { scale: .86; transition-duration: .09s; }
.lp-pre:active .lp-press-custom > s { scale: .92; transition-duration: .1s; }
.lp-pre.on .lp-press > s { background: var(--accent); }

/* ================= Effects ================= */
.ef-top { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; padding-bottom: calc(10 * var(--sp)); }
/* The preview stays on screen while the switches scroll under it (18.10.2026): pinned to the top
   of the page's scroller, on the dialog's own colour so rows pass cleanly beneath it. A wide
   dialog puts it beside the list instead (below). */
.ef-main { display: grid; grid-template-columns: minmax(0, 1fr); align-items: start; }
.ef-preview { display: grid; gap: 6px; position: sticky; top: calc(-6 * var(--sp)); z-index: 2;
  padding: calc(6 * var(--sp)) calc(24 * var(--sp)) calc(8 * var(--sp)); margin-inline: calc(-24 * var(--sp)); background: var(--panel-solid);
  box-shadow: 0 1px 0 var(--line-soft, var(--line)); }
.ef-stage.fx-stage { height: 150px; border: 1px solid var(--line); }
.ef-stage.fx-stage.fx-rows { display: grid; align-content: center; }
.ef-stage.fx-stage.fx-nav { display: grid; align-content: center; }
.ef-stage.fx-stage.fx-cards, .ef-stage.fx-stage.fx-sweep { height: 150px; }
/* The panel sweep's miniature (effects.js panelDemo): two views stacked, the box's own colour
   is the line that shows in the gap between them as one is handed to the other. */
.ef-pn { position: absolute; inset: 0;
  background: linear-gradient(to bottom, transparent, var(--accent) 14%, var(--accent) 86%, transparent), var(--input); }
.ef-pn-v.fx-stage { position: absolute; inset: 0; height: auto; border-radius: 0; display: grid; align-content: center; background: var(--input); }
.ef-showing { margin: 0; font-size: calc(var(--fs-sm) + var(--fs-half)); color: var(--mut); }
.ef-hand {
  position: absolute; z-index: 3; width: 14px; height: 20px; pointer-events: none; margin: -2px 0 0 -2px;
  background: var(--text); clip-path: polygon(0 0, 0 78%, 22% 60%, 40% 100%, 54% 94%, 37% 55%, 66% 55%);
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .5));
}
.ef-hand[hidden] { display: none; }
.ef-row { cursor: default; }
.ef-row.ef-sel { background: var(--glass); }
.ef-row.off .stg-l { color: var(--text2); }
.ef-beta { font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--mut); border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; margin-left: 4px; }
.ef-choice { height: 28px; border-radius: var(--r-xs); border: 1px solid var(--line); background: var(--input); color: var(--text); font: inherit; font-size: var(--fs-base); padding: 0 6px; }
.ef-choice[hidden] { display: none; }
.ef-note { margin: 0 0 calc(10 * var(--sp)); padding: calc(10 * var(--sp)) calc(12 * var(--sp)); border-radius: var(--r-sm); background: var(--glass); color: var(--text2); font-size: var(--fs-base); line-height: 1.45; }
.ef-mouse { padding: calc(8 * var(--sp)) 0; }
.ef-mouse > summary { cursor: pointer; color: var(--text2); font-size: var(--fs-base); min-height: 32px; display: flex; align-items: center; }
/* A disclosure says it is one (judge 1.7): a caret that turns when it opens. */
.ef-mouse > summary { list-style: none; gap: 10px; }
.ef-mouse > summary::-webkit-details-marker { display: none; }
.ef-mouse > summary::before {
  content: ''; flex: none; width: 7px; height: 7px; margin: 0 2px 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); transition: transform .15s var(--ease, ease);
}
.ef-mouse[open] > summary::before { transform: rotate(45deg); margin-bottom: 4px; }
/* Keyboard hints mean nothing on a phone (judge 1.7). */
html[data-narrow] .stg-kbdhint { display: none; }

/* A wide dialog: the switches in one column, the preview beside them, sticky, so whichever row
   you are on is playing next to it however far down it is. */
@media (min-width: 900px) {
  html:not([data-narrow]) .ef-main { grid-template-columns: minmax(0, 1fr) minmax(240px, 300px); column-gap: 24px; }
  html:not([data-narrow]) .ef-preview { order: 2; top: 0; padding: calc(10 * var(--sp)) 0 0; margin-inline: 0; box-shadow: none; background: none; }
  .ef-top .lp-press { display: none; }
  .ef-top .lp-pre { padding: calc(6 * var(--sp)) calc(10 * var(--sp)); gap: 1px; }
  .ef-stage.fx-stage, .ef-stage.fx-stage.fx-cards, .ef-stage.fx-stage.fx-sweep { height: 142px; }
}

/* N39: the presets keep a place for the Custom card, so a switch that makes one does not add a
   row and shove every switch down under the pointer: four across on a wide dialog, two by two
   on a narrower one and on a phone. */
.stg .ef-top .lp-presets { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 900px) {
  html:not([data-narrow]) .stg .ef-top .lp-presets { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
}

/* ================= first run ================= */
.stg-fr { width: min(760px, calc(100vw - 32px)); }
.stg-fr .modal-body { display: grid; gap: 6px; }
.stg-fr .fr-x { margin-left: auto; }

/* ================= phone: a list that pushes a page ================= */
html[data-narrow] .modal-ov:has(> .modal.stg-modal) { padding: 0; align-items: stretch; }
html[data-narrow] .modal-ov > .modal.stg-modal {
  width: 100%; max-width: 100%; border-radius: 0; border: 0;
  /* Divided by the UI zoom: 100dvh is measured before `zoom`, so at 1.1 the sheet ran ~78 px
     past the screen foot and the last row of every page could not be reached (judges 17.10). */
  height: calc(100dvh / var(--ui-z, 1)); max-height: calc(100dvh / var(--ui-z, 1));
}
html[data-narrow] .modal-ov > .modal.stg-modal > .modal-body { max-height: none; height: auto; }
html[data-narrow] .stg { grid-template-columns: minmax(0, 1fr); }
html[data-narrow] .stg-side { border-right: 0; padding: calc(12 * var(--sp)) calc(12 * var(--sp)); }
html[data-narrow] .stg[data-view="page"] > .stg-side { display: none; }
html[data-narrow] .stg[data-view="list"] > .stg-page { display: none; }
html[data-narrow] .stg-item { min-height: 48px; font-size: calc(var(--fs-base) + 1px); }
html[data-narrow] .stg-chev { display: grid; place-items: center; width: 16px; height: 16px; color: var(--dim); }
html[data-narrow] .stg-chev > svg { width: 14px; height: 14px; }
html[data-narrow] .stg-item.on { background: none; color: var(--text2); font-weight: inherit; }
html[data-narrow] .stg-item.on > i { color: var(--dim); }
html[data-narrow] .stg-back { display: inline-grid; }
html[data-narrow] .stg-ph { padding: calc(10 * var(--sp)) calc(10 * var(--sp)) calc(2 * var(--sp)); }
html[data-narrow] .stg-body { padding: calc(4 * var(--sp)) calc(16 * var(--sp)) calc(24 * var(--sp)); }
html[data-narrow] .stg-slash { display: none; }
html[data-narrow] .stg-row { flex-wrap: wrap; gap: 8px 12px; }
html[data-narrow] .stg-ctl { max-width: 100%; }
html[data-narrow] .lp-themes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
html[data-narrow] .stg-rs .rs-shapes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Pinned above the list on a phone, so a little shorter: it shares the screen with the switches. */
html[data-narrow] .ef-stage.fx-stage, html[data-narrow] .ef-stage.fx-stage.fx-cards, html[data-narrow] .ef-stage.fx-stage.fx-sweep { height: 116px; }
html[data-narrow] .ef-preview { top: calc(-4 * var(--sp)); padding: calc(4 * var(--sp)) calc(16 * var(--sp)) calc(8 * var(--sp)); margin-inline: calc(-16 * var(--sp)); }
/* data-narrow rather than a width query: a media query meets the UI zoom (see test/firstrun.js). */
html[data-narrow] .lp-presets { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* First run on a phone (judges 17.10.2026): three minis to a row, names only, and each effect
   preset as one row (its press demo, the name, its one line) rather than losing the line. */
html[data-narrow] .stg-fr .lp-themes { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
html[data-narrow] .stg-fr .lp-flags { display: none; }
html[data-narrow] .stg-fr .lp-nm { font-size: var(--fs-sm); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html[data-narrow] .stg-fr .lp-presets { grid-template-columns: minmax(0, 1fr); gap: 6px; }
html[data-narrow] .stg-fr .lp-pre { grid-template-columns: 44px minmax(0, 1fr); column-gap: 10px; row-gap: 0; align-items: center; padding: calc(7 * var(--sp)) calc(10 * var(--sp)); }
html[data-narrow] .stg-fr .lp-press { grid-row: 1 / 3; height: 30px; margin: 0; }
html[data-narrow] .stg-fr .lp-pre .lp-nm { font-size: var(--fs-base); }

@media (prefers-reduced-motion: reduce) {
  .stg-ring::after { animation: none; }
  .lp-press > s { transition: none; }
}
