/*
 * The phone screen.
 *
 * Dark by default because the app is used in the same moments the glasses are — outdoors,
 * quickly, one-handed — and because the lens preview is green on black and a page that
 * frames it in white makes the preview look like a photograph of a different device.
 *
 * The controls are large. Not for style: the wearer is holding a phone in one hand while
 * talking to a stranger, and every control on this page has a version that is a tap on the
 * glasses precisely because looking down at a phone is the thing being avoided.
 */

:root {
  --bg: #0b0d10;
  --card: #14181d;
  /*
   * A surface *inside* a card: inputs, the log, one saved conversation. It has to be a
   * token rather than a literal, because the light theme below only redefines tokens —
   * a hard-coded dark hex survives into the light theme and puts near-black text on a
   * near-black box. That is exactly what happened to the record list.
   */
  --sunken: #0e1216;
  --line: #232a32;
  --text: #e9eef4;
  --dim: #9aa7b4;
  --accent: #4da3ff;
  --accent-ink: #04121f;
  --warn: #ffb454;
  --bad: #ff6b6b;
  --radius: 14px;

  /* The lens, at the pixel size the glasses actually grant. See bridge.js. */
  --lens-w: 864px;
  --lens-h: 432px;
  /*
   * A half-width cell is 864/56 ≈ 15.43px and a card line is 43px (both measured on the
   * device). The font size below is the one that puts a monospace advance on that pitch;
   * it is an approximation of the lens, not the lens. The authority on whether a line fits
   * is `wrap.js`, which counts cells — this preview only has to look like the answer.
   */
  --lens-font: 25.5px;
  --lens-line: 43px;
  /*
   * The lens is green on black, and it stays green on black in both themes: this block is
   * a picture of the glasses, not part of the phone's chrome. `#4bb565` is Even Realities'
   * own TC-Green from the companion-app palette — the same value the HUD preview in
   * people-i-know uses, so the two apps show the same display.
   */
  --lens-ink: #4bb565;
  --lens-bg: #000000;

  /*
   * 文字サイズ (`prefs.js`, `TEXT_SCALE`). Set on the root from `renderTextSize`.
   *
   * **Every rule that draws a sentence multiplies by this, and nothing else does.** The two
   * groups are not a matter of taste: a card heading or a hint that grew with the sentences
   * would push the words out of the buttons they are written in, an input under 16px makes
   * iOS zoom the page on focus and never zoom back, and the lens preview is a picture of the
   * glasses — 864px drawn at their size and scaled as a whole — so a preview that grew would
   * be showing the wearer a screen they will not get. The `1` fallback is the size every
   * screen in this file was measured at.
   */
  --text-scale: 1;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, 'Hiragino Sans', 'Noto Sans JP', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
}

.bar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 12px 16px calc(12px + env(safe-area-inset-top, 0px));
  background: rgba(11, 13, 16, 0.94);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(8px);
}

.bar h1 {
  margin: 0;
  font-size: 18px;
  letter-spacing: 0.04em;
}

.status {
  margin: 0;
  font-size: 12px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

/*
  文字サイズ。A pill pushed to the far right of the header, so it is in the corner your thumb
  is already near and never in the way of the status line, which wraps to two lines on a
  narrow phone. `flex: none` so it keeps its size while the status gives up width.
*/
.sizer {
  margin-left: auto;
  flex: none;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: 999px;
}

.sizer button {
  min-width: 34px;
  padding: 4px 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font: inherit;
  line-height: 1;
  cursor: pointer;
}

/* 小 and 大 are the same two characters at two sizes — the control says what it does
   without a label, which is the whole reason it can live in a corner this small. */
.sizer [data-text-down] {
  font-size: 12px;
}

.sizer [data-text-up] {
  font-size: 17px;
}

/* At either end there is nothing left to do, and a button that still looks pressable is one
   somebody presses twice before believing it. */
.sizer button:disabled {
  opacity: 0.35;
  cursor: default;
}

.sizer span {
  min-width: 1em;
  text-align: center;
  font-size: 11px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

.status[data-state='ok'] {
  color: var(--accent);
}

.status[data-state='mock'] {
  color: var(--warn);
}

main {
  padding: 12px 16px 24px;
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.card,
details.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
}

.card h2,
details.card summary {
  margin: 0 0 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--dim);
  letter-spacing: 0.04em;
}

details.card summary {
  cursor: pointer;
  margin: 0;
}

details.card[open] summary {
  margin-bottom: 10px;
}

/* A group inside a card: the live screen's three bands belong together, and one label
   each would read as three unrelated settings. */
.card h3 {
  margin: 18px 0 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--dim);
  letter-spacing: 0.04em;
}

