/* GENERATED by design/ship.py from settings/settings.css -- DO NOT EDIT. That file is the master; run `python3 design/export.py --shell` and this one is rewritten. */
  /* The Library's palette, its header and its 44 px phone targets: this is a
     page of the same app, reached from the Library's gear and from the app's
     Settings menu item, and it must not look like somebody's dialog. */
  :root {
    --bg: #fcfcfb;
  /* ---- THE RADIUS SCALE (Osca, 30 Aug: "all boxes across all pages are just
     the wrong shape, wrong curve, not modern enough").
     Four files had grown ten different radii between them -- 3, 4, 6, 7, 8,
     10, 12, 14, 50% and 999px -- assigned per element as each was written, so
     no two boxes on a screen agreed and none of them agreed with the next
     screen. These four steps are the whole vocabulary now, and they are one
     step larger at every level than what they replace, which is most of what
     "modern" means here. A box picks the step for its ROLE, not its size:
       --r-0  a mark on running text (the word, the sentence highlight)
       --r-1  a control you press (button, input, select, small chip)
       --r-2  a surface that holds things (card, section, panel, header button)
       --r-3  a surface that floats over another (sheet, popup, menu)
     Anything outside these four is a deliberate exception and says why. ---- */
  --r-0: 5px;
  --r-1: 11px;
  --r-2: 15px;
  --r-3: 22px;
  --r-pill: 999px;
  /* The chrome's font, not the book's -- see reader.html's own note. */
  --ui-font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI Variable Text",
             "Segoe UI", Inter, system-ui, "Helvetica Neue", Arial, sans-serif;
 --fg: #0b0b0b; --fg-dim: #52514f; --accent: #832f2b;
    --border: #e4e3e0; --panel-bg: #ffffff; --link: #832f2b; --control-bg: #f5f5f3;
    --ok: #3f7a45; --bad: #a03328;
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
  }
  [data-theme="dark"] {
    --bg: #131316; --fg: #e8e7e6; --fg-dim: #98979b; --accent: #c9c4bb;
    --border: #2c2c32; --panel-bg: #1a1a1f; --link: #c9c4bb; --control-bg: #1a1a1f;
    --ok: #7fc08a; --bad: #d98a7a;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --bg: #131316; --fg: #e8e7e6; --fg-dim: #98979b; --accent: #c9c4bb;
      --border: #2c2c32; --panel-bg: #1a1a1f; --link: #c9c4bb; --control-bg: #1a1a1f;
      --ok: #7fc08a; --bad: #d98a7a;
    }
  }
  * { box-sizing: border-box; }
  html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg);
    font-family: var(--ui-font); height: 100%; }
  body { height: 100vh; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }

  /* THE TAB ROW *IS* THE TITLE BAR (Osca, 31 Aug: "Can we make the tab
     section headless? ... like Safari"). Not a bar beneath a bar: the
     traffic lights and the six icon tabs share one row, and there is no
     heading -- the window's own title says Settings, and saying it twice
     three centimetres apart was the page repeating its own chrome.

     THE LIGHTS' 80 px AT EACH END BELONG TO THE WINDOW, NOT THE PAGE. The
     left 80 px is where macOS draws the close/minimise/zoom buttons over an
     overlay title bar; the same 80 px is reserved on the right so the strip
     stays centred in the WHOLE window, which is where the picture puts it
     (the mock's dots are absolutely positioned and take the row's centre
     from nothing). Six tabs are 62 px each with a 2 px gap = 382 px, so at
     560 the strip runs 89..471 and never reaches either reservation.

     The lights themselves are NOT drawn here: they are the native window's,
     and until `settingswin.rs` opens this window with an overlay title bar
     (report §6) the row simply sits under the ordinary bar. A page that
     painted three coloured circles would be a picture of a title bar that
     does not close the window. */
  header { padding: 6px 80px; border-bottom: 1px solid var(--border);
    display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
    background: var(--control-bg); position: relative; min-height: 52px; }
  /* A hairline box around every icon in the bar is the single most dated
     thing on these pages: five outlined squares in a row read as a toolbar
     from 2012. The button is the icon; the surface only appears under the
     pointer, which is also the only moment it means anything. */
  header button, header .headerLink {
    min-height: 40px; min-width: 40px;
    border-radius: var(--r-1); border: 1px solid transparent;
    background: transparent; color: var(--fg-dim);
    font-size: 1rem; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    text-decoration: none;
    transition: background 0.14s, color 0.14s;
  }
  header button:hover, header .headerLink:hover {
    background: var(--control-bg); color: var(--fg);
  }
  header button:active, header .headerLink:active { transform: scale(0.96); }
  header button svg { display: block; }
  header button:focus-visible, header .headerLink:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 1px;
  }
  /* THE PHONE'S DOOR BACK TO THE LIBRARY (settings.html `#libraryDoor`):
     nothing on the Mac, where this page is a WINDOW and a window has no back
     (Osca, 31 Aug: no "< Library"). On the phone it is a page, and a page
     with no way out is a trap; THE PHONE WHOLE block at the foot shows the
     door under the phone's media query, and nowhere else. */
  #libraryDoor { display: none; font-size: 1.4rem; line-height: 1; }

  /* 22px all round, the mock's, and NO card around the whole form: every
     setting now sits in a card of its own (settings.js's `.set-card`) and a
     card inside a card is the wall of boxes the redraw was for.

     THE COLUMN IS 560 AND IT IS CENTRED (Osca, 1 Sep): *"The window opens far
     wider than the 560 the mock is drawn at, and the settings content has no
     max-width, so every card spans the whole pane and the controls strand at
     the right edge -- that's why it looks nothing like `mock/settings.html`."*

     It had a cap, and the cap was 640 -- near enough to be invisible at 560
     and useless at 900, where a card ran the width of a laptop screen with a
     segmented toggle marooned at the far end of it. 560 is the number the
     mock is drawn at, so at any window width the cards and their right-hand
     controls keep the proportions of the picture; at the window's own 560 the
     padding takes it in to 516 and the cap never binds, which is the case the
     mock actually shows.

     The other half of this is not ours: `settingswin.rs` opens the window at
     `DEFAULT_W = 560` already, but the remembered geometry restores whatever
     width the window was last dragged to. Report §6 asks for that to be
     clamped, so a window stretched once does not reopen stretched. */
  main { flex: 1 1 auto; min-height: 0; overflow-y: auto;
    padding: 20px calc(22px + var(--safe-right)) calc(26px + var(--safe-bottom)) calc(22px + var(--safe-left)); }
  main > * { max-width: 560px; margin-left: auto; margin-right: auto; }

  /* The preview is the setting: the same rules the reader's own .paneReading
     has, reading the same three custom properties, so what is drawn here is
     what a Reader tab will draw. */
  /* ONE LIVE PREVIEW CARD, not a rule across the panel: the mock draws it as
     a card of its own under Size & spacing, which is where a person reading
     down the Reading tab meets it. */
  /* The picture's card, to its own numbers (job 6): a 10px corner like every
     other card on the window, 16px of the reading face at 1.75, and 16/18 of
     padding. It was on the application's 15px radius and a `rem` size, which
     made it both rounder and larger than the one drawn -- and it is the one
     card on the tab a person looks at rather than reads past. */
  .preview {
    margin-top: 10px; border: 1px solid var(--border); border-radius: 10px;
    background: var(--panel-bg); padding: 16px 18px;
    font-family: var(--read-family, "Tiempos Text", Charter, "Iowan Old Style", "Source Serif 4", "Palatino Linotype", Georgia, serif);
    font-size: calc(16px * var(--read-scale, 1));
    line-height: var(--read-line, 1.75);
  }
  .preview p { margin: 0 0 0.7em; }
  .preview p:last-child { margin-bottom: 0; }
  .preview .word { border-radius: var(--r-0); padding: 1px 1px; }
  /* NO SENTENCE HIGHLIGHT HERE. It is the reader's "now" mark, and it means
     "this is the sentence being spoken" -- which is a lie in a preview that
     is not playing, and the picture draws plain text. The `.word` rule stays:
     it is what a person changing the size is judging. */

  #status { font-size: 0.8rem; color: var(--fg-dim); min-height: 1.4em; margin-top: 10px; }
  #status.bad { color: var(--bad); }


  /* THE RESERVATION SURVIVES THIS BLOCK, and that is the fix that took a
     failing check to find: the window is 560 wide, so it matches
     `max-width: 640px` -- the phone breakpoint -- and a `padding: ... 10px`
     here quietly gave the traffic lights' 80 px back to the tab strip on the
     very window the reservation exists for. Only the safe-area insets and
     the touch targets belong in a width test this wide. */
  @media (max-width: 640px), (max-height: 500px) {
    header { padding: calc(8px + var(--safe-top)) calc(80px + var(--safe-right)) 8px calc(80px + var(--safe-left)); gap: 6px; }
    header button, header .headerLink { min-height: 44px; min-width: 44px; border-radius: var(--r-2); }
    .opts button { min-height: 44px; padding: 0 14px; }
    /* the preview reads at the phone's own base size, like the reader does */
    .preview { font-size: calc(18px * var(--read-scale, 1)); line-height: var(--read-line, 1.7); }
  }

  /* A PHONE HAS NO TRAFFIC LIGHTS, so it reserves no room for them and the
     six tabs share the whole width. 480 px is under every window this app
     opens and over every phone it runs on, which is the only thing the
     breakpoint has to be right about. */
  @media (max-width: 480px) {
    header { padding: calc(8px + var(--safe-top)) calc(10px + var(--safe-right)) 8px calc(10px + var(--safe-left)); }
    header .set-tabs { width: 100%; }
    header .set-tab { flex: 1 1 0; width: auto; }
  }

