/* ==========================================================================
   Guitar Tuner

   Visual direction: the inside of a guitar case. Deep green felt, aged nickel
   for the wire and the type, brass for anything active. The six strings along
   the bottom are drawn at true relative gauges and sit in the thumb zone,
   because on a phone that is where a hand actually reaches.
   ========================================================================== */

:root {
  /* Case interior */
  --case-deep:  #0A1618;
  --case:       #0F2224;
  --felt:       #17383A;
  --felt-edge:  #21504F;

  /* Hardware */
  --nickel:      #C6D3D0;
  --nickel-dim:  #7C918E;
  --nickel-faint:#4A5F5E;
  --brass:       #C9A227;
  --brass-bright:#E8C24E;
  --mint:        #7FE3C4;

  /* Numerals and readouts. Tabular figures are not a stylistic preference
     here: the deviation updates ~40 times a second, and proportional digits
     would make the whole line twitch sideways on every change. */
  --font-data: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  /* ui-rounded resolves to SF Pro Rounded on Apple platforms — a softer,
     instrument-dial letterform for the note itself. */
  --font-display: ui-rounded, -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;

  --edge: 0 1px 0 rgba(255, 255, 255, 0.045);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* 页面下方的静态说明区沿用主站的暖纸色设计语言。
     本文件是自包含的（不引 css/style.css），所以这里自带一份对应的令牌；
     改动这些值等于改动全站色调，别单独调。 */
  --paper:       #f5f0e7;
  --paper-deep:  #ece3d3;
  --ink:         #221d17;
  --ink-soft:    #4c453a;
  --line:        rgba(34, 29, 23, 0.14);
  --accent:      #9a6b3f;
  --accent-deep: #7a4f2a;
  --font-serif:  "Songti SC", "Noto Serif SC", "STSong", "SimSun", Georgia, "Times New Roman", serif;
  --font-body:   "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--case-deep);
}

body {
  font-family: var(--font-ui);
  color: var(--nickel);
  /* Stops the double-tap-to-zoom delay and the grey flash on tap in Safari. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
  /* 这里原本是 overflow:hidden（调音器单屏铺满）。现在页面底部有一块静态说明
     文字需要能滚到，所以放开纵向滚动；调音器本身仍是整屏高（见 .app）。 */
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Shell ───────────────────────────────────────────────────────────── */

.app {
  position: relative;
  display: flex;
  flex-direction: column;
  /* 用 min-height 而不是 height：屏幕上仍是一整屏，但内容不会被裁掉，
     页面下方还有说明区时也能正常滚动。 */
  min-height: 100vh;
  min-height: 100dvh; /* survives Safari's collapsing toolbar */
  padding:
    calc(env(safe-area-inset-top) + 0.75rem)
    calc(env(safe-area-inset-right) + 1.25rem)
    calc(env(safe-area-inset-bottom) + 0.75rem)
    calc(env(safe-area-inset-left) + 1.25rem);
  /* A soft pool of light behind the readout, like a case lid opened under a
     lamp — keeps the flat background from reading as a plain dark theme. */
  background:
    radial-gradient(120% 55% at 50% 6%, #16302F 0%, rgba(10, 22, 24, 0) 68%),
    var(--case-deep);
}

/* ── Top bar ─────────────────────────────────────────────────────────── */

.topbar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex: none;
}

/* The wordmark is a <p>, not an <h1>: the page's single h1 is the
   "吉他在线调音器" heading in the static section below. */
.wordmark {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--nickel-dim);
}

.status {
  margin: 0;
  font-family: var(--font-data);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nickel-faint);
  display: flex;
  align-items: center;
  gap: 0.5em;
}

.status::before {
  content: "";
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

[data-state="listening"] .status { color: var(--brass); }
[data-state="listening"] .status::before { animation: pulse 2s var(--ease) infinite; }
[data-state="error"] .status { color: var(--nickel-dim); }

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.25; }
}

/* ── Readout ─────────────────────────────────────────────────────────── */