/*
  The halves of 音声チャット are one card with a line between them, because the danger there
  is not finding the box — it is typing your own sentence into the other person's. A rule
  and a heading are what make 「上」 and 「下」 two places rather than one long list.
*/
.card h3.split {
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* With 「自分が言うこと」 away there is nothing above it to be divided from, and a rule
   directly under the card's own title divides it from the title. */
[data-pins][hidden] + .split {
  padding-top: 0;
  border-top: 0;
}

/* Inside a half, where a rule would divide something already divided. */
.card h4 {
  margin: 14px 0 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--dim);
  letter-spacing: 0.04em;
}

/*
  Folded away inside a card: 探す and 自分の文, which are opened when the first two rows did
  not have it. Flat rather than a card inside a card — a second border around a third of the
  screen reads as a second card, and this page already answers for its cards.
*/
.drawer {
  margin-top: 12px;
}

.drawer > summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--dim);
}

/* The demonstration sentences, which 「聴覚発話サポート」 takes away. `display:flex` below
   beats the attribute's own `display:none`, so it is said again here. */
.samples[hidden] {
  display: none;
}

.hint {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--dim);
}

/* 言語モード ------------------------------------------------------------- */

/*
  The language picker, which is a `.field` that gives its select the rest of the line. In
  the settings card a select sits next to a short label and looks fine narrow; here it is
  the control the wearer changes on the way into a conversation, so it takes the width.
*/
.field.wide {
  padding: 0 0 12px;
}

.field.wide select {
  flex: 1;
  min-width: 0;
}

/* 聞くボタン ------------------------------------------------------------- */

.listen {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 14px;
  border: 1px solid var(--accent);
  border-radius: 12px;
  background: transparent;
  color: var(--text);
  font: inherit;
  cursor: pointer;
}

.listen-label {
  font-size: 20px;
  font-weight: 700;
}

/*
  Listening. The colour of the old stop button, because that is what this button now is:
  the one control on the page somebody presses in a hurry, and it should not need reading
  twice to be sure of.
*/
.listen[data-on='true'] {
  background: var(--warn);
  border-color: var(--warn);
  color: var(--accent-ink);
}

/*
  Listen and speak, side by side. Flex rather than two fixed columns: 「日本語で話す」 is
  hidden on the routes that do not need it, and a grid would leave its half empty.
*/
.talk {
  display: flex;
  gap: 8px;
}

.talk .listen {
  flex: 1;
  min-width: 0;
}

/* The second of the pair, and visibly the second: same shape, quieter edge. */
.speak {
  border-color: var(--line);
}

.speak .listen-label {
  color: var(--dim);
}

.meter {
  height: 6px;
  margin-bottom: 12px;
  border-radius: 3px;
  background: var(--line);
  overflow: hidden;
}

.meter-fill {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 80ms linear;
}

.line {
  margin: 8px 0 0;
  min-height: 1.6em;
  font-size: calc(14px * var(--text-scale, 1));
  color: var(--dim);
}

/* レンズのプレビュー ------------------------------------------------------ */

/*
 * Drawn at the glasses' own pixel size and then scaled down as a whole, rather than laid
 * out at phone size. Anything else is a picture of a different display: the wrapping, the
 * row heights and the number of lines that fit are the things being previewed, and they
 * only mean something at 864×432.
 */