/* ==================================================================
   PHONE FIT -- from design/phone/phone.html, 6 Sep 2026 (Copy CSS). THE PHONE'S NUMBERS.
   One value per property, one property per rule, no other layout code.
   The values are the same in library.css, settings.css and bar/askbar.css
   (the bar is on the reader too, where neither page sheet is loaded); the
   bench is the source and Copy CSS is how they change. `(max-height: 500px)`
   is in the query because the phone rotated is 852 wide.
   ================================================================== */
@media (max-width: 600px), (max-height: 500px) {
  :root {
    --ph-margin: 14px;
    --ph-gap: 14px;
    --ph-cols: 2;
    --ph-tile: 150px;
    --ph-type: 16px;
    --ph-head: 56px;
    --ph-card: 560px;
    --ph-tap: 44px;
  }
  html { font-size: var(--ph-type); }
  /* the header is FIXED at --ph-head under the safe area (Osca, 6 Sep); the
     padding leaves --ph-tap for the tab row */
  header { height: calc(var(--ph-head) + var(--safe-top, 0px)); }
  header { padding-top: calc(6px + var(--safe-top, 0px)); }
  header { padding-bottom: 6px; }
  header button, header .headerLink { min-width: var(--ph-tap); }
  header button, header .headerLink { min-height: var(--ph-tap); }
  main { padding-left: calc(var(--ph-margin) + var(--safe-left, 0px)); }
  main { padding-right: calc(var(--ph-margin) + var(--safe-right, 0px)); }
  main > * { max-width: var(--ph-card); }
  /* the form's own rules (settings.js, injected after this sheet) weigh
     (0,3,1) and later; `body` in front is what lets these win */
  body .ttstv-settings .opts button { min-height: var(--ph-tap); }
  body .ttstv-settings .opts.set-seg button { min-height: var(--ph-tap); }
  body .ttstv-settings .opts.set-seg button { min-width: var(--ph-tap); }
  body .ttstv-settings .set-menu { min-height: var(--ph-tap); }
  body .ttstv-settings .kag-btn, body .ttstv-settings .lang-btn, body .ttstv-settings .vc-btn { min-height: var(--ph-tap); }
  body .ttstv-settings .hk-cap { min-width: var(--ph-tap); }
  body .ttstv-settings .hk-cap { min-height: var(--ph-tap); }
  /* THE TABS, RE-LAID TO FIT THE FIXED HEADER (Osca, 6 Sep). settings.js's
     `.set-titlebar .set-tab { flex: 0 0 auto; width: 62px }` beat this
     sheet's own 480px rule (it weighs the same and comes later), so six
     62px tabs wrapped to two rows at 393 and the header grew to 81. One
     `header.` more and they share the width, one row, --ph-tap tall. */
  header.set-titlebar .set-tab { flex: 1 1 0; }
  header.set-titlebar .set-tab { width: auto; }
  header.set-titlebar .set-tab { min-width: 0; }
  header.set-titlebar .set-tab { min-height: var(--ph-tap); }
  header.set-titlebar .set-tab { padding: 2px 0; }
  header.set-titlebar .set-tab svg { margin-bottom: 0; }
  /* one line each. 9.5px was seven names in 373px ("Cloud GPU" wrapped at
     11); the phone has FOUR since 6 Sep (THE PHONE WHOLE, settings.js
     `phoneTabs`), ~80px each beside the door, and 11px fits them */
  header.set-titlebar .set-tab { white-space: nowrap; }
  header.set-titlebar .set-tab { font-size: 11px; }
  /* and no 80px reserved for traffic lights the phone has not got: the row
     takes the width, in landscape too (the 480px rule below 640 never did).
     SCOPED TO THE PHONE (25 Sep): these two rules were bare `header` and hit
     the Mac's 560 px Settings window, overriding 80 px to 10 px and putting
     the traffic lights over the first tab -- Osca's screenshot, SET-1. */
  html[data-phone] header { padding-left: calc(10px + var(--safe-left, 0px)); }
  html[data-phone] header { padding-right: calc(10px + var(--safe-right, 0px)); }
  /* the strip takes what the row has left (`width: 100%` until 6 Sep, when
     the door to the Library joined the row and 100% + 44 crossed the edge) */
  header .set-tabs { width: auto; }
  header .set-tabs { flex: 1 1 0; }
  header .set-tabs { min-width: 0; }
}
@media (max-height: 500px) and (orientation: landscape) {
  /* 3, not 4 (Osca, 6 Sep: "one size, 2 across, 3 in landscape"); the same
     value as library.css and bar/askbar.css, always */
  :root { --ph-cols: 3; }
}