.readout {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(0.5rem, 2.5vh, 1.25rem);
  min-height: 0;
}

.note {
  display: flex;
  align-items: flex-start;
  line-height: 0.82;
  color: var(--nickel);
  transition: color 260ms var(--ease);
}

.note-letter {
  font-family: var(--font-display);
  font-size: clamp(4.5rem, 24vw, 8.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.note-octave {
  font-family: var(--font-data);
  font-size: clamp(1rem, 4.5vw, 1.5rem);
  font-weight: 500;
  color: var(--nickel-faint);
  margin-top: 0.35em;
  margin-left: 0.15em;
}

[data-tuned="true"] .note { color: var(--mint); }
[data-signal="false"] .note-letter { color: var(--nickel-faint); }

/* ── Meter ───────────────────────────────────────────────────────────── */

.meter {
  width: 100%;
  max-width: 26rem;
  height: clamp(3.5rem, 11vh, 4.875rem);
  flex: none;
  overflow: visible;
}

.meter-ticks line {
  stroke: var(--nickel-faint);
  stroke-width: 1;
}

.meter-ticks line.major { stroke: var(--nickel-dim); }

.meter-ticks text {
  fill: var(--nickel-faint);
  font-family: var(--font-data);
  font-size: 9px;
  letter-spacing: 0.06em;
  text-anchor: middle;
}

/* The ±5 cent target. This is the thing you are aiming at, so it is drawn as a
   filled band rather than a hairline outline — at arm's length a dashed 1px
   rectangle on a dark background is invisible. */
.meter-zone {
  fill: color-mix(in srgb, var(--nickel) 9%, transparent);
  stroke: var(--nickel-dim);
  stroke-width: 1;
  transition: stroke 260ms var(--ease), fill 260ms var(--ease);
}

[data-tuned="true"] .meter-zone {
  stroke: var(--mint);
  fill: color-mix(in srgb, var(--mint) 22%, transparent);
}

.meter-centre {
  stroke: var(--nickel);
  stroke-width: 1.5;
}

.meter-marker {
  fill: var(--brass);
  stroke: var(--brass);
  stroke-width: 2;
  stroke-linecap: round;
  transition: opacity 200ms var(--ease);
}

[data-tuned="true"] .meter-marker { fill: var(--mint); stroke: var(--mint); }
[data-signal="false"] .meter-marker { opacity: 0.18; }

/* ── Guidance + data ─────────────────────────────────────────────────── */

.guidance {
  margin: 0;
  font-family: var(--font-ui);
  font-size: clamp(0.9375rem, 4vw, 1.125rem);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass);
  text-align: center;
  min-height: 1.4em;
  transition: color 260ms var(--ease);
}

[data-tuned="true"] .guidance { color: var(--mint); }
[data-signal="false"] .guidance { color: var(--nickel-faint); }

.data {
  display: flex;
  gap: clamp(1.25rem, 7vw, 2.75rem);
  margin: 0;
  flex: none;
}

.data-cell { text-align: center; }

.data dt {
  font-family: var(--font-ui);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nickel-faint);
  margin-bottom: 0.35em;
}

.data dd {
  margin: 0;
  font-family: var(--font-data);
  font-size: clamp(0.9375rem, 4.2vw, 1.125rem);
  font-variant-numeric: tabular-nums;
  color: var(--nickel);
}

.data dd i {
  font-style: normal;
  font-size: 0.75em;
  color: var(--nickel-faint);
}

/* ── Strings ─────────────────────────────────────────────────────────── */

.strings {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-bottom: 0.75rem;
}