.lens-frame {
  width: 100%;
  aspect-ratio: 2 / 1;
  overflow: hidden;
  border-radius: 10px;
  background: var(--lens-bg);
  border: 1px solid var(--line);
  container-type: inline-size;
}

.lens {
  position: relative;
  width: var(--lens-w);
  height: var(--lens-h);
  transform-origin: 0 0;
  /* 864px wide, scaled to whatever the card is. Set from main.js on resize. */
  transform: scale(var(--lens-scale, 0.4));
  color: var(--lens-ink);
  font-family: ui-monospace, 'SF Mono', 'Menlo', 'Consolas', 'Noto Sans Mono CJK JP', monospace;
}

.lens-card {
  position: absolute;
  inset: 0;
  padding: 0;
  white-space: pre;
  font-size: var(--lens-font);
  line-height: var(--lens-line);
}

.pad {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-top: 12px;
}

.pad button,
.secondary,
.row button,
.samples button {
  padding: 12px 6px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.secondary {
  width: 100%;
  margin-top: 10px;
  color: var(--dim);
}

/* 入力 ------------------------------------------------------------------- */

.row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/*
 * **`.secondary` is full-width on its own line — and one of several inside a row.**
 *
 * The class means 「the quiet alternative to the thing above it」, and on its own that is a
 * button spanning the card under a paragraph. In a `.row` the same 100% makes every button
 * wrap onto a line of its own: reported for [取込][閲覧][消去], and true of the backup
 * card's three from the day it was written.
 */
.row .secondary {
  width: auto;
  margin-top: 0;
}

/*
 * A button says its label on one line or goes to the next row — it never sets its text
 * vertically. Three buttons with long labels in a narrow card did exactly that: 「今すぐ
 * バックアップ」 came out as one character per line, in a column the height of the card.
 */
.row button {
  white-space: nowrap;
  flex: 1 1 auto;
}

/*
 * A row where the button is only as wide as its label. The default shares the width between
 * the two, which is right for 「すべて書き出す」「すべて消す」 — a pair of equals — and wrong
 * for a box you type a sentence into next to a two-character button.
 */
.row.tight button {
  flex: 0 0 auto;
  padding-left: 18px;
  padding-right: 18px;
}

.row input {
  flex: 1;
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--sunken);
  color: var(--text);
  font: inherit;
  font-size: 16px; /* under 16px, iOS zooms the page on focus and never zooms back */
}

.samples {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}

.samples button {
  padding: 8px 10px;
  font-size: calc(13px * var(--text-scale, 1));
  color: var(--dim);
}

/* 会話 ------------------------------------------------------------------- */

.turns {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.turns:empty::after {
  content: 'まだ何も聞いていません。';
  color: var(--dim);
  font-size: 13px;
}

.turn {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--sunken);
  cursor: pointer;
  text-align: left;
  width: 100%;
  color: inherit;
  font: inherit;
}

.turn[data-speaker='user'] {
  border-left: 3px solid var(--accent);
}

.turn-meta {
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.06em;
}

.turn-main {
  font-size: calc(15px * var(--text-scale, 1));
}

.turn-sub {
  font-size: calc(13px * var(--text-scale, 1));
  color: var(--dim);
}

/* よくある文の初期データ --------------------------------------------------- */

/*
 * The scenes, as things to tick. A wrapping row of chips rather than a column of checkboxes:
 * eight of them down the card is a screen of its own, and what the wearer is doing here is
 * glancing at a set and touching two of them.
 */
.scenes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0 10px;
}

.scene {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
  cursor: pointer;
}

.scene input {
  margin: 0;
}


/*
 * A window, not a page. The pack runs to a few hundred phrases and this card sits in the
 * middle of a long page — laid out in full it would push everything below it out of reach,
 * so it scrolls inside its own box and the page keeps its shape.
 */