/* ==================================================================
   THE PHONE, WHOLE (Osca, 6 Sep). design/phone/settings.html is the
   contract; this block is its text, byte for byte (test-phone.mjs checks).
   Settings on the phone is ONE COLUMN with the phone's own four tabs --
   General, Reading, Sync, Voices; Cloud GPU folds under Sync, Models under
   Voices, and Languages and Hotkeys are the Mac's (settings.js `phoneTabs`,
   the JS half of this contract). The tab strip IS the title: nothing else
   is in the header but the door back to the Library. Every rule keys on
   `html[data-phone]` -- the flag settings.html's <head> sets for a coarse
   pointer with no hover, or for ?phone -- INSIDE the media query: this
   page's own Mac window is 560 wide and matches a width test alone, and the
   Mac is untouched.
   ================================================================== */
@media (max-width: 600px), (max-height: 500px) {
  html[data-phone] #libraryDoor { display: inline-flex; }
  html[data-phone] header.set-titlebar { gap: 4px; }
  /* one column: the cards take the width the margin leaves, never a 560 */
  html[data-phone] main > * { max-width: none; }
  /* a slider is a thumb's target too: the track's box is 44 tall (the thumb
     the engine draws is its own size; the hit area is what this raises) */
  html[data-phone] body .ttstv-settings .set-range { min-height: var(--ph-tap); }
  /* ...and a field: the Kaggle and Modal cards' inputs, the pair address */
  html[data-phone] body .ttstv-settings .kag-in, html[data-phone] body .ttstv-settings input[type="text"], html[data-phone] body .ttstv-settings input[type="password"] { min-height: var(--ph-tap); }
}
@media (max-width: 600px), (max-height: 500px) {
  /* the listen-window dots (settings.js .set-ticks, 13x13): the BUTTON is
     --ph-tap square and invisible, the dot it drew is now its ::after, at
     the same 13px / 16px thumb, so the rail looks as it did and every dot
     is a thumb's target (Osca, 6 Sep: tap targets under 44 raised) */
  body .ttstv-settings .opts.set-ticks button,
  body .ttstv-settings .opts.set-ticks button[aria-pressed="true"] {
    width: var(--ph-tap); height: var(--ph-tap);
    background: transparent; border: 0; box-shadow: none;
  }
  body .ttstv-settings .opts.set-ticks button::after {
    content: ""; position: absolute; left: 50%; top: 50%;
    width: 13px; height: 13px; transform: translate(-50%, -50%);
    border-radius: 50%; background: var(--control-bg); border: 1px solid var(--border);
  }
  body .ttstv-settings .opts.set-ticks button:hover:not([disabled])::after { background: var(--border); }
  body .ttstv-settings .opts.set-ticks button[aria-pressed="true"]::after {
    width: 16px; height: 16px; background: #fff; border: 0;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  }
}

/* ==================================================================
   THE TRANSFER ROW IS A GRID, NOT A SQUEEZE (14 Sep).

   Osca's first screenshot of the wave-A build: *"the 'This network' row is
   laid out ONE WORD PER LINE beside the QR"* -- the same disease the phone's
   door card had on 13 Sep (the block above), on the Mac this time, and from
   the same two rules: `.set-l { flex: 1 1 auto }` is shrinkable and
   `.set-c { flex: 0 0 auto }` is not, so a right-hand side of a code, two
   buttons and a picker takes its max-content width out of a 560 px window
   and the sentence gets whatever is left -- which was 26 px wide.

   A grid says the opposite in one line: the sentence's column is
   `minmax(0, 1fr)` and takes the width; the controls are `auto` and take
   what they need; the square is its own column at a FIXED size and never
   competes with the words for room. The buttons wrap inside their own column
   rather than pushing the sentence out of the row.

   `.tr-open` -- the ten digits and the address to type them at -- spans the
   whole row under both, because it is a line of text and not a control.
   ================================================================== */
body .ttstv-settings .set-row.tr-dest {
  display: grid;
  /* THE FLOOR IS THE POINT. `minmax(0, 1fr)` alone is not a fix: a 0 minimum
     lets the controls take their max-content width again and the sentence
     goes back to 31.3 px at 420 (measured). 10rem is the floor under the
     words, and it is what makes the BUTTONS wrap -- an `auto` track shrinks
     to its min-content, which is one button wide, the moment the track
     beside it refuses to go below its own minimum. */
  grid-template-columns: minmax(10rem, 1fr) auto auto;
  align-items: center;
  column-gap: var(--s-row-gap);
}
body .ttstv-settings .set-row.tr-dest > .set-l { grid-column: 1; grid-row: 1; }
body .ttstv-settings .set-row.tr-dest > .set-c {
  grid-column: 2; grid-row: 1;
  flex-wrap: wrap; justify-content: flex-end; max-width: 100%;
}
body .ttstv-settings .set-row.tr-dest > .tr-open {
  grid-column: 1 / -1; grid-row: 2;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px;
  margin-top: 6px;
}
body .ttstv-settings .set-row.tr-dest > .tr-open[hidden] { display: none; }
/* THE SQUARE AT A FIXED SIZE, in its own column beside the sentence: an
   `<svg>` with no width of its own fills whatever box it is given, and the
   box it was being given was "the rest of the row". */
body .ttstv-settings .set-row.tr-dest > .tr-qr {
  grid-column: 3; grid-row: 1 / span 2;
  flex: 0 0 auto; width: 96px; height: 96px;
}
body .ttstv-settings .set-row.tr-dest > .tr-qr[hidden] { display: none; }
body .ttstv-settings .tr-qr svg { display: block; width: 100%; height: 100%; }
body .ttstv-settings .tr-road { display: block; }
body .ttstv-settings .tr-code { font-variant-numeric: tabular-nums; }

/* ==================================================================
   A ROW WITH FIELDS ON IT IS TWO LINES ON A PHONE (G-SETTINGS2, 13 Sep).
   Osca, T-SIM 20:35: *"the 'Your door' card renders one word per line"* --
   and it did, measured at 393 px in the container's Chromium:

     .set-l  { flex: 1 1 auto; min-width: 0 }   the label, shrinkable
     .set-c  { flex: 0 0 auto }                 the controls, NOT shrinkable

   so a right-hand side of two 150 px fields and a button took its
   max-content 443.3 px inside a 363 px row, squeezed the label column to
   26 px (hence one word per line, a 264.8 px tall row) and hung 106 px
   past the card, clipped invisibly by `.set-card { overflow: hidden }`.
   **The Use button sat at x 433 on a card ending at 378: the release press
   Osca is asked to make was not on the screen at all.**

   The fix is the stack, and only where there is something to stack: a row
   that has a VISIBLE field in it (`.kag-in` -- the door's address and pass,
   the LAN pairing's address and code) puts its label on one line and its
   controls on the next, where `.kag-in`'s own `flex: 1 1 150px` shares the
   363 px out. A row whose right side is a button, a segment or a slider is
   untouched, at 44 px, exactly as the phone block above leaves it -- and
   `:has()` means a row goes back to one line the moment its fields hide
   again. The Mac never matches: `html[data-phone]` inside the query.
   ================================================================== */
@media (max-width: 600px), (max-height: 500px) {
  html[data-phone] body .ttstv-settings .set-row:has(.kag-in:not([hidden])) { flex-wrap: wrap; }
  html[data-phone] body .ttstv-settings .set-row:has(.kag-in:not([hidden])) > .set-l { flex: 1 1 100%; }
  html[data-phone] body .ttstv-settings .set-row:has(.kag-in:not([hidden])) > .set-c { flex: 1 1 100%; }
  html[data-phone] body .ttstv-settings .set-row:has(.kag-in:not([hidden])) > .set-c { min-width: 0; }
  /* and the one control in a STACKED row that is not a field: a `<select>`'s
     intrinsic width is the widest Studio name Bonjour found, which is not a
     number this sheet can know. Scoped to the same `:has()` and not to
     `.set-menu` at large -- measured: a bare
     `html[data-phone] .set-c > .set-menu { max-width: 100% }` is a 100% of a
     shrink-to-fit column, and it took the Interface font row from 92.2 px to
     262.3 px on the phone. */
  html[data-phone] body .ttstv-settings .set-row:has(.kag-in:not([hidden])) > .set-c > .set-menu { max-width: 100%; }
  /* AND THE SAME DISEASE ON ONE MORE ROW, measured on the way past: Light /
     dark is three options with two grey sub-lines, a 370.9 px segment inside
     a 363 px row, and it hung 32.9 px past the card -- so "System", the
     third option, was partly off the screen and the crossing was invisible
     for the same reason. Every `.opts.set-seg` row is stacked rather than
     that one field by name: the next three-option segment breaks the same
     way, and a phone that puts wide controls under their label is what the
     rows above already look like. The cost, measured: Light / dark 92.2 ->
     135.4 px, View 70 -> 101.1, Touch off 110 -> 153.2, and 0 elements
     crossing anywhere in Settings. (The other shape -- letting the segment
     wrap inside a shrunken column -- was measured too and is worse: 158 px,
     114 px, and a 0.8 px crossing left over.) */
  html[data-phone] body .ttstv-settings .set-row:has(.opts.set-seg) { flex-wrap: wrap; }
  html[data-phone] body .ttstv-settings .set-row:has(.opts.set-seg) > .set-l { flex: 1 1 100%; }
  html[data-phone] body .ttstv-settings .set-row:has(.opts.set-seg) > .set-c { flex: 1 1 100%; }
  html[data-phone] body .ttstv-settings .set-row:has(.opts.set-seg) > .set-c { min-width: 0; }
  /* AND THE TRANSFER ROW GOES BACK TO BEING ONE OF THEM (14 Sep). The grid
     above is the MAC's answer -- a sentence column, a controls column and a
     fixed square column, which is right in a 560 px window and wrong in a
     363 px one, where three columns is the squeeze under another name. On a
     phone with its fields open the row stacks like every other row here, by
     the same `:has()` and the same four rules. */
  html[data-phone] body .ttstv-settings .set-row.tr-dest:has(.kag-in:not([hidden])) { display: flex; }
}