.string {
  /* A row, not a pill: the string *is* the control. */
  display: grid;
  grid-template-columns: 2.5rem 1fr 2.75rem;
  align-items: center;
  gap: 0.75rem;
  /* 44px minimum target height, per Apple's guidance. */
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.string-name {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
  color: var(--nickel-faint);
  transition: color 200ms var(--ease);
}

.string-name i {
  font-family: var(--font-data);
  font-style: normal;
  font-size: 0.6em;
  font-weight: 500;
  opacity: 0.65;
  vertical-align: 0.35em;
  margin-left: 0.08em;
}

/* Gauges stay visible on every row: they are what separates the two E strings,
   and one number appearing on only the active row reads as a rendering fault. */
.string-gauge {
  font-family: var(--font-data);
  font-size: 0.625rem;
  text-align: right;
  color: var(--nickel-faint);
  opacity: 0.45;
  font-variant-numeric: tabular-nums;
  transition: color 200ms var(--ease), opacity 200ms var(--ease);
}

.string-wire {
  display: block;
  width: 100%;
  height: 1.75rem;
  overflow: visible;
}

.string-wire path {
  fill: none;
  stroke: var(--nickel-faint);
  stroke-linecap: round;
  transition: stroke 220ms var(--ease);
}

/* The winding on the three wound strings — a fine overlay, barely there,
   but it is the difference between six lines and six *strings*. */
.string-wire path.winding {
  stroke: var(--case-deep);
  stroke-dasharray: 0.8 2.2;
  opacity: 0.55;
}

/* "Active" is the string currently sounding — set by detection, whether it was
   chosen automatically or pinned. */
.string[data-active="true"] .string-name { color: var(--brass); }
.string[data-active="true"] .string-gauge { opacity: 1; }
.string[data-active="true"] .string-wire path { stroke: var(--brass); }

/* "Pressed" is the string the user pinned, which is a different thing: it stays
   marked while silent, so the dot answers "why is it only listening for D?" */
.string[aria-pressed="true"] .string-name {
  color: var(--brass);
  position: relative;
}

.string[aria-pressed="true"] .string-name::before {
  content: "";
  position: absolute;
  left: -0.75rem;
  top: 50%;
  width: 0.3125rem;
  height: 0.3125rem;
  margin-top: -0.15625rem;
  border-radius: 50%;
  background: currentColor;
}

.string[data-tuned="true"] .string-name,
.string[data-tuned="true"] .string-gauge { color: var(--mint); }
.string[data-tuned="true"] .string-wire path { stroke: var(--mint); }

.string:focus-visible {
  outline: 2px solid var(--brass-bright);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ── Controls ────────────────────────────────────────────────────────── */

.controls {
  flex: none;
  display: flex;
  gap: 0.625rem;
}

.btn {
  min-height: 3rem;
  padding: 0 1.5rem;
  border-radius: 0.625rem;
  border: 1px solid transparent;
  font-family: var(--font-ui);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: background-color 180ms var(--ease), color 180ms var(--ease),
              border-color 180ms var(--ease), transform 120ms var(--ease);
}

.btn:active { transform: scale(0.98); }

.btn:focus-visible {
  outline: 2px solid var(--brass-bright);
  outline-offset: 2px;
}

.btn-primary {
  flex: 1;
  background: var(--brass);
  color: #16120A;
  box-shadow: var(--edge);
}

.btn-ghost {
  flex: none;
  background: var(--felt);
  border-color: var(--felt-edge);
  color: var(--nickel-dim);
}

.btn-ghost[aria-pressed="true"] {
  color: var(--brass);
  border-color: color-mix(in srgb, var(--brass) 45%, transparent);
  background: color-mix(in srgb, var(--brass) 10%, var(--felt));
}

[data-state="listening"] .btn-primary {
  background: transparent;
  border-color: var(--felt-edge);
  color: var(--nickel-dim);
}

/* ── Notices ─────────────────────────────────────────────────────────── */

.notice {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.875rem;
  padding: 2rem;
  text-align: center;
  background: color-mix(in srgb, var(--case-deep) 94%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

.notice[hidden] { display: none; }

.notice-static { position: fixed; }

.notice-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--nickel);
}

.notice-body {
  margin: 0;
  max-width: 26rem;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--nickel-dim);
}

.notice .btn { margin-top: 0.5rem; }

.notice-diagnostics {
  margin: 0.25rem 0 0;
  font-family: var(--font-data);
  font-size: 0.6875rem;
  line-height: 1.5;
  color: var(--nickel-faint);
  /* Long enough to wrap on a phone, and worth selecting to paste into a bug
     report, so it stays selectable unlike the rest of the chrome. */
  -webkit-user-select: text;
  user-select: text;
  max-width: 22rem;
}

.notice-diagnostics[hidden] { display: none; }

/* ── Landscape and larger screens ────────────────────────────────────── */

@media (min-width: 40rem) {
  .app { max-width: 34rem; margin-inline: auto; }
}

/* Short viewports — phone in landscape. Drop the least load-bearing rows
   rather than letting the strings scroll out of reach. */
@media (max-height: 32rem) and (orientation: landscape) {
  .note-letter { font-size: clamp(3rem, 13vh, 4.5rem); }
  .data { display: none; }
  .readout { gap: 0.375rem; }
  .string { min-height: 2.25rem; }
  .string-wire { height: 1.25rem; }
}

/* ── Motion preferences ──────────────────────────────────────────────── */

/* The travelling wave is switched off in tuner.js when this is set; the string
   still shows deviation as a static bow, so no information is lost. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ==========================================================================
   页面静态说明（调音器下方）

   调音器本身只有一个巨大的音名和一条指针，正常状态下几乎没有可读文字。
   这一段是给不吃 JS 的访客与搜索引擎准备的静态内容，因此完全用普通
   HTML 写死、不依赖脚本。视觉上切回主站的暖纸色，让它明确区别于
   上方那台「仪表」——用户一眼能看出哪里是工具、哪里是说明。
   ========================================================================== */

.info {
  --measure: 44rem;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.85;
  padding:
    3rem
    max(1.25rem, env(safe-area-inset-right))
    calc(4rem + env(safe-area-inset-bottom))
    max(1.25rem, env(safe-area-inset-left));
}

.info > * {
  max-width: var(--measure);
  margin-inline: auto;
}

.info h1 {
  margin: 0 auto 1.5rem;
  font-family: var(--font-serif);
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1.4;
  color: var(--ink);
}

/* 与主站的 .rule 同一手法：标题下的短古铜细线 */
.info h1::after {
  content: "";
  display: block;
  width: 56px;
  height: 2px;
  margin-top: 1rem;
  border-radius: 2px;
  background: var(--accent);
}

.info h2 {
  margin: 2.75rem auto 0.875rem;
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  line-height: 1.5;
  color: var(--ink);
}

.info p { margin: 0 auto 1rem; }

.info ul,
.info ol {
  margin: 0 auto 1rem;
  padding-left: 1.35rem;
}

.info li { margin-bottom: 0.4rem; }

.info ul { list-style: disc; }
.info ol { list-style: decimal; }

/* 六弦频率表那种「名称 + 数值」的行，换成等宽数字对齐 */
.info ul li::marker { color: var(--accent); }
.info ol li::marker { color: var(--accent); font-variant-numeric: tabular-nums; }

.info dl { margin: 0 auto 1rem; }

.info dt {
  margin-top: 1.25rem;
  font-weight: 700;
  color: var(--ink);
}

.info dd {
  margin: 0.35rem 0 0;
  padding-left: 1rem;
  border-left: 2px solid var(--line);
  color: var(--ink-soft);
}

.info strong {
  font-weight: 700;
  color: var(--ink);
}

.info a {
  color: var(--accent-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(154, 107, 63, 0.45);
  transition: color 160ms var(--ease), text-decoration-color 160ms var(--ease);
}

.info a:hover {
  color: var(--accent);
  text-decoration-color: currentColor;
}

.info a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

@media (min-width: 40rem) {
  .info { font-size: 1.0625rem; padding-top: 3.5rem; }
  .info h1 { font-size: 2rem; }
  .info h2 { font-size: 1.375rem; }
}