.book {
  margin-top: 10px;
  max-height: 320px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--sunken);
  padding: 4px 0;
  -webkit-overflow-scrolling: touch;
}

.book:empty::after {
  content: 'まだ取り込んでいません。';
  display: block;
  padding: 12px;
  color: var(--dim);
  font-size: 13px;
}

/* The scene's name, once, above the phrases that belong to it. */
.book-scene {
  margin: 0;
  padding: 10px 12px 4px;
  border-top: 1px solid var(--line);
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
}

.book-scene:first-child {
  border-top: 0;
}

/* How many times it has actually come up. Absent until it has. */
.book-hits {
  font-size: 11px;
  color: var(--dim);
}

.book-entry {
  padding: 10px 12px;
  border-top: 1px solid var(--line);
}

.book-entry:first-child {
  border-top: 0;
}

/* Under a scene heading the line is already drawn by the heading. */
.book-scene + .book-entry {
  border-top: 0;
}

/* What the other person says, and what it means. The pair that is looked up. */
.book-text {
  margin: 0;
  font-size: calc(13px * var(--text-scale, 1));
  line-height: 1.5;
}

.book-ja {
  margin: 2px 0 0;
  font-size: calc(13px * var(--text-scale, 1));
  line-height: 1.5;
  color: var(--dim);
}

/* The replies, indented the way the lens indents them. */
.book-answer {
  margin: 6px 0 0 12px;
  font-size: calc(12px * var(--text-scale, 1));
  line-height: 1.5;
  color: var(--dim);
}

.book-answer b {
  font-weight: 600;
  color: var(--text);
}

/* 記録 ------------------------------------------------------------------- */

.records {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.records:empty::after {
  content: 'まだ記録がありません。';
  color: var(--dim);
  font-size: 13px;
}

.record {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--sunken);
  padding: 10px 12px;
}

/*
 * One line while closed.
 *
 * `display: flex` is what makes it one line, and it costs the native disclosure triangle:
 * a flex `<summary>` has no list marker, so the arrow below is ours. That is the trade —
 * the browser's own marker sits on a line of its own above a block title, which is most of
 * the empty space this list used to have.
 */
.record summary {
  display: flex;
  align-items: baseline;
  gap: 8px;
  cursor: pointer;
  font-size: 14px;
  margin: 0;
  color: var(--text);
  list-style: none;
}

.record summary::-webkit-details-marker {
  display: none;
}

.record summary::before {
  content: '▶';
  flex: none;
  display: inline-block;
  font-size: 9px;
  line-height: 1;
  color: var(--dim);
  transition: transform 0.12s ease;
}

.record[open] summary::before {
  transform: rotate(90deg);
}

/*
 * The sentence takes whatever room the timestamp leaves, and is cut rather than wrapped.
 * `min-width: 0` is not optional: without it a flex item refuses to shrink below its
 * content and the ellipsis never appears — the timestamp is pushed off the edge instead.
 */
.record-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
  font-weight: 600;
}

.record-when {
  flex: none;
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

.record-lines {
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid var(--line);
  padding-top: 10px;
}

.record-line {
  display: flex;
  gap: 8px;
  font-size: calc(14px * var(--text-scale, 1));
}

.record-line[data-speaker='user'] {
  /* The wearer's own turns, set off so the two voices are tellable apart at a glance. */
  padding-left: 8px;
  border-left: 2px solid var(--accent);
}

.record-clock {
  flex: none;
  width: 3.2em;
  color: var(--dim);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  padding-top: 3px;
}

.record-foreign {
  color: var(--dim);
  font-size: calc(13px * var(--text-scale, 1));
}

.record-actions {
  display: flex;
  gap: 6px;
  margin-top: 10px;
}

.record-actions button {
  flex: 1;
  padding: 8px;
  font-size: 13px;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 8px;
  background: transparent;
  font-family: inherit;
  cursor: pointer;
}

.export {
  width: 100%;
  margin-top: 10px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--sunken);
  color: var(--text);
  font-family: ui-monospace, monospace;
  font-size: 12px;
  resize: vertical;
}

