/* Kliqed terminal — the Desk direction.
 *
 * A trading desk, not an app. The rules are few and they are absolute:
 *
 *   Rules, not cards.     A hairline separates two things. A border with a
 *                         radius and a gradient separates them three times.
 *   One typeface.         Monospace throughout, because every screen here is
 *                         a column of numbers and columns want to line up.
 *   Amber is the machine.  Section headers, the value you just changed,
 *                         anything the system wants you to notice. Never
 *                         decoration — if it is amber it is speaking.
 *   Green and red are money. Nothing else may use them.
 *
 * Both themes are real. Dark is a navy terminal at night; light is the same
 * terminal on cool paper — a blue-grey ground rather than white, because a
 * pure white sheet under amber goes acid. Every colour below is a token, and
 * only the tokens change between the two.
 *
 * WHY NAVY, AND WHY AMBER SURVIVED IT
 *
 *   The ground moved from a warm near-black to a light navy. Amber is the
 *   one colour that had to keep working, because the whole interface uses it
 *   to mean "the machine is speaking" — and amber on navy is the easiest
 *   pairing there is: they sit opposite each other, so the accent separates
 *   from the ground harder than it did on black.
 *
 *   What did NOT survive was the warmth of the greys. A cream ink and a
 *   brown-grey dim were chosen against a warm black; on blue they read as
 *   dirt. Every neutral below is now cooled to the same blue family as the
 *   ground, which is the whole of "harmonise the rest with it".
 *
 *   Red needed a nudge too. A saturated red on saturated blue vibrates at
 *   the edge, so --down is lighter and slightly warmer here than it was on
 *   black. Green did not: it was already far enough from the ground.
 */

:root {
  /* ── ground: light navy, four steps of it ── */
  --bg:#182b45; --panel:#1e3352; --panel-2:#25405f; --sunk:#132339;
  --line:#3a5779; --line-soft:#2a4160;
  --ink:#e9eff8; --dim:#9aabc4; --dimmer:#8b9db8;

  /* ── the machine's own voice ── */
  --accent:#ffb425; --accent-soft:rgba(255,180,37,.13); --accent-line:rgba(255,180,37,.45);

  /* ── the machine, worried ── */
  --warn:#e3ab4e;

  /* ── money ── */
  --up:#37d48a; --down:#ff6357;
  --up-soft:rgba(55,212,138,.13); --down-soft:rgba(255,99,87,.13);
  --up-line:rgba(55,212,138,.42); --down-line:rgba(255,99,87,.44);

  /* ── canvas: the chart reads these through getComputedStyle ── */
  --c-entry:#ffb425; --c-base:#9aabc4; --c-target:#4b6588; --c-target-hit:#37d48a;
  --c-stop:#ff6357; --c-grid:rgba(58,87,121,.55); --c-axis:#8b9db8;
  --c-tag-bg:#e9eff8; --c-tag-ink:#182b45;

  color-scheme:dark;

  /* Desk has no rounded corners. The two variables stay so every rule that
     referenced them keeps working; they simply resolve to square. */
  --r:0px; --r-sm:0px; --r-pill:2px;
  --shadow:0 14px 40px rgba(6,14,26,.62);

  /* Installed to a home screen with `viewport-fit=cover` and a translucent
     status bar, the page really does start at pixel zero — behind the clock
     and the signal bars. These are the strips iOS reserves; everything fixed
     to an edge has to move out of them. */
  --safe-t:env(safe-area-inset-top, 0px);
  --safe-b:env(safe-area-inset-bottom, 0px);
  --safe-l:env(safe-area-inset-left, 0px);
  --safe-r:env(safe-area-inset-right, 0px);
  --bar-h:56px;
  --ui-scale:1;        /* the text-size dial; see html{font-size} below */
  --font:ui-monospace,"SF Mono","JetBrains Mono","Cascadia Mono",Menlo,Consolas,monospace;
  --sans:var(--font);          /* Desk is monospace everywhere, deliberately */
}

/* Paper. Warm rather than white — amber on pure white reads acid, and this
   is a printout of the same terminal, not a different product.
 *
 * Declared twice on purpose. The media query is what the page uses before a
 * single line of JavaScript runs, so a viewer whose phone is in light mode
 * never sees a flash of the dark theme. The attribute selector is the
 * explicit choice from the header key, and it wins in both directions —
 * `:not([data-theme="dark"])` is what lets someone keep the dark terminal on
 * a device that is otherwise in light mode. The two blocks are identical and
 * adjacent so that a change to one that misses the other is obvious. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg:#eef2f8; --panel:#e5ebf4; --panel-2:#dce4f0; --sunk:#e2e8f2;
    --line:#c3cede; --line-soft:#d5dde9;
    --ink:#122135; --dim:#566880; --dimmer:#5b6d85;

    --accent:#8a5300; --accent-soft:rgba(138,83,0,.10); --accent-line:rgba(138,83,0,.42);

    --warn:#8a6410;

    --up:#0f7448; --down:#c02c1f;
    --up-soft:rgba(15,116,72,.11); --down-soft:rgba(192,44,31,.10);
    --up-line:rgba(15,116,72,.38); --down-line:rgba(192,44,31,.36);

    --c-entry:#8a5300; --c-base:#566880; --c-target:#a8b6c9; --c-target-hit:#0f7448;
    --c-stop:#c02c1f; --c-grid:rgba(195,206,222,.95); --c-axis:#5b6d85;
    --c-tag-bg:#122135; --c-tag-ink:#eef2f8;

    color-scheme:light;
    --shadow:0 10px 30px rgba(24,43,69,.14);
  }
}

:root[data-theme="light"] {
  --bg:#eef2f8; --panel:#e5ebf4; --panel-2:#dce4f0; --sunk:#e2e8f2;
  --line:#c3cede; --line-soft:#d5dde9;
  --ink:#122135; --dim:#566880; --dimmer:#5b6d85;

  --accent:#8a5300; --accent-soft:rgba(138,83,0,.10); --accent-line:rgba(138,83,0,.42);

  --warn:#8a6410;

  --up:#0f7448; --down:#c02c1f;
  --up-soft:rgba(15,116,72,.11); --down-soft:rgba(192,44,31,.10);
  --up-line:rgba(15,116,72,.38); --down-line:rgba(192,44,31,.36);

  --c-entry:#8a5300; --c-base:#566880; --c-target:#a8b6c9; --c-target-hit:#0f7448;
  --c-stop:#c02c1f; --c-grid:rgba(195,206,222,.95); --c-axis:#5b6d85;
  --c-tag-bg:#122135; --c-tag-ink:#eef2f8;

  color-scheme:light;
  --shadow:0 10px 30px rgba(24,43,69,.14);
}

* { box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
html,body { height:100%; }
/* iOS inflates text in wide-looking layouts; the sizes here are already the
   sizes wanted */
html { -webkit-text-size-adjust:100%; text-size-adjust:100%; }
/* ONE root size, and every size in this file is written against it in rem.
   A phone follows the width of its own screen: a bigger handset was getting
   the same eleven pixels floating in more glass, which is what "the layout
   was tuned for the last phone" actually looks like. The clamp keeps it
   honest at both ends — no thirteen-pixel headline on a small phone, no
   tablet-sized type on a large one — and --ui-scale is the reader's own thumb
   on the dial, applied on top of whatever the screen asked for. */
html { font-size: calc(16px * var(--ui-scale, 1)); }
@media (max-width:900px), (hover:none) and (pointer:coarse) and (max-width:1100px) {
  html { font-size: calc(clamp(15px, 4.15vw, 18.5px) * var(--ui-scale, 1)); }
}
body {
  margin:0; font-family:var(--font); color:var(--ink); background:var(--bg);
  font-size:0.875rem; line-height:1.45; overflow-x:hidden;
  font-variant-numeric:tabular-nums;
}
button,input,select { font:inherit; color:inherit; }
a { color:var(--accent); text-decoration:none; }
a:hover { text-decoration:underline; }
h1,h2,h3 { margin:0; font-weight:700; letter-spacing:.01em; }
[hidden] { display:none !important; }

/* ── the mark ─────────────────────────────────────────────────────────
   Four bars, stepped. On Desk they are one hue at four intensities — a
   level meter rather than a rainbow. */