/* 設定 ------------------------------------------------------------------- */

.field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
}

.field span {
  font-size: 14px;
}

.field select,
.fields input {
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--sunken);
  color: var(--text);
  font: inherit;
  font-size: 16px;
}

.check {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  font-size: 14px;
}

.check input {
  width: 20px;
  height: 20px;
  accent-color: var(--accent);
}

.fields {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.fields label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--dim);
}

.phrases {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: calc(14px * var(--text-scale, 1));
}

.phrases b {
  font-weight: 600;
}

.phrases span {
  display: block;
  color: var(--dim);
  font-size: calc(13px * var(--text-scale, 1));
}

/* 「この言語のオフライン文はまだありません」 — the panel's answer, not its absence. */
.phrases .empty {
  color: var(--dim);
  font-size: calc(13px * var(--text-scale, 1));
}

/* 回答候補 -------------------------------------------------------------- */

.replies {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/*
  A row, not a row of buttons. The whole thing is the button — 「言いづらいとき」 is somebody
  reaching for their phone mid-conversation, and a 24px speaker icon is a target they have to
  aim at. The icon says what pressing does; the row is what gets pressed.
*/
.reply {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
  padding: 10px 12px;
  /* The Japanese line inherits this; the two under it are set relative to their own base. */
  font-size: calc(15px * var(--text-scale, 1));
}

.reply-words {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.reply-words b {
  font-weight: 600;
}

.reply-words span {
  color: var(--dim);
  font-size: calc(13px * var(--text-scale, 1));
}

.reply-reading {
  /* The line the wearer actually reads out loud (§30). It is not a footnote to the sentence
     above it — it is the one of the two they can say — so it keeps the full colour. */
  color: var(--text) !important;
}

.reply-speak {
  font-size: 20px;
  line-height: 1;
  flex: none;
}

/* Being said now. The row it is on is the one the phone is talking from. */
.reply[data-speaking] {
  border-color: var(--accent);
}

/* 診断 ------------------------------------------------------------------- */

.measures {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 12px;
  margin: 0;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.measures dt {
  color: var(--dim);
}

.measures dd {
  margin: 0;
  word-break: break-all;
}

.log {
  margin: 10px 0 0;
  padding: 10px;
  max-height: 240px;
  overflow: auto;
  background: var(--sunken);
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 11px;
  line-height: 1.5;
  white-space: pre-wrap;
  color: var(--dim);
}

.log .error {
  color: var(--bad);
}

.log .warn {
  color: var(--warn);
}

.build {
  margin: 0;
  text-align: center;
  font-size: 11px;
  color: var(--dim);
}

/*
 * The light theme, which is *only* a redefinition of the tokens above.
 *
 * That is the rule, and it used to be broken by a list of selectors patched one at a time
 * — which meant the theme was correct exactly for the surfaces somebody had remembered to
 * add to the list, and wrong for the two nobody had (the saved conversations and the
 * export box: near-black text on a near-black panel, invisible on a phone in light mode).
 * A new surface must not need an entry here to be readable; it needs `var(--sunken)`.
 */
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f4f6f8;
    --card: #ffffff;
    --sunken: #f7f9fb;
    --line: #dde3ea;
    --text: #12171d;
    --dim: #5d6b7a;
    --accent: #0b62d0;
    --accent-ink: #ffffff;
  }

  /* Not a token: the bar is translucent, so it needs the background as an rgba(). */
  .bar {
    background: rgba(244, 246, 248, 0.94);
  }
}

/* 定型文の「消す」。行の右、ボタンの外。押し間違えないよう文字は小さく、幅は指ぶん。 */
.pin-drop {
  width: auto;
  margin-top: 6px;
  padding: 6px 14px;
  font-size: 13px;
}

.replies li {
  display: flex;
  align-items: center;
  gap: 8px;
}

.replies li .reply {
  flex: 1;
  min-width: 0;
}