.boot-mark,.login-mark,.rail-mark { display:flex; flex-direction:column-reverse; gap:2px; }
.boot-mark i,.login-mark i,.rail-mark i { display:block; height:4px; border-radius:0; background:var(--accent); }
.boot-mark i:nth-child(1),.login-mark i:nth-child(1),.rail-mark i:nth-child(1){ width:32px; opacity:1; }
.boot-mark i:nth-child(2),.login-mark i:nth-child(2),.rail-mark i:nth-child(2){ width:24px; opacity:.72; }
.boot-mark i:nth-child(3),.login-mark i:nth-child(3),.rail-mark i:nth-child(3){ width:16px; opacity:.48; }
.boot-mark i:nth-child(4),.login-mark i:nth-child(4),.rail-mark i:nth-child(4){ width:9px;  opacity:.3; }
.rail-mark i { height:3px; }

.boot { position:fixed; inset:0; display:grid; place-items:center; z-index:60; background:var(--bg); }
.boot-mark { animation:pulse 1.1s ease-in-out infinite; }
@keyframes pulse { 0%,100%{opacity:.35} 50%{opacity:1} }

/* ── sign in ──────────────────────────────────────────────────────── */
.login { min-height:100dvh; display:grid; place-items:center;
         padding:calc(24px + var(--safe-t)) calc(24px + var(--safe-r))
                 calc(24px + var(--safe-b)) calc(24px + var(--safe-l)); }
.login-card {
  width:min(370px,100%); background:var(--panel);
  border:1px solid var(--line); padding:26px 22px 22px;
}
.login-card h1 { font-size:1.625rem; letter-spacing:.26em; margin-top:16px; color:var(--accent); }
.login-sub { margin:4px 0 22px; color:var(--dim); font-size:0.6875rem; letter-spacing:.2em; text-transform:uppercase; }
.login-note { color:var(--dim); font-size:0.78125rem; margin:0 0 14px; }
.login-error { color:var(--down); font-size:0.78125rem; margin:12px 0 0; }
.field { display:block; margin-bottom:14px; }
.field span { display:block; font-size:0.625rem; color:var(--dimmer); margin-bottom:6px; letter-spacing:.16em; text-transform:uppercase; }
.field input {
  width:100%; padding:11px 12px; background:var(--sunk); border:1px solid var(--line);
  border-radius:0; font-family:var(--font); font-size:max(16px, 1rem); outline:none;
}
.field input:focus { border-color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent-line); }
#code { letter-spacing:.5em; text-align:center; }

/* ── buttons ──────────────────────────────────────────────────────────
   Square, bordered, uppercase. A control on a desk is a key, not a pill. */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  padding:8px 13px; border-radius:0; border:1px solid var(--line);
  background:var(--panel); color:var(--ink); cursor:pointer;
  font-family:var(--font); font-size:0.75rem; font-weight:600;
  letter-spacing:.09em; text-transform:uppercase;
  transition:border-color .12s, background .12s, color .12s;
}
.btn:hover { border-color:var(--dim); background:var(--panel-2); }
.btn:active { background:var(--sunk); }
.btn:disabled { opacity:.4; cursor:not-allowed; }
.btn.small { padding:5px 10px; font-size:0.6875rem; }
.btn.wide { width:100%; }
.btn.primary { background:var(--accent); border-color:var(--accent); color:var(--bg); font-weight:700; }
.btn.primary:hover { background:var(--accent); border-color:var(--accent); filter:brightness(1.08); }
.btn.good { background:transparent; border-color:var(--up-line); color:var(--up); }
.btn.good:hover { background:var(--up-soft); border-color:var(--up); }
/* `warn` was a second name for `danger` — same colour, same meaning, two
   spellings. Kept as an alias so nothing breaks, but new code uses danger. */
.btn.warn { border-color:var(--down-line); color:var(--down); background:var(--down-soft); }
.btn.warn:hover { border-color:var(--down); }
.btn.ghost { background:transparent; }
.btn.danger { border-color:var(--down-line); color:var(--down); background:var(--down-soft); }
.btn.danger:hover { border-color:var(--down); }
.icon-btn { background:none; border:0; font-size:1.125rem; color:var(--dim); cursor:pointer; padding:4px 8px; }
.icon-btn:hover { color:var(--ink); }

/* keyboard users get the same affordance a mouse gets */
:focus-visible { outline:2px solid var(--accent); outline-offset:1px; border-radius:0; }

/* ── work in progress, and the connection ─────────────────────────── */
.prog { position:fixed; top:var(--safe-t); left:0; height:2px; width:100%; z-index:45; pointer-events:none;
        background:linear-gradient(90deg,transparent,var(--accent),transparent);
        transform:translateX(-100%); opacity:0; }
.prog.on { opacity:1; animation:sweep 1.1s linear infinite; }
@keyframes sweep { to { transform:translateX(100%); } }

/* The banner is fixed, so the screen behind it has to be pushed down by
   exactly its height or it covers the first line. The height is measured and
   written to --conn-h when it is shown, because the text wraps to two lines on
   a narrow phone and a guessed constant would be wrong on one of them. */
body.has-conn .view { padding-top: var(--conn-h, 34px); }

.conn { position:fixed; top:calc(var(--bar-h) + var(--safe-t)); left:228px; right:0; z-index:40;
        padding:8px 16px; background:var(--down-soft);
        border-bottom:1px solid var(--down-line); color:var(--down);
        font-size:0.71875rem; letter-spacing:.06em; }

.ptr { position:fixed; top:calc(var(--bar-h) + var(--safe-t)); left:50%; margin-left:-84px; width:168px; z-index:44;
       text-align:center; font-size:0.65625rem; letter-spacing:.14em; text-transform:uppercase;
       color:var(--dim); padding:7px 0;
       border:1px solid var(--line); background:var(--panel); transition:opacity .15s; }
.ptr.ready { color:var(--accent); border-color:var(--accent-line); }

.sk { height:96px; position:relative; overflow:hidden; border:1px solid var(--line-soft); }
.sk::after { content:""; position:absolute; inset:0;
             background:linear-gradient(90deg,transparent,var(--accent-soft),transparent);
             animation:shimmer 1.3s infinite; }
@keyframes shimmer { from { transform:translateX(-100%); } to { transform:translateX(100%); } }

.filters { display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-bottom:10px; }
.filters-k { font-size:0.625rem; letter-spacing:.16em; text-transform:uppercase; color:var(--dimmer); }
.filters .chip { padding:5px 11px; font-size:0.6875rem; }

/* ── app frame ────────────────────────────────────────────────────── */
.app { display:grid; min-height:100dvh; grid-template-columns:228px 1fr;
       grid-template-rows:calc(var(--bar-h) + var(--safe-t)) 1fr; }
.rail { grid-row:1/3; border-right:1px solid var(--line); background:var(--panel);
        display:flex; flex-direction:column; padding:14px 0 12px; }
.rail-brand { display:flex; align-items:center; gap:11px; padding:2px 16px 16px; }
.rail-name { font-weight:700; letter-spacing:.28em; font-size:0.8125rem; color:var(--accent); }
.rail-nav { display:flex; flex-direction:column; flex:1; }
.rail-nav button {
  display:flex; align-items:center; gap:10px; padding:8px 16px; border:0; border-radius:0;
  background:none; color:var(--dim); cursor:pointer; font-family:var(--font);
  font-size:0.75rem; letter-spacing:.1em; text-transform:uppercase; text-align:left; width:100%;
  border-left:2px solid transparent;
}
.rail-nav button:hover { background:var(--panel-2); color:var(--ink); }
.rail-nav button.on { background:var(--accent-soft); color:var(--accent); border-left-color:var(--accent); }
.rail-nav .glyph { width:18px; text-align:center; font-size:0.8125rem; }
.rail-nav .badge { margin-left:auto; font-size:0.65625rem; color:var(--accent);
                   border:1px solid var(--accent-line); padding:0 5px; letter-spacing:.04em; }
.rail-foot { padding:12px 16px 0; border-top:1px solid var(--line-soft); }

.top {
  grid-column:2; display:flex; align-items:center; gap:10px;
  padding:var(--safe-t) calc(16px + var(--safe-r)) 0 calc(16px + var(--safe-l));
  border-bottom:1px solid var(--line); background:var(--panel);
  position:sticky; top:0; z-index:20;
}
.top-right { margin-left:auto; display:flex; align-items:center; gap:8px; }
.status { display:flex; align-items:center; gap:9px; flex-wrap:wrap; min-width:0; }
.top-title { font-size:0.75rem; font-weight:700; letter-spacing:.16em; text-transform:uppercase;
             white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.lock { border:1px solid var(--up-line); background:var(--up-soft); color:var(--up);
        border-radius:0; padding:3px 9px; font-size:0.65625rem; font-family:var(--font);
        letter-spacing:.1em; text-transform:uppercase; cursor:pointer; white-space:nowrap; }
.unlocked { display:flex; align-items:center; gap:10px; margin:12px 0; padding:9px 11px;
            border:1px solid var(--up-line); background:var(--up-soft);
            font-size:0.75rem; color:var(--up); }
.unlocked .link { margin-left:auto; }
.tick { width:6px; height:6px; border-radius:50%; background:var(--up); opacity:.22; transition:opacity .25s; }
.tick.on { opacity:1; }

/* The day/night key. Square, quiet, and it never moves — a control you reach
   for by muscle memory should not be somewhere new each visit. */
.theme-btn {
  border:1px solid var(--line); background:var(--panel); color:var(--dim);
  border-radius:0; padding:4px 9px; font-family:var(--font); font-size:0.6875rem;
  letter-spacing:.1em; text-transform:uppercase; cursor:pointer; white-space:nowrap;
}
.theme-btn:hover { border-color:var(--dim); color:var(--ink); }

/* `min-width:0` is load-bearing, not tidiness. A grid item defaults to
   `min-width:auto`, which is its CONTENT's minimum — and a <canvas> carries an
   intrinsic width of its backing store, which is the CSS width times the device
   pixel ratio: 3x on an iPhone. Without this the chart quietly forced the
   column, and therefore the page, three times wider than the phone, and every
   screen rendered shrunk to fit — a desktop layout on a handset. */
.view, .top { grid-column:2; min-width:0; }
.view { padding:16px; padding-bottom:40px; max-width:1500px; width:100%; }

.tabs { display:none; }
.only-mobile { display:none; }

/* ── pills, chips, tiles ──────────────────────────────────────────── */
.pill { display:inline-flex; align-items:center; gap:6px; padding:2px 8px; border-radius:var(--r-pill);
        font-size:0.65625rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
        border:1px solid var(--line); background:var(--panel-2); color:var(--dim); white-space:nowrap; }
.pill.live { color:var(--up); border-color:var(--up-line); background:var(--up-soft); }
.pill.paused { color:var(--accent); border-color:var(--accent-line); background:var(--accent-soft); }
.pill.warn { color:var(--down); border-color:var(--down-line); background:var(--down-soft); }
.pill.cyan { color:var(--accent); border-color:var(--accent-line); background:var(--accent-soft); }
.pill.bad { color:var(--down); border-color:var(--down-line); background:var(--down-soft); }
.pill.dim { color:var(--dimmer); }
/* `flex:0 0 auto` because the pill may now shrink to make room for the coin
   symbol beside it, and a flex child with a 5px width shrinks to nothing
   before the text does — the dot simply vanished. */
.pill.dot::before { content:""; width:5px; height:5px; border-radius:50%;
                    background:currentColor; flex:0 0 auto; }

/* ── event log ─────────────────────────────────────────────────────────
   Dense on purpose: the value of this screen is scanning fifty lines for the
   one that matters, not reading any single one of them beautifully. */
.log-top { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:5px; font-size:0.6875rem; }
.log-msg { font-size:0.78125rem; line-height:1.45; word-break:break-word; }
.log-detail { margin-top:7px; padding:8px 10px; background:var(--sunk); border:1px solid var(--line-soft);
              color:var(--dim); font-size:0.71875rem; line-height:1.5; white-space:pre-wrap;
              word-break:break-word; max-height:260px; overflow:auto; }

.grid { display:grid; gap:10px; }
.grid > * { min-width:0; }          /* same reason as .view — see above */
.grid.tiles { grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
.grid.two { grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); }
.card, .card.row { min-width:0; }

.card { background:var(--panel); border:1px solid var(--line); border-radius:0; padding:13px 14px; }
.card.tap { cursor:pointer; transition:border-color .12s; }
.card.tap:hover { border-color:var(--dim); }
.card-head { display:flex; align-items:center; gap:9px; margin-bottom:10px;
             padding-bottom:8px; border-bottom:1px solid var(--line-soft); }
.card-head h2 { font-size:0.6875rem; letter-spacing:.16em; text-transform:uppercase;
                color:var(--accent); line-height:1.2; }
.card-head .spacer { margin-left:auto; }

/* A 9-pixel uppercase label on a 1.45 body leading carries almost half its own
   height in empty space above and below it, three times over in every tile.
   Small type gets tight leading; only running prose needs the loose kind. */
.tile .k { font-size:0.59375rem; letter-spacing:.16em; text-transform:uppercase;
           color:var(--dimmer); line-height:1.2; }
.tile .v { font-size:1.3125rem; font-weight:600; margin-top:4px; letter-spacing:-.02em;
           line-height:1.15; }
.tile .s { font-size:0.6875rem; color:var(--dim); margin-top:2px; line-height:1.25; }

.section-title { font-size:0.625rem; letter-spacing:.2em; text-transform:uppercase;
                 color:var(--accent); margin:20px 0 8px; line-height:1.2;
                 padding-bottom:5px; border-bottom:1px solid var(--line); }
.section-title:first-child { margin-top:0; }

/* ── dashboard: section labels, hero, controls, feed ──────────────── */
.sec { display:flex; align-items:baseline; gap:10px; margin:18px 0 8px;
       font-size:0.625rem; letter-spacing:.2em; text-transform:uppercase; color:var(--accent);
       padding-bottom:5px; border-bottom:1px solid var(--line); }
.sec:first-child { margin-top:0; }
.sec-right { margin-left:auto; }
.link { background:none; border:0; color:var(--dim); cursor:pointer; font-family:var(--font);
        font-size:0.625rem; letter-spacing:.14em; text-transform:uppercase; padding:0; }
.link:hover { color:var(--accent); }

/* The top of the book: four readings divided by rules, not one hero and
   three footnotes. Two by two on a phone — nothing gets demoted. */
.hero { padding:0; }
.cells { display:grid; grid-template-columns:repeat(4,1fr); }
.cell { padding:11px 13px; border-right:1px solid var(--line-soft); min-width:0; }
.cell:last-child { border-right:0; }
.cell-k { font-size:0.5625rem; letter-spacing:.17em; text-transform:uppercase; color:var(--dimmer); }
.cell-v { font-size:1.25rem; font-weight:600; letter-spacing:-.025em; margin-top:4px;
          white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cell-s { font-size:0.65625rem; color:var(--dim); margin-top:2px; white-space:nowrap;
          overflow:hidden; text-overflow:ellipsis; }
.hero-spark { border-top:1px solid var(--line-soft); padding:6px 10px 4px; }
.hero-foot { padding:8px 13px; font-size:0.625rem; color:var(--dim); line-height:1.45;
             border-top:1px solid var(--line-soft); background:var(--panel-2); }

/* ── the book: column headings and single-line rows ───────────────────
   This is what makes Desk a desk. Four numbers on one line under a heading
   that names each column, so a list of ten reads as a table rather than ten
   paragraphs. The detail that used to be a second line of prose lives behind
   the expand, where it is read once rather than scanned past every time. */
.thead, .trow {
  display:grid; grid-template-columns:minmax(0,1.5fr) repeat(3,minmax(0,1fr)) minmax(0,.9fr);
  gap:8px; align-items:baseline;
}
.thead { padding:6px 13px; border:1px solid var(--line); border-bottom:0;
         background:var(--panel-2); font-size:0.5625rem; letter-spacing:.16em;
         text-transform:uppercase; color:var(--dimmer); }
.tbody { border:1px solid var(--line); }
.tbody > .card.row { border:0; border-bottom:1px solid var(--line-soft); }
.tbody > .card.row:last-child { border-bottom:0; }
.tsym { font-size:0.8125rem; display:flex; align-items:baseline; gap:5px; min-width:0; }
/* The symbol is the one thing in the row that must never be cut. Sharing the
   cell with a badge shrank it proportionally, which turned ICP into "I…" —
   the name holds its width and the badge beside it gives way instead. */
.tsym > b { font-weight:700; letter-spacing:.05em; white-space:nowrap; flex:0 0 auto; }
.trow .pill, .trow .tflag { min-width:0; flex:0 1 auto; overflow:hidden;
                            text-overflow:ellipsis; white-space:nowrap; }
.tnum { text-align:right; font-size:0.78125rem; white-space:nowrap;
        overflow:hidden; text-overflow:ellipsis; }
.trow .chg { text-align:right; font-size:0.8125rem; font-weight:700; white-space:nowrap; }
.tid { font-style:normal; font-size:0.59375rem; color:var(--dimmer); }
.tflag { font-style:normal; font-size:0.53125rem; font-weight:700; letter-spacing:.1em;
         padding:1px 4px; border:1px solid currentColor; }
.tflag.held { color:var(--accent); }
.tflag.warn { color:var(--down); }
.trow-meta { margin-top:3px; font-size:0.625rem; color:var(--dimmer); line-height:1.3; }
.trow-meta b { color:var(--dim); font-weight:600; }
/* The pills that used to sit in a row head are flags on the symbol now. */
.trow .pill { font-size:0.53125rem; padding:1px 5px; }

.warn-card { border-color:var(--accent-line); background:var(--accent-soft); padding:0; }
.warn-line { font-size:0.75rem; color:var(--ink); padding:8px 14px 8px 28px; position:relative;
             border-bottom:1px solid var(--accent-soft); }
.warn-card .warn-line:last-child { border-bottom:0; }
.warn-line::before { content:"!"; position:absolute; left:14px; color:var(--accent); font-weight:700; }

/* The control strip: five keys in a row, each a cell in one band. */
.strip { display:flex; gap:0; overflow-x:auto; -webkit-overflow-scrolling:touch;
         scroll-snap-type:x proximity; border:1px solid var(--line); background:var(--panel); }
.strip::-webkit-scrollbar { height:0; }
/* The whole cell is the key. One target, one decision. */
.ctl { flex:0 0 auto; width:128px; scroll-snap-align:start; border:0;
       border-right:1px solid var(--line-soft); background:none; color:inherit;
       font-family:var(--font); text-align:left; cursor:pointer;
       padding:9px 11px; display:flex; flex-direction:column; gap:3px; }
.ctl:last-child { border-right:0; }
.ctl:hover { background:var(--panel-2); }
.ctl:active { background:var(--sunk); }
.ctl-k { font-size:0.5625rem; letter-spacing:.17em; text-transform:uppercase; color:var(--dimmer); }
.ctl-v { font-size:0.78125rem; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ctl-a { font-size:0.53125rem; letter-spacing:.14em; text-transform:uppercase; color:var(--accent); margin-top:1px; }
.ctl.good .ctl-v { color:var(--up); }
.ctl.warn .ctl-v { color:var(--accent); }

.chart-bar { display:flex; align-items:center; gap:9px; margin-bottom:9px; }
.pick { background:var(--sunk); border:1px solid var(--line); border-radius:0; padding:6px 9px;
        font-family:var(--font); font-size:0.75rem; outline:none; max-width:60%; }
.chart-tag { margin-left:auto; font-size:0.6875rem; color:var(--dim); }

.quick { display:grid; grid-template-columns:repeat(2,1fr); gap:8px; }
.quick .btn { padding:12px 10px; justify-content:flex-start; }

.feed { padding:0; }
.act { display:flex; align-items:flex-start; gap:10px; padding:9px 14px;
       border-bottom:1px solid var(--line-soft); cursor:pointer; }
.act:last-child { border-bottom:0; }
.act:hover { background:var(--panel-2); }
.act-i { font-size:0.8125rem; line-height:1.3; }
.act-b { min-width:0; flex:1; }
.act-t { font-size:0.78125rem; font-weight:600; }
.act-d { font-size:0.6875rem; color:var(--dim); margin-top:2px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.act-w { font-size:0.625rem; color:var(--dimmer); white-space:nowrap; margin-top:2px; }

/* ── expandable rows ──────────────────────────────────────────────── */
.card.row { padding:0; overflow:hidden; }
/* A row whose content is NOT wrapped in .row-main carries its own padding.
   Without it the text sits flush against the card edge, and a 20px corner
   radius with overflow:hidden then shaves the first letter and the top of the
   line off - which is exactly what the subscriber list was doing. */
.card.row.pad { padding:12px 14px; }
.card.row.pad + .card.row.pad { margin-top:8px; }
.card.row .row-main { padding:12px 14px; cursor:pointer; position:relative; }
.card.row .row-main:hover { background:var(--panel-2); }
.card.row .chev { position:absolute; right:12px; bottom:10px; color:var(--dimmer); font-size:0.8125rem; transition:transform .18s; }
.card.row.open .chev { transform:rotate(180deg); }
.card.row.open { border-color:var(--dim); }
.card.row.danger { border-left:2px solid var(--down); }
.expand:not(:empty) { padding:2px 14px 14px; border-top:1px solid var(--line-soft); }
.menu { display:grid; gap:6px; }

.mono { font-family:var(--font); }
.up { color:var(--up); } .down { color:var(--down); } .dim { color:var(--dim); }
.muted { color:var(--dimmer); font-size:0.75rem; }
.empty { color:var(--dim); text-align:center; padding:34px 16px; font-size:0.78125rem; }
.empty b { display:block; color:var(--ink); font-size:0.875rem; margin-bottom:5px;
           letter-spacing:.1em; text-transform:uppercase; }

/* ── bars ─────────────────────────────────────────────────────────── */
.bar { height:5px; border-radius:0; background:var(--sunk); overflow:hidden; border:1px solid var(--line-soft); }
.bar > i { display:block; height:100%; border-radius:0; background:var(--accent); }
.bar.risk > i { background:var(--down); }

/* ── signal / position rows ───────────────────────────────────────── */
.row-head { display:flex; align-items:baseline; gap:8px; }
.row-head .pair { font-size:0.9375rem; font-weight:700; letter-spacing:.06em; }
.row-head .quote { font-size:0.6875rem; color:var(--dimmer); }
.row-head .chg { margin-left:auto; font-size:0.9375rem; font-weight:700; }
.row-sub { display:flex; gap:12px; flex-wrap:wrap; margin-top:7px; font-size:0.71875rem; color:var(--dim); }
.row-sub b { color:var(--ink); font-weight:600; }

.ladder { display:flex; gap:3px; margin-top:10px; }
.ladder i { flex:1; height:3px; border-radius:0; background:var(--line); }
.ladder i.hit:nth-child(1),.ladder i.hit:nth-child(2),
.ladder i.hit:nth-child(3),.ladder i.hit:nth-child(4){ background:var(--up); }

/* ── where price sits against the base ────────────────────────────── */
.track { margin-top:10px; }
.track-top { display:flex; align-items:baseline; gap:8px; font-size:0.6875rem; }
.track-k { color:var(--dimmer); letter-spacing:.14em; text-transform:uppercase; font-size:0.59375rem; }
.track-v { color:var(--ink); }
.track-gap { margin-left:auto; font-weight:700; }
.track-bar { position:relative; height:7px; border-radius:0; background:var(--sunk); margin-top:6px;
             border:1px solid var(--line); overflow:visible; }
.track-fill { position:absolute; left:0; top:0; bottom:0; border-radius:0; background:var(--up-soft); }
.track-entry { position:absolute; top:-3px; width:1px; height:13px; background:var(--dimmer); transform:translateX(0); }
.track-now { position:absolute; top:-4px; width:3px; height:15px; border-radius:0;
             background:var(--up); transform:translateX(-1px); }
.track.under .track-fill { background:var(--down-soft); }
.track.under .track-bar { border-color:var(--down-line); }
.track.under .track-now { background:var(--down); }
.track-foot { display:flex; justify-content:space-between; gap:8px; margin-top:5px;
              font-size:0.59375rem; color:var(--dimmer); }
.base-note { border:1px solid var(--down-line); background:var(--down-soft);
             border-radius:0; padding:9px 11px; font-size:0.71875rem; color:var(--ink);
             margin:10px 0; line-height:1.45; }

.targets { display:flex; flex-direction:column; gap:0; margin-top:5px;
           border:1px solid var(--line-soft); }
.t-row { display:flex; align-items:center; gap:9px; padding:7px 10px; border-radius:0;
         background:transparent; border:0; border-bottom:1px solid var(--line-soft); }
.targets .t-row:last-child { border-bottom:0; }
.t-row.hit { background:var(--up-soft); }
.t-row .n { font-size:0.6875rem; color:var(--dimmer); width:20px; }
.t-row .px { font-size:0.8125rem; }
.t-row .pct { margin-left:auto; font-size:0.75rem; color:var(--accent); }
.t-row .away { font-size:0.6875rem; color:var(--dimmer); }
.t-row .mark { font-size:0.75rem; }

.actions { display:flex; gap:6px; flex-wrap:wrap; margin-top:12px; }
.actions .btn { flex:1 1 auto; min-width:100px; }

/* ── tables ───────────────────────────────────────────────────────── */
.table-wrap { overflow-x:auto; -webkit-overflow-scrolling:touch; }
table { width:100%; border-collapse:collapse; font-size:0.78125rem; }
th { text-align:left; font-size:0.59375rem; letter-spacing:.16em; text-transform:uppercase;
     color:var(--dimmer); font-weight:700; padding:7px 10px;
     border-bottom:1px solid var(--line); white-space:nowrap; }
td { padding:8px 10px; border-bottom:1px solid var(--line-soft); font-size:0.75rem; white-space:nowrap; }
tr:last-child td { border-bottom:0; }
tbody tr:hover td { background:var(--panel-2); }
td.name { font-weight:700; }
.num { text-align:right; }

/* ── settings ─────────────────────────────────────────────────────── */
.setting { padding:12px 0; border-bottom:1px solid var(--line-soft); }
.setting:last-child { border-bottom:0; }
.setting-top { display:flex; align-items:center; gap:11px; }
.setting-label { font-weight:700; font-size:0.75rem; letter-spacing:.08em; text-transform:uppercase; }
.setting-value { margin-left:auto; font-size:0.875rem; color:var(--accent); font-weight:600; }
.setting-help { color:var(--dim); font-size:0.71875rem; margin-top:5px; max-width:70ch; line-height:1.5; }
.stepper { display:flex; gap:5px; margin-top:9px; flex-wrap:wrap; }
.stepper .btn { min-width:40px; }
.jump { background:transparent; border:1px solid var(--line); color:var(--dim); }
.jump.on { border-color:var(--accent); color:var(--accent); background:var(--accent-soft); }
.toggle { width:46px; height:22px; border-radius:0; border:1px solid var(--line);
          background:var(--sunk); position:relative; cursor:pointer; flex:0 0 auto; }
.toggle::after { content:""; position:absolute; top:2px; left:2px; width:16px; height:16px;
                 border-radius:0; background:var(--dimmer); transition:transform .16s, background .16s; }
.toggle.on { background:var(--up-soft); border-color:var(--up-line); }
.toggle.on::after { transform:translateX(22px); background:var(--up); }

/* ── chart ────────────────────────────────────────────────────────── */
.chart-wrap { position:relative; min-width:0; }
canvas { display:block; width:100%; max-width:100%; border-radius:0; }
.chart-tabs { display:flex; gap:4px; margin-bottom:9px; flex-wrap:wrap; align-items:center; }
.chart-tabs .btn { padding:3px 9px; font-size:0.6875rem; min-width:32px; }
.chart-tabs .btn.on { border-color:var(--accent); color:var(--accent); background:var(--accent-soft); }
.chart-sep { flex:1 1 auto; }
.chart-hint { margin-top:6px; font-size:0.625rem; color:var(--dimmer); letter-spacing:.06em; }
/* Sideways is the chart's; downwards stays the page's, so a finger on the
   chart can still scroll past it. */
canvas.chart { touch-action:pan-y; cursor:grab; }
canvas.chart:active { cursor:grabbing; }

/* ── sheet ────────────────────────────────────────────────────────── */
.sheet-wrap { position:fixed; inset:0; z-index:50; display:flex; align-items:center; justify-content:center; }
.sheet-scrim { position:absolute; inset:0; background:rgba(7,16,30,.68); }
:root[data-theme="light"] .sheet-scrim { background:rgba(18,33,53,.38); }
.sheet {
  position:relative; width:min(450px,100%); max-height:88dvh; overflow-y:auto;
  background:var(--panel); border:1px solid var(--line); border-radius:0;
  padding:18px; box-shadow:var(--shadow); animation:rise .16s ease-out;
}
@keyframes rise { from { opacity:0; transform:translateY(12px); } }
.sheet h2 { font-size:0.8125rem; letter-spacing:.16em; text-transform:uppercase; color:var(--accent); margin-bottom:4px; }
.sheet .sub { color:var(--dim); font-size:0.75rem; margin-bottom:14px; }
.sheet .kv { display:flex; justify-content:space-between; gap:14px; padding:6px 0;
             border-bottom:1px solid var(--line-soft); font-size:0.78125rem; }
.sheet .kv span { color:var(--dim); }
.sheet .kv b { font-weight:700; }
.sheet .warn-box { border:1px solid var(--down-line); background:var(--down-soft); border-radius:0;
                   padding:10px 12px; font-size:0.75rem; color:var(--ink); margin:12px 0; }
.sheet .note-box { border:1px solid var(--line); background:var(--sunk); border-radius:0;
                   padding:10px 12px; font-size:0.75rem; color:var(--dim); margin:12px 0; white-space:pre-wrap; }
.chips { display:flex; gap:6px; flex-wrap:wrap; margin:8px 0 4px; }
.chip { padding:6px 12px; border-radius:var(--r-pill); border:1px solid var(--line);
        background:var(--panel-2); cursor:pointer; font-family:var(--font); font-size:0.75rem; }
.chip:hover { border-color:var(--dim); }
.chip.on { border-color:var(--accent); color:var(--accent); background:var(--accent-soft); }
/* a thin book, marked wherever the pair appears — never blocked, just visible */
.chip.thin { border-color:var(--accent-line); color:var(--accent); background:transparent; }
.chip.on.thin { background:var(--accent-soft); }
.card.warn { border-color:var(--accent-line); background:var(--accent-soft); }
.card.warn .setting-help { color:var(--ink); }

/* ── toasts ───────────────────────────────────────────────────────── */
/* Notices arrive at the TOP. At the bottom they sat under the thumb, behind
   the tab bar on a phone, and away from the header where a change is being
   read — so the confirmation for an action was the one thing on screen most
   likely to be missed. */
.toasts { position:fixed; z-index:70; left:50%; transform:translateX(-50%);
          top:calc(var(--bar-h) + var(--safe-t) + 10px);
          display:flex; flex-direction:column; gap:6px;
          width:min(440px,calc(100% - 24px)); pointer-events:none; }
.toast { background:var(--panel); border:1px solid var(--line); border-left:2px solid var(--accent);
         border-radius:0; padding:10px 13px; font-size:0.78125rem; box-shadow:var(--shadow);
         animation:rise .16s ease-out; white-space:pre-wrap; }
.toast.good { border-left-color:var(--up); }
.toast.bad { border-left-color:var(--down); }

/* ── mobile ───────────────────────────────────────────────────────────
   Width is the usual signal and the wrong one on its own: an iPhone turned
   sideways is 932px, and "Request Desktop Website" reports wider still. A
   coarse pointer with no hover is a touch screen whatever its width, and a
   touch screen wants the tab bar. */
@media (max-width:900px), (hover:none) and (pointer:coarse) and (max-width:1100px) {
  body { font-size:0.875rem; }
  /* The header row was a FIXED 52px, so the moment the title wrapped to a
     second line that line had nowhere to go: it spilled out of the bar and
     landed on top of the first section heading. The row is sized by its own
     content now, which is the only honest height for a bar that can wrap. */
  .app { grid-template-columns:1fr; grid-template-rows:auto 1fr; --bar-h:52px; }
  .rail { display:none; }
  /* The header put the title in the SAME row as the controls, with no bottom
     padding at all and nothing between it and the status bar. On a phone that
     squeezed the title to an ellipsis, pushed the last control off the right
     edge, and left the whole bar pressed against the clock above it. Row one
     is the controls; row two is the title, with the width to itself. */
  .top { grid-column:1; flex-wrap:wrap; row-gap:6px;
         padding:calc(var(--safe-t) + 8px) calc(12px + var(--safe-r))
                 9px calc(12px + var(--safe-l)); }
  .top .status { order:3; flex:1 1 100%; gap:8px; }
  .top-right { flex-wrap:wrap; justify-content:flex-end; row-gap:6px; min-width:0; }
  .view { grid-column:1;
          padding:12px calc(12px + var(--safe-r)) calc(92px + var(--safe-b)) calc(12px + var(--safe-l)); }
  .only-mobile { display:inline-flex; }
  .grid.tiles { grid-template-columns:repeat(2,1fr); }
  .tile .v { font-size:1.125rem; }
  /* Every rule below is the same layout with less air. A phone spends its
     height on the numbers, not on the space around them. */
  .card { padding:11px 12px; }
  .grid { gap:8px; }
  .section-title { margin:14px 0 7px; }
  .sec { margin:13px 0 7px; }
  .card-head { margin-bottom:8px; padding-bottom:7px; }
  .tabs {
    display:grid; grid-auto-flow:column; position:fixed; left:0; right:0; bottom:0; z-index:30;
    background:var(--panel); border-top:1px solid var(--line);
    padding:6px calc(4px + var(--safe-r)) calc(6px + var(--safe-b)) calc(4px + var(--safe-l));
  }
  .tabs button { background:none; border:0; color:var(--dimmer); display:flex; flex-direction:column;
                 align-items:center; gap:2px; font-family:var(--font); font-size:0.5625rem;
                 letter-spacing:.1em; text-transform:uppercase; padding:4px 2px; cursor:pointer; }
  .tabs button .glyph { font-size:1.0625rem; line-height:1; }
  .tabs button.on { color:var(--accent); }
  .sheet { align-self:flex-end; width:100%; max-width:none; border-radius:0;
           border-left:0; border-right:0; border-bottom:0;
           padding-bottom:calc(18px + var(--safe-b)); animation:up .18s ease-out; }
  .sheet-wrap { align-items:flex-end; }

  /* ...except the navigation, which slides in from the left. A hamburger is
     a promise about where a menu lives; answering it from the bottom edge
     makes the button and the panel disagree. */
  .sheet-wrap.nav { align-items:stretch; justify-content:flex-start; }
  .sheet-wrap.nav .sheet {
    align-self:stretch; width:min(310px,84vw); max-width:none; height:100%;
    border-radius:0; border-top:0; border-bottom:0; border-left:0;
    border-right:1px solid var(--line);
    padding:calc(16px + var(--safe-t)) 16px calc(16px + var(--safe-b));
    overflow-y:auto; animation:in-left .18s ease-out;
  }
  @keyframes in-left { from { transform:translateX(-100%); } }
  @keyframes up { from { transform:translateY(100%); } }
  .actions .btn { flex:1 1 44%; }
  .toasts { top:calc(var(--bar-h) + var(--safe-t) + 8px); bottom:auto; }

  /* the header keeps a live light and the name of the screen; the engine
     detail it used to carry now lives in the controls strip, where it has
     a button next to it */
  .wide-only { display:none; }
  .conn { left:0; }
  .grid.two { grid-template-columns:1fr; }
  .quick .btn { font-size:0.6875rem; }

  /* The five keys wrap into a block instead of scrolling sideways. A control
     you have to swipe to discover is a control you forget you have — and the
     scroll competed with the page's own. */
  .strip { flex-wrap:wrap; overflow-x:visible; }
  .ctl { flex:1 1 33%; width:auto; min-width:0; border-bottom:1px solid var(--line-soft); }
  .ctl:nth-child(3n) { border-right:0; }
  .ctl:nth-last-child(-n+2) { border-bottom:0; }

  /* Two by two rather than four across — still one band, still no scrolling
     to reach the fourth reading. */
  .cells { grid-template-columns:1fr 1fr; }
  .cell { border-bottom:1px solid var(--line-soft); }
  .cell:nth-child(2n) { border-right:0; }
  .cell:nth-child(n+3) { border-bottom:0; }
  .cell-v { font-size:1.125rem; }

  /* The table keeps its columns on a phone — that is the whole point of it —
     but drops to four, folding "now" into the expand where there is a chart
     to read it against anyway. */
  .thead, .trow { grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) minmax(0,1fr) minmax(0,.9fr); gap:6px; }
  .thead > :nth-child(3), .trow > :nth-child(3) { display:none; }
  .thead { padding:5px 11px; }
  .card.row .row-main { padding:10px 11px; }
  .tsym { font-size:0.78125rem; }
  .tnum { font-size:0.71875rem; }
  .trow .chg { font-size:0.78125rem; }
  .card.row .chev { display:none; }
}

@media (prefers-reduced-motion:reduce) { * { animation:none !important; transition:none !important; } }

/* ── action bars ───────────────────────────────────────────────────
 *
 * `.actions` used to be a wrapping flex row. On a desk that reads as
 * disorder: the same three buttons sit side by side at one width and
 * two-and-one at another, so the control you reach for moves depending on
 * how wide the panel happens to be. Position is memory — a button that
 * moves has to be read every time.
 *
 * auto-fit + minmax gives equal columns that depend only on WIDTH. It is
 * deliberately not a declared column count: several of these bars have
 * conditional children (Buy appears only when buying is allowed), so any
 * number written here would be right on one render and wrong on the next.
 * One rule, no counting, nothing to keep in sync.
 */
.actions {
  display:grid; gap:6px; margin-top:12px;
  grid-template-columns:repeat(auto-fit,minmax(132px,1fr));
}
/* The irreversible one never shares a row. */
.actions.solo  { grid-template-columns:1fr; margin-top:8px; }
/* Two long labels side by side truncate before they inform. Stack them. */
.actions.stack { grid-template-columns:1fr; }

/* ── one rhythm for every list ─────────────────────────────────────
 *
 * Rows sized themselves by content, so a list of positions breathed
 * unevenly down the page and the eye had to re-find the columns on each
 * one. A single height is most of what separates a terminal from a page of
 * divs.
 */
/* The floor was on the TEXT line, so one line of figures sat at the top of a
   44px box with two thirds of it empty — the blank band under every position
   and every signal. The row is a comfortable target without it: its own
   padding and the meta line under it already carry more than 44px. */
.trow { min-height:0; }

/* Numbers line up or they are not numbers. Applies to every cell that
   carries a figure, not only the ones that remembered to ask. */
.tnum, .tid, .quote, .stat-v, .row-sub b { font-variant-numeric:tabular-nums; }

/* ---- chart: the crosshair layer ------------------------------------------
   The overlay sits exactly on the chart canvas and takes the pointer, so the
   readout can redraw on every move without repainting the candles. It must
   not block the drag-to-pan handlers on the canvas beneath, which is why the
   touch-action matches rather than being set to none. */
.chart-stage { position:relative; }
.chart-stage canvas { display:block; width:100%; }
canvas.chart-cross {
  position:absolute; inset:0; touch-action:pan-y; cursor:crosshair;
}
.chart-readout {
  min-height:15px; margin-bottom:6px; font:11px/1.35 ui-monospace, monospace;
  color:var(--dim); letter-spacing:.02em; white-space:nowrap;
  overflow-x:auto; scrollbar-width:none;
}
.chart-readout::-webkit-scrollbar { display:none; }
.chart-readout.up   { color:var(--up); }
.chart-readout.down { color:var(--down); }


/* =========================================================================
   LIQUID GLASS  —  the iOS 26 material
   -------------------------------------------------------------------------
   Everything above this line is the flat terminal look the dashboard was
   built with: square corners, hairline borders, no depth. This is one
   additive block so it can be cut out whole to get that back.

   iOS 26 replaced flat translucency with a material that behaves like real
   glass. Four properties do the work, and skipping any one of them leaves a
   frosted panel rather than glass:

     1. REFRACTION  a heavy blur with saturation lifted, so colour bleeds
                    through from whatever is behind rather than being greyed
     2. SPECULAR    a bright hairline along the top edge and a dark one along
                    the bottom - the highlight a curved surface catches
     3. FLOAT       controls sit ON the content with a gap to the screen
                    edge, and content scrolls UNDER them, instead of bars
                    that own a strip of the layout
     4. CONCENTRIC  a radius that follows the shape it sits inside: the inner
                    corner equals the outer minus the padding, which is why
                    nesting looks machined rather than stacked

   Everything else here is what makes any web page usable on glass: 44px
   targets, 16px inputs, safe-area insets.
   ========================================================================= */
:root {
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-xl: 28px;
  --tap: 44px;
  --glass-tint: 62%;              /* how much panel colour survives the blur */
  --glass-blur: 28px;
  --glass-edge: color-mix(in srgb, white 20%, transparent);
  --glass-edge-dim: color-mix(in srgb, #050c18 22%, transparent);
  --glass-lift: 0 10px 34px rgb(6 14 26 / .34), 0 2px 8px rgb(6 14 26 / .20);
}

/* 1 + 2: the material itself. Applied by name so anything can be made of it
   without repeating six declarations. */
.glass, header, .topbar, .tabs, .sheet, .modal-body, .chart-tabs, .card {
  background: color-mix(in srgb, var(--panel) var(--glass-tint), transparent);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(190%);
  backdrop-filter: blur(var(--glass-blur)) saturate(190%);
  border: 0.5px solid var(--glass-edge);
  box-shadow:
    inset 0 0.5px 0 var(--glass-edge),
    inset 0 -0.5px 0 var(--glass-edge-dim),
    var(--glass-lift);
}
/* Cards are the one surface that must not glow: a screen of forty signals
   with a lift on each is soup. They keep the material and lose the shadow. */
.card { box-shadow: inset 0 0.5px 0 var(--glass-edge),
                    inset 0 -0.5px 0 var(--glass-edge-dim); }

/* 4: concentric radii */
.card, .sheet, .modal-body, .empty { border-radius: var(--r-lg); }
.btn, input, select, textarea, .pick { border-radius: var(--r-md); }
.btn.small, .chip, .tag, .pill, .tabs { border-radius: 999px; }
.card .card, .card .empty { border-radius: var(--r-md); }

/* 3: the tab bar floats, and content scrolls under it */
.tabs {
  position: fixed; z-index: 40;
  left: max(12px, env(safe-area-inset-left));
  right: max(12px, env(safe-area-inset-right));
  bottom: max(10px, calc(env(safe-area-inset-bottom) + 4px));
  padding: 5px; gap: 2px;
}
main, .scroll { padding-bottom: calc(var(--tap) + 34px); }
header, .topbar {
  position: sticky; top: 0; z-index: 30;
  padding-top: max(10px, env(safe-area-inset-top));
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
body { padding-left: env(safe-area-inset-left);
       padding-right: env(safe-area-inset-right); }

/* controls: capsules that light up rather than change colour */
.btn { min-height: var(--tap); padding: 10px 17px; }
.btn.small { min-height: 34px; padding: 7px 14px; }
.tabs button { min-height: var(--tap); border-radius: 999px; }
.tabs button.on {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  box-shadow: inset 0 0.5px 0 var(--glass-edge);
}
/* Never under 16px however the dial is set: Safari zooms the whole page
   when it focuses a field whose text is smaller than that. */
input, select, textarea { min-height: var(--tap); font-size: max(16px, 1rem); }
/* 16px is not a preference: anything smaller makes iOS Safari zoom the whole
   page the moment a field takes focus. */

/* A field had no ground of its own, so it fell through to whatever the
   browser paints for `color-scheme: dark` — a neutral grey. Against a warm
   black that passed; against navy it is plainly a different material, and
   the sign-in screen is two grey slabs on a blue card. So the fields are
   made of the same tokens as everything else. */
input, select, textarea {
  background: var(--sunk);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: 10px 12px;
}
input::placeholder, textarea::placeholder { color: var(--dimmer); opacity: 1; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent-line);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
input:disabled, select:disabled, textarea:disabled {
  color: var(--dim); background: var(--panel); cursor: not-allowed;
}
/* Chrome paints its own ground on an autofilled field and ignores
   `background`. The inset shadow is the only thing it honours. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: 0 0 0 1000px var(--sunk) inset;
  caret-color: var(--ink);
}

/* the interval row as a segmented control, glass on glass */
.chart-tabs { padding: 3px; gap: 2px; border-radius: var(--r-md); }
.chart-tabs .btn {
  min-height: 32px; flex: 1 1 0; min-width: 0; border: 0;
  background: transparent; box-shadow: none;
  border-radius: calc(var(--r-md) - 3px);   /* concentric with its parent */
}
.chart-tabs .btn.on {
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  box-shadow: inset 0 0.5px 0 var(--glass-edge), 0 1px 3px rgb(0 0 0 / .25);
  color: var(--text);
}
.chart-sep { flex: 0 0 6px; }

/* sheets: rounded only at the top, with the grab handle iOS puts on anything
   draggable */
.sheet {
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  padding-bottom: max(18px, env(safe-area-inset-bottom));
}
.sheet::before {
  content: ''; display: block; width: 36px; height: 5px; border-radius: 999px;
  background: color-mix(in srgb, var(--dim) 60%, transparent);
  margin: 9px auto 15px;
}

/* press feedback: the platform dims, it does not recolour */
.btn:active, .tabs button:active { opacity: .55; transition: opacity .06s; }

/* prices stay monospaced and tabular. A column that shifts by a pixel per
   digit is harder to read however native the rest looks. */
.num, td.num, .price, .chart-readout { font-variant-numeric: tabular-nums; }

html, body { overscroll-behavior-y: none; }
.scroll, .sheet, .modal-body { -webkit-overflow-scrolling: touch; }

/* Blur is expensive and not universal. Without support the material would
   fall back to a nearly transparent panel with text over content, so the
   tint goes opaque instead - less beautiful, still readable. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass, header, .topbar, .tabs, .sheet, .modal-body, .chart-tabs, .card {
    background: var(--panel);
  }
}
@media (prefers-reduced-transparency: reduce) {
  .glass, header, .topbar, .tabs, .sheet, .modal-body, .chart-tabs, .card {
    background: var(--panel); backdrop-filter: none; -webkit-backdrop-filter: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .btn:active, .tabs button:active { transition: none; }
}


/* ---- subscriber accounts ------------------------------------------------ */
.join { display:flex; flex-direction:column; gap:10px; text-align:left; }
.join-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
.join-head h2 { margin:0; font-size:1.1875rem; }
.join-price { font-size:0.9375rem; }
.join-err { min-height:16px; font-size:0.75rem; color:var(--down); }
.join input { width:100%; }

.sub-card { display:flex; flex-direction:column; gap:10px; }
.sub-status { display:flex; align-items:baseline; gap:10px; }
.sub-status.on  b { color:var(--up); }
.sub-status.off b { color:var(--warn, var(--down)); }

.pay { display:flex; flex-direction:column; gap:9px; }
.pay-line { display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
/* An address is long and must never be truncated into something that looks
   complete but is not — it wraps instead. */
.pay-addr { word-break:break-all; font-size:0.75rem; }
.pay-line.ref code { font-size:0.9375rem; letter-spacing:.08em; }
.tx { font-size:0.6875rem; color:var(--dim); word-break:break-all; }

.stat-row { display:grid; grid-template-columns:repeat(auto-fit,minmax(84px,1fr));
            gap:9px; margin-bottom:12px; }
.stat { padding:11px; text-align:center; }
.stat-v { font-size:1.3125rem; font-weight:700; font-variant-numeric:tabular-nums; }
.stat-k { font-size:0.6875rem; color:var(--dim); }

.pill { padding:2px 9px; font-size:0.6875rem; border:1px solid var(--line); }
.pill.active  { color:var(--up);   border-color:var(--up); }
.pill.pending { color:var(--warn, var(--accent)); border-color:var(--accent); }
.pill.expired,
.pill.blocked { color:var(--down); border-color:var(--down); }


/* ---- packages ----------------------------------------------------------- */
.plans { display:grid; grid-template-columns:repeat(2,1fr); gap:8px; }
.plan { padding:11px 9px; text-align:center; cursor:pointer;
        border:1px solid var(--line); background:var(--panel); }
.plan.on { border-color:var(--accent); background:var(--accent-soft); }
/* A package the owner switched off is greyed, not removed. It must still be
   legible - "unavailable" is information, and information you cannot read is
   not information. */
.plan.off { opacity:.42; cursor:not-allowed; filter:grayscale(1); }
.plan-name { font-weight:700; font-size:0.8125rem; }
.plan-price { font-size:1.0625rem; font-variant-numeric:tabular-nums; }
.plan-days { font-size:0.6875rem; color:var(--dim); }

/* ---- support thread ----------------------------------------------------- */
.thread { display:flex; flex-direction:column; gap:7px; margin:10px 0;
          max-height:52vh; overflow-y:auto; }
.bubble { max-width:78%; padding:8px 11px; font-size:0.8125rem; line-height:1.4;
          border:1px solid var(--line); }
.bubble.me   { align-self:flex-end; background:var(--accent-soft);
               border-color:var(--accent); }
.bubble.them { align-self:flex-start; background:var(--panel-2); }
.bubble-at { margin-top:3px; font-size:0.625rem; color:var(--dim); }
.composer { display:flex; gap:8px; align-items:flex-end; }
.composer textarea { flex:1 1 auto; resize:vertical; font-family:var(--font);
                     font-size:1rem; padding:9px; }
.btn.danger { color:var(--down); border-color:var(--down); }
.join-err.good { color:var(--up); }

/* ---- paying: which address, on which network ---------------------------- */
.ways { display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
        gap:8px; margin:8px 0; }
.way { padding:9px 8px; text-align:left; cursor:pointer;
       border:1px solid var(--line); background:var(--panel); }
.way.on { border-color:var(--accent); background:var(--accent-soft); }
.way-label { font-weight:600; font-size:0.78125rem; }
.way-net { font-size:0.6875rem; color:var(--dim); letter-spacing:.08em; }
/* The network is the one detail a mistake cannot be recovered from: the same
   address can exist on chains that cannot see each other. So it is loud. */
.pay-line.net .net-name { color:var(--accent); letter-spacing:.1em;
                          font-weight:700; }
.pay-line.net .muted { flex:1 1 100%; font-size:0.6875rem; }

/* ---- tickets ------------------------------------------------------------ */
.card.row.shut { opacity:.62; }
.card.row.shut b { font-weight:600; }
.pill.dim { color:var(--dim); border-color:var(--line); }
.join .muted { font-size:0.71875rem; line-height:1.45; }
.btn.wide.small { font-size:0.71875rem; padding:7px 10px; }


/* ---- manual composer ----------------------------------------------------- */
.field-label { margin:12px 0 5px; font-size:0.6875rem; letter-spacing:.1em;
               text-transform:uppercase; color:var(--dim); }
.two-up { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.tgt-rows { display:flex; flex-direction:column; gap:7px; }
.tgt-row { display:flex; align-items:center; gap:8px; }
.tgt-row input { flex:1 1 auto; min-width:0; }
.tgt-n { font-size:0.6875rem; font-weight:700; color:var(--dim); width:22px; }
/* The percentage is the thing actually being promised to a subscriber; the
   price alone means nothing without it, so it is shown while it is typed. */
.tgt-pct { min-width:64px; text-align:right; font-size:0.78125rem;
           font-variant-numeric:tabular-nums; color:var(--dim); }
.tgt-pct.up { color:var(--up); } .tgt-pct.down { color:var(--down); }
.stop-line { display:flex; align-items:center; gap:7px; flex-wrap:wrap;
             margin-top:7px; font-size:0.75rem; }
.stop-line input { width:70px; }
.stop-line select { padding:7px; font-family:var(--font); }

.seg { display:flex; gap:6px; flex-wrap:wrap; }
.seg.vert { flex-direction:column; }
.seg-b { padding:9px 12px; font-size:0.78125rem; cursor:pointer; text-align:left;
         border:1px solid var(--line); background:var(--panel); }
.seg-b.on { border-color:var(--accent); background:var(--accent-soft); }

.tgt-strip { display:flex; gap:6px; flex-wrap:wrap; margin-top:7px; }
.tgt-chip { font-size:0.6875rem; padding:3px 7px; border:1px solid var(--line);
            border-radius:3px; }
.tgt-chip.hit { border-color:var(--up); color:var(--up); }
.note-card { display:flex; align-items:center; gap:10px; }

/* ---- permissions --------------------------------------------------------- */
.perms { display:flex; gap:6px; flex-wrap:wrap; margin-top:8px; }
.perm { font-size:0.71875rem; padding:6px 10px; cursor:pointer;
        border:1px solid var(--line); background:var(--panel); color:var(--dim); }
.perm.on { border-color:var(--accent); background:var(--accent-soft);
           color:var(--ink); }

/* ---- detectors ----------------------------------------------------------- */
.det-pick { display:flex; flex-direction:column; gap:8px; }
.det-b { text-align:left; padding:10px 11px; cursor:pointer;
         border:1px solid var(--line); background:var(--panel); }
.det-b.on { border-color:var(--accent); background:var(--accent-soft); }
.det-name { font-weight:700; font-size:0.8125rem; }
.det-what { font-size:0.71875rem; color:var(--dim); line-height:1.45; margin-top:3px; }
.det-frame { font-size:0.65625rem; color:var(--dimmer); letter-spacing:.06em;
             margin-top:3px; }
.det-head { display:flex; align-items:center; gap:10px; }
.det-glyph { font-size:1.375rem; }
.det-p { font-size:0.8125rem; line-height:1.55; margin:9px 0 0; }
.warn-p { color:var(--down); }
.def-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
            gap:6px; }
.def { display:flex; justify-content:space-between; gap:8px; font-size:0.71875rem;
       padding:5px 8px; background:var(--panel-2); border:1px solid var(--line); }
.def-k { color:var(--dim); }
.def-v { font-variant-numeric:tabular-nums; font-weight:600; }

/* ---- a subscriber's own settings ----------------------------------------- */
.set-row { display:flex; align-items:center; justify-content:space-between;
           gap:14px; padding:12px 14px; }
.set-k { font-size:0.84375rem; font-weight:600; }
.set-help { font-size:0.71875rem; color:var(--dim); line-height:1.45; margin-top:3px;
            max-width:52ch; }
.set-v { min-width:62px; text-align:center; font-variant-numeric:tabular-nums; }
.stepper { display:flex; align-items:center; gap:8px; flex:0 0 auto; }
.set-row .pill { cursor:pointer; margin-left:8px; }

/* A setting you type into rather than step through. Wide enough for a wallet
   address, and monospaced so a transposed character is visible. */
/* A setting you type into rather than step through. Full width on its own
   line, monospaced so a transposed character in an address is visible, and
   sized so a 42-character address is readable without scrolling it. */
.set-text { display:block; width:100%; margin-top:9px; box-sizing:border-box;
            font-family:ui-monospace, "JetBrains Mono", Menlo, monospace;
            font-size:max(16px, 0.875rem); padding:9px 11px; }
.set-text:focus { border-color:var(--accent); outline:none; }
/* The typed box for a number setting. Narrow, centred and tabular, so it
   reads as a value beside its arrows rather than as a form field. */
.set-num { width:92px; text-align:center; box-sizing:border-box;
           font-family:ui-monospace, "JetBrains Mono", Menlo, monospace;
           font-size:max(16px, 0.875rem); padding:8px 6px; font-variant-numeric:tabular-nums; }
.set-num:focus { border-color:var(--accent); outline:none; }
.set-unit { color:var(--dim); font-size:0.75rem; }

/* ---- packages and payment addresses ------------------------------------- */
.packs { display:grid; gap:12px; }
.pack { border:1px solid var(--line); background:var(--panel-2); padding:12px 13px; }
/* Off is greyed, not hidden: a card that vanishes reads as a fault, and you
   still need to see what is switched off in order to switch it back on. */
.pack.off { opacity:.55; }
.pack.off .pf { color:var(--dim); }
.pack-top { display:flex; align-items:center; gap:10px; margin-bottom:10px; }
.pack-top b { font-size:0.8125rem; letter-spacing:.04em; }
.pack-grid { display:grid; gap:10px;
             grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); }
.pack-note { margin-top:9px; font-size:0.71875rem; color:var(--dim); line-height:1.45; }
.pf-lab { font-size:0.65625rem; letter-spacing:.1em; text-transform:uppercase;
          color:var(--dim); margin-bottom:4px; }
.pf { width:100%; box-sizing:border-box; padding:8px 10px; font-size:0.8125rem;
      font-family:var(--font); }
/* An address is long and gets read character by character when it is checked,
   so it is monospaced. */
.pf-wide { font-family:ui-monospace,"JetBrains Mono",Menlo,monospace;
           font-size:0.75rem; }
.pf-num { font-variant-numeric:tabular-nums; }
.pf:focus { border-color:var(--accent); outline:none; }
.pf-switch { display:flex; align-items:center; gap:8px; height:34px; }
.pf-switch .dim { font-size:0.6875rem; }

/* A caveat that belongs beside a number, not under it. Used where a table is
   true but easy to read as something it is not — a score that was recorded
   and never applied being the case that prompted it. */
.note {
  margin: 10px 0 14px;
  padding: 10px 12px;
  border-left: 3px solid var(--warn, #d9a441);
  background: color-mix(in srgb, var(--warn, #d9a441) 8%, transparent);
  border-radius: 6px;
  font-size: 0.8125rem;
  line-height: 1.5;
}
.note b { color: var(--warn, #d9a441); }

/* A heading over a run of settings. Only drawn when there is more than one
   group to separate — a lone heading over the whole list is furniture. */
.group-head {
  margin: 18px 4px 8px;
  font-size: 0.75rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--dimmer);
}
/* "How it decides" — folded away by default. The detail is worth having and
   is not worth pushing the controls off the first screen. */
.det-more { margin-top: 8px; }
.det-more summary {
  cursor: pointer;
  font-size: 0.8125rem;
  color: var(--accent);
  padding: 4px 0;
}
.det-more[open] summary { margin-bottom: 4px; }
