/* ============================================================================
   QUERYABLE INDEX — second brain Mini App
   The archive is an instrument you query, printed on greenbar fanfold.

   Two type families do all the work:
     REGISTER (mono)  every id, count, date, label, filter token, the query
                      itself. tabular-nums wherever numbers stack.
     RECORD   (sans)  titles and summaries only. Never metadata.

   Nothing here loads from the network: system fonts, inline SVG, no image.
   ========================================================================= */


/* ── 1. COLOUR ────────────────────────────────────────────────────────────
   The ledger palette is app-owned. Telegram's themeParams are read into
   --tg-* tokens by app.js and consumed only where the app meets Telegram's
   own chrome (--backdrop, --focus); letting them drive paper/ink would erase
   the greenbar identity, and the header/background are pushed the other way
   with setHeaderColor/setBackgroundColor instead.

   MEASURED CONTRAST (WCAG 2.1, sRGB) — every text token against every ground
   it can land on. Verified, not assumed; recompute before changing a value.

   LIGHT   ground:        paper #E8EAE3   bar #DCE0D4   surface #F1F3EC
     ink       #171C1B      14.21           12.85         15.41
     dust      #546059       5.42            4.90          5.88   ← was 4.14
     vermilion #A8331A       5.49            4.96          5.95   ← was 4.25
     verdigris #16645A       5.76            5.21          6.25
     paper on ink (inverted primary action)  14.21

   DARK    ground:        paper #0F1413   bar #1C2422   surface #151B1A
                          bar-gut #232D2A
     ink       #DEE4DB      14.36           12.25         13.48   / 10.96
     dust      #93A39B       7.04            6.00          6.61   /  5.37
     vermilion #F0805C       7.03            6.00          6.60   /  5.36
     verdigris #5AD0B7       9.86            8.41          9.26   /  7.53
     paper on ink (inverted primary action)  14.36

   Worst case anywhere: 4.90:1. No token drops below AA, and no rule in this
   file applies `opacity` to text — dimming is done by choosing a token.

   GREENBAR IN DARK. paper→bar is only 1.17:1 near black, which is what made
   the stripe vanish in review. So dark gets a second step the light theme
   does not need: striped rows lift their gutter column to --bar-gut, giving
   paper→bar-gut 1.31:1. The fanfold reads as a ladder down the hard rule.
   In light, --bar-gut === --bar: one tone is enough on bright stock.
   ------------------------------------------------------------------------ */

:root {
  color-scheme: light;
  --paper:      #E8EAE3;
  --bar:        #DCE0D4;
  --bar-gut:    #DCE0D4;
  --surface:    #F1F3EC;
  --ink:        #171C1B;
  --dust:       #546059;
  --rule:       #C2CAB9;
  --rule-hard:  #9AA893;
  --vermilion:  #A8331A;
  --verdigris:  #16645A;
  --wash:       rgba(22, 100, 90, .11);   /* verdigris wash — never under text
                                             on --bar; only paper/surface */
  --shade:      rgba(23, 28, 27, .05);
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --paper:     #0F1413;
    --bar:       #1C2422;
    --bar-gut:   #232D2A;
    --surface:   #151B1A;
    --ink:       #DEE4DB;
    --dust:      #93A39B;
    --rule:      #2A3532;
    --rule-hard: #46534E;
    --vermilion: #F0805C;
    --verdigris: #5AD0B7;
    --wash:      rgba(90, 208, 183, .14);
    --shade:     rgba(0, 0, 0, .32);
  }
}

/* Explicit override wins over the media query in both directions — Telegram's
   colorScheme is authoritative when it disagrees with the OS. */
:root[data-theme="light"] {
  color-scheme: light;
  --paper: #E8EAE3; --bar: #DCE0D4; --bar-gut: #DCE0D4; --surface: #F1F3EC;
  --ink: #171C1B; --dust: #546059; --rule: #C2CAB9; --rule-hard: #9AA893;
  --vermilion: #A8331A; --verdigris: #16645A;
  --wash: rgba(22, 100, 90, .11); --shade: rgba(23, 28, 27, .05);
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #0F1413; --bar: #1C2422; --bar-gut: #232D2A; --surface: #151B1A;
  --ink: #DEE4DB; --dust: #93A39B; --rule: #2A3532; --rule-hard: #46534E;
  --vermilion: #F0805C; --verdigris: #5AD0B7;
  --wash: rgba(90, 208, 183, .14); --shade: rgba(0, 0, 0, .32);
}


/* ── 2. TYPE + SPACE SCALE ────────────────────────────────────────────────
   Eight sizes, six spaces. Any value not on these scales is a bug: the
   previous draft drifted to fifteen sizes and eight mono label sizes all
   doing the same job.

   fs-apparatus is the floor at 11px and it is a floor, not a default —
   density comes from editing the metadata down, never from shrinking it.
   fs-record is 16px because that is the WKWebView zoom threshold: the query
   input may not go below it.
   ------------------------------------------------------------------------ */

:root {
  --fs-apparatus: 11px;   /* dates, counts, sources, field labels — FLOOR */
  --fs-token:     12px;   /* filter tokens, tags, syntax table */
  --fs-register:  13px;   /* record id, queue chips, action bar */
  --fs-body:      14px;   /* row summaries, key points */
  --fs-record:    16px;   /* record titles, the query input — iOS floor */
  --fs-legend:    20px;   /* section legend that carries weight */
  --fs-title:     26px;   /* detail title — the detail screen's one big thing */
  --fs-hero:      44px;   /* the hero figure — one per screen, no more */

  --lh-hero:  .84;
  --lh-tight: 1.22;
  --lh-mono:  1.45;
  --lh-body:  1.5;
  --lh-fa:    1.9;

  --tr-label: .16em;      /* uppercase mono labels */
  --tr-mark:  .3em;       /* the wordmark only */
  --tr-mono:  .02em;
  --tr-title: -.015em;
  --tr-fa:    0;          /* tracking breaks joined Arabic letterforms */

  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 40px;

  --tap: 44px;                              /* minimum touch target */
  --gutter: clamp(38px, 11.5vw, 46px);      /* id column; shrinks at 360px */
  --edge: clamp(10px, 3.6vw, 16px);         /* page inline padding */

  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, "Cascadia Mono",
          "Roboto Mono", "DejaVu Sans Mono", monospace;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --fa:   "SF Arabic", "Geeza Pro", "Vazirmatn", "IRANSansX",
          "Noto Naskh Arabic", Tahoma, var(--sans);

  --sat: max(env(safe-area-inset-top, 0px), var(--tg-safe-area-inset-top, 0px));
  --sab: max(env(safe-area-inset-bottom, 0px), var(--tg-safe-area-inset-bottom, 0px));
  --cat: var(--tg-content-safe-area-inset-top, 0px);

  --backdrop: var(--tg-theme-secondary-bg-color, var(--paper));
  --focus: var(--verdigris);
}


/* ── 3. BASE ───────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--backdrop);
}

body {
  margin: 0;
  overflow-x: hidden;                 /* nothing may scroll the page sideways */
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior-y: none;
}

h1, h2, h3, p, dl, dd, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }

button, input { font: inherit; color: inherit; }

button {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: start;
}

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* Every numeric column in this app aligns. */
.num { font-variant-numeric: tabular-nums; }

.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

[hidden] { display: none !important; }


/* ── 4. SHELL ──────────────────────────────────────────────────────────── */

.app { min-height: 100dvh; }

.view { display: none; }
body[data-view="index"]  #view-index  { display: block; }
/* column layout so the action bar's sticky bottom has a full-height box to
   pin against even when the record is short */
body[data-view="detail"] #view-detail { display: flex; flex-direction: column; min-height: 100dvh; }
body[data-view="detail"] #detail { flex: 1; }


/* ── 5. CHROME — masthead, hero, query, chips ──────────────────────────── */

.chrome {
  background: var(--surface);
  padding-block-start: calc(var(--sat) + var(--cat) + var(--sp-3));
}

.qbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--surface);
  border-block-end: 1px solid var(--rule-hard);
  padding-block-start: var(--sp-1);
}

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-inline: var(--edge);
}

/* The mark is tractor-feed sprocket holes — the physical edge of the fanfold
   stock the whole layout references — knocked out of a solid ink strip with
   fill-rule="evenodd", so the holes are holes in any theme. */
.mark {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink);
}
.mark svg { display: block; flex: none; }
.mark__word {
  font-family: var(--mono);
  font-size: var(--fs-register);
  font-weight: 600;
  letter-spacing: var(--tr-mark);
  /* tracked-out words gain a trailing gap; pull it back so the mark's optical
     right edge is the X, not the space after it */
  margin-inline-end: calc(var(--tr-mark) * -1);
}

.clock {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--dust);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The one confident element on the list screen: what the archive wants from
   you right now, as a single figure. */
.hero {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--edge) var(--sp-4);
}
/* the figure hard-aligns with the record titles below it, not with the mark */
.hero__fig { margin-inline-start: -.04em; }
.hero__fig {
  font-family: var(--mono);
  font-size: var(--fs-hero);
  line-height: var(--lh-hero);
  font-weight: 600;
  letter-spacing: -.035em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.hero[data-hot="1"] .hero__fig { color: var(--vermilion); }
.hero__l { min-width: 0; }
.hero__k {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink);
}
.hero[data-hot="1"] .hero__k { color: var(--vermilion); }
.hero__sub {
  display: block;
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  letter-spacing: var(--tr-mono);
  color: var(--dust);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

/* query field — a real input, not a pill */
.q {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-inline: var(--edge);
  min-height: var(--tap);
  padding-inline: var(--sp-2);
  background: var(--paper);
  border: 1px solid var(--rule-hard);
  box-shadow: inset 0 1px 0 var(--shade);
}
.q:focus-within { border-color: var(--verdigris); box-shadow: 0 0 0 2px var(--wash); }
.q svg { flex: none; display: block; color: var(--dust); }
.q input {
  flex: 1 1 auto;
  min-width: 0;
  appearance: none;
  border: 0;
  background: transparent;
  outline: 0;
  font-family: var(--mono);
  font-size: var(--fs-record);       /* 16px — below this iOS zooms on focus */
  letter-spacing: var(--tr-mono);
  color: var(--ink);
  /* stretch rather than pad: the field's touch target is the full 44px bar,
     not just the text box inside it */
  align-self: stretch;
  padding-block: 0;
}
.q input::placeholder { color: var(--dust); }
.q__clear {
  flex: none;
  width: var(--tap);
  min-height: var(--tap);
  margin-inline-end: calc(var(--sp-2) * -1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--dust);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
}

/* what the server understood — tokens the user can strike out */
.parsed {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--edge) 0;
}
.tok {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: var(--tap);
  padding-inline: var(--sp-2);
  border: 1px solid var(--verdigris);
  background: var(--wash);
  color: var(--verdigris);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tok--unknown {
  border-color: var(--rule-hard);
  border-style: dashed;
  background: transparent;
  color: var(--dust);
}
.tok__x { font-size: var(--fs-apparatus); letter-spacing: var(--tr-label); }
.tok--note {
  border: 0;
  background: transparent;
  color: var(--dust);
  padding-inline: 0;
  white-space: normal;
}

/* queue chips write DSL into the field — the chip row *is* the query language */
.chips {
  display: flex;
  margin-block-start: var(--sp-3);
  border-block-start: 1px solid var(--rule);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.chips::-webkit-scrollbar { height: 0; }
.chip {
  flex: 1 0 auto;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  padding-inline: var(--sp-3);
  border-block-end: 2px solid transparent;
  color: var(--dust);
  font-family: var(--mono);
  font-size: var(--fs-register);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  white-space: nowrap;
  transition: color .12s linear, border-color .12s linear;
}
.chip:first-child { padding-inline-start: var(--edge); }
.chip:last-child  { padding-inline-end: var(--edge); }
.chip__n { font-size: var(--fs-apparatus); font-variant-numeric: tabular-nums; }
.chip[aria-pressed="true"] { color: var(--verdigris); border-block-end-color: var(--verdigris); }
.chip[aria-disabled="true"] { cursor: default; }
.chip--due[aria-pressed="true"] { color: var(--vermilion); border-block-end-color: var(--vermilion); }


/* ── 6. SECTION LEGEND + COLUMN HEADER ─────────────────────────────────── */

.legend {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-5) var(--edge) var(--sp-2);
}
.legend h2 {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--ink);
}
.legend .fill { flex: 1; height: 1px; background: var(--rule); }
.legend .cnt {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  letter-spacing: var(--tr-mono);
  color: var(--dust);
  font-variant-numeric: tabular-nums;
}
.legend--due h2, .legend--due .cnt { color: var(--vermilion); }

/* The column header doubles as the sort control — the right-hand label names
   the column the list is ordered by, and tapping it cycles the order. It pins
   under the query bar so the right column never goes unlabelled mid-scroll
   (--qbar-h is measured by app.js). */
.colhead {
  position: sticky;
  top: calc(var(--qbar-h, 0px) - 1px);
  z-index: 10;
  display: grid;
  grid-template-columns: var(--gutter) minmax(0, 1fr);
  border-block: 1px solid var(--rule);
  background: var(--surface);
}
.colhead__g {
  border-inline-end: 1px solid var(--rule);
  padding-inline-start: var(--edge);
  display: flex;
  align-items: center;
}
.colhead__c {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding-inline: var(--sp-3) 0;
}
.colhead__c > span { padding-block: var(--sp-2); }
.colhead__c > span:last-child { padding-inline-end: var(--edge); }
.colhead span, .colhead button {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--dust);
}
.sortbtn {
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding-inline: var(--sp-2) var(--edge);
  color: var(--ink);
}
.sortbtn i { font-style: normal; color: var(--verdigris); }


/* ── 7. THE LEDGER LINE ────────────────────────────────────────────────── */

/* A run is one legend + one column header + its rows. It exists so the sticky
   column header above is scoped to its own rows and hands off to the next
   run's header instead of pinning over the whole feed. */
.run { display: block; }

.list { border-block-end: 1px solid var(--rule); }

.rec {
  position: relative;
  background: var(--paper);
  border-block-end: 1px solid var(--rule);
}
.rec[data-stripe="1"] { background: var(--bar); }
.rec[data-stripe="1"] .rec__gut { background: var(--bar-gut); }
.rec:last-child { border-block-end: 0; }
.rec[data-due="1"]::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 2px;
  background: var(--vermilion);
}
/* Optimistic write in flight. Marked with a rule, not with opacity — dimming
   text is exactly what the contract forbids, and a half-faded row reads as
   broken rather than busy. */
.rec[data-pending="1"]::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  height: 2px;
  background: var(--verdigris);
}

.rec__open {
  display: grid;
  grid-template-columns: var(--gutter) minmax(0, 1fr);
  min-height: var(--tap);
}
.rec__open:focus-visible { outline-offset: -2px; z-index: 2; }

.rec__gut {
  border-inline-end: 1px solid var(--rule);
  padding: var(--sp-3) var(--sp-2) var(--sp-3) var(--edge);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
}
.rec__idx {
  font-family: var(--mono);
  font-size: var(--fs-register);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--tr-mono);
  font-variant-numeric: tabular-nums;
  color: var(--dust);
}
.rec[data-due="1"] .rec__idx { color: var(--vermilion); }
.rec__fa {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: 1.3;
  letter-spacing: var(--tr-mono);
  color: var(--ink);
  border: 1px solid var(--rule-hard);
  padding-inline: 3px;
}

/* Importance renders exactly once per record, here in the gutter, and is
   announced exactly once. It is not repeated in the metadata strip. */
.meter { display: flex; gap: 2px; align-items: flex-end; height: 10px; }
.meter i { display: block; width: 3px; height: 100%; background: var(--rule-hard); }
.meter i.on { background: var(--dust); }
.meter[data-v="4"] i.on { background: var(--ink); }
.meter[data-v="5"] i.on { background: var(--vermilion); }

.rec__body {
  min-width: 0;
  padding: var(--sp-3) var(--edge) var(--sp-3) var(--sp-3);
}

/* Alignment is scoped to the text node, never the cell: a Persian record's
   English gloss stays left-aligned LTR prose inside an otherwise RTL row. */
.rec__t {
  font-size: var(--fs-record);
  line-height: var(--lh-tight);
  letter-spacing: var(--tr-title);
  font-weight: 560;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.rec__s {
  margin-block-start: var(--sp-1);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--dust);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}
.rec__s--none {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}

/* Any Persian text node, wherever it turns up. This was an enumerated list of
   five classes, which meant a Persian *tag* name kept the mono face and its
   tracking — and tracking pulls Arabic-script letterforms apart at the joins.
   The script is a property of the text, not of the component, so the selector
   has to be too. Tags and query tokens are on this path. */
[lang="fa"] {
  font-family: var(--fa);
  letter-spacing: var(--tr-fa);
}
[lang="fa"].rec__t, [lang="fa"].rec__s,
[lang="fa"].prose, [lang="fa"].dtitle, [lang="fa"].kp__s {
  line-height: var(--lh-fa);
  text-align: right;
}
/* Body Persian gets the full ~1.9 leading; a title is set two or three lines
   at most, where 1.9 reads as a gap rather than as rhythm — 1.7 keeps the
   extra room the dots and descenders need without opening the block up. */
[lang="fa"].rec__t { font-weight: 600; line-height: 1.7; }
[lang="fa"].dtitle { line-height: 1.7; }

/* The apparatus never mirrors: it is dir="ltr" structurally, so the tabular
   right-hand column lines up across languages. */
.rec__m {
  margin-block-start: var(--sp-2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-2);
  align-items: center;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  letter-spacing: var(--tr-mono);
  color: var(--dust);
  font-variant-numeric: tabular-nums;
}
.m-l { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); min-width: 0; }
.m-r { flex: none; margin-inline-start: auto; }
.dot { color: var(--rule-hard); }
.kind {
  color: var(--ink);
  border: 1px solid var(--rule-hard);
  padding-inline: 3px;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}
.qstate { color: var(--verdigris); letter-spacing: var(--tr-label); text-transform: uppercase; }
.qstate--none { color: var(--dust); }
.stamp {
  color: var(--vermilion);
  border: 1px solid var(--vermilion);
  padding-inline: 3px;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}
.prov {
  border: 1px solid currentColor;
  padding-inline: 3px;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--dust);
}
.prov--lexical, .prov--tag { color: var(--verdigris); }

/* Highlight is an underline, not a background box: the text keeps full ink
   contrast (12.85:1 worst case) and no coloured box interrupts a cursive
   Persian line. Persian only ever receives whole-word ranges. */
mark {
  background: transparent;
  color: inherit;
  font-weight: 640;
  box-shadow: inset 0 -.14em 0 var(--verdigris);
}
/* Fallback when a Persian range would split a word: mark the whole record. */
.rec[data-hl="row"] .rec__gut { box-shadow: inset 3px 0 0 var(--verdigris); }

/* row actions — 44px, reachable without opening the record */
.rec__act {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--rule);
  border-block-start: 1px solid var(--rule);
  margin-inline-start: var(--gutter);
}
.rec__act button {
  min-height: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}
.rec__act button:disabled { color: var(--dust); cursor: default; }


/* ── 8. STATES ─────────────────────────────────────────────────────────── */

/* An empty state is prose, not apparatus — it reads one step up from the
   11px floor because someone is being told what to do next. */
.blank {
  padding: var(--sp-5) var(--edge) var(--sp-4);
  font-family: var(--mono);
  font-size: var(--fs-token);
  line-height: 1.75;
  letter-spacing: var(--tr-mono);
  color: var(--dust);
}
.blank b {
  display: block;
  font-size: var(--fs-register);
  font-weight: 600;
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--ink);
  margin-block-end: var(--sp-2);
}
.blank__try {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin-block-start: var(--sp-3);
}

.skel { border-block-end: 1px solid var(--rule); }
.skel > i {
  display: block;
  height: 68px;
  border-block-end: 1px solid var(--rule);
  background: linear-gradient(90deg, var(--paper), var(--bar), var(--paper));
  background-size: 220% 100%;
  animation: sweep 1.1s linear infinite;
}
.skel > i:nth-child(2) { animation-delay: .12s; }
.skel > i:nth-child(3) { animation-delay: .24s; }
@keyframes sweep { to { background-position: -220% 0; } }

/* Errors say what happened and what to do about it. */
.alert {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  max-width: 620px;
  margin-inline: auto;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--edge) calc(var(--sp-3) + var(--sab));
  background: var(--surface);
  border-block-start: 2px solid var(--vermilion);
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  color: var(--ink);
}
.alert b {
  display: block;
  color: var(--vermilion);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  font-weight: 600;
}
.alert button {
  flex: none;
  min-height: var(--tap);
  padding-inline: var(--sp-3);
  border: 1px solid var(--rule-hard);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
}


/* ── 9. TAG INDEX + SYNTAX ─────────────────────────────────────────────── */

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--edge) 0;
}
.tag {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: var(--sp-3);
  border: 1px solid var(--rule-hard);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-mono);
  transition: border-color .12s linear, color .12s linear;
}
.tag::before { content: "#"; color: var(--dust); }
/* The label is its own node so a Persian tag can carry lang/dir without the
   "#" and the count inheriting RTL and swapping ends. Deliberately declares no
   font or tracking: both must fall through to [lang="fa"] above, and an
   `inherit` here has equal specificity but later source order, so it would
   silently pull the mono face back over Persian text. */
.tag__l[lang="fa"] { font-size: calc(var(--fs-token) + 1px); }
.tag__n { color: var(--dust); font-variant-numeric: tabular-nums; margin-inline-start: var(--sp-2); }
/* A tag carrying both languages is the bridge between them — say so. */
.tag[data-bridge="1"] { border-color: var(--verdigris); color: var(--verdigris); }
.tag[data-bridge="1"]::before, .tag[data-bridge="1"] .tag__n { color: var(--verdigris); }
.tag[aria-pressed="true"] { background: var(--wash); border-color: var(--verdigris); color: var(--verdigris); }

.syn { border-block-start: 1px solid var(--rule); }
.syn__row {
  display: grid;
  /* fixed first column so every token starts on the same rule, like a legend */
  grid-template-columns: 126px minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-2) var(--edge);
  border-block-end: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--fs-token);
  line-height: var(--lh-mono);
  color: var(--dust);
}
.syn__row code { color: var(--verdigris); font: inherit; }
.syn__row span { overflow-wrap: anywhere; }
.syn__note {
  padding: var(--sp-3) var(--edge);
  border-block-end: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  letter-spacing: var(--tr-mono);
  color: var(--dust);
}

.colophon {
  padding: var(--sp-4) var(--edge) calc(var(--sp-6) + var(--sab));
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--dust);
}

.more {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--tap);
  border-block-end: 1px solid var(--rule);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}


/* ── 10. DETAIL ────────────────────────────────────────────────────────── */

.dbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: calc(var(--sat) + var(--cat) + var(--tap));
  padding: calc(var(--sat) + var(--cat)) var(--edge) 0;
  background: var(--surface);
  border-block-end: 1px solid var(--rule-hard);
}
/* Telegram already draws a back affordance; two would be one too many */
body[data-tgback="1"] .back { display: none; }
body[data-tgback="1"] .dbar { justify-content: flex-start; }
.back {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  margin-inline-start: calc(var(--sp-3) * -1);
  padding-inline: var(--sp-3);
  color: var(--dust);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}
.back svg { display: block; }

.dhead { padding: var(--sp-4) var(--edge) var(--sp-4); border-block-end: 1px solid var(--rule); }
.dhead .rec__m { margin-block-start: 0; margin-block-end: var(--sp-3); }
.dtitle {
  font-size: var(--fs-title);
  line-height: var(--lh-tight);
  letter-spacing: -.022em;
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.dtitle-alt {
  margin-block-start: var(--sp-2);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--dust);
  overflow-wrap: anywhere;
}

.fields {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-1) var(--sp-3);
  margin-block-start: var(--sp-4);
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  line-height: var(--lh-mono);
  font-variant-numeric: tabular-nums;
}
.fields dt { color: var(--dust); letter-spacing: var(--tr-label); text-transform: uppercase; }
.fields dd { color: var(--ink); letter-spacing: var(--tr-mono); overflow-wrap: anywhere; }
.fields dd.hot { color: var(--vermilion); }

.qsel {
  display: flex;
  border-block-end: 1px solid var(--rule);
  background: var(--surface);
  overflow-x: auto;
  scrollbar-width: none;
}
.qsel::-webkit-scrollbar { height: 0; }
.qsel button {
  flex: 1 0 auto;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--sp-3);
  border-inline-end: 1px solid var(--rule);
  color: var(--dust);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  white-space: nowrap;
}
.qsel button:first-child { padding-inline-start: var(--edge); }
.qsel button:last-child { border-inline-end: 0; padding-inline-end: var(--edge); }
.qsel button[aria-pressed="true"] { color: var(--verdigris); background: var(--wash); }

.block { padding-inline: var(--edge); padding-block-end: var(--sp-5); }
.block .legend { padding-inline: 0; }
.prose {
  font-size: var(--fs-record);
  line-height: var(--lh-body);
  color: var(--ink);
  overflow-wrap: anywhere;
}
.prose + .prose { margin-block-start: var(--sp-3); }

/* the second-language summary is labelled, never left to be guessed at */
.altmark {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-block-start: var(--sp-4);
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--dust);
}
.altmark .fill { flex: 1; height: 1px; background: var(--rule); }
.altmark + .prose { margin-block-start: var(--sp-2); }

.kp { border-block-start: 1px solid var(--rule); }
.kp li {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  gap: var(--sp-3);
  padding-block: var(--sp-3);
  border-block-end: 1px solid var(--rule);
}
.kp b {
  font-family: var(--mono);
  font-size: var(--fs-apparatus);
  font-weight: 600;
  line-height: var(--lh-body);
  letter-spacing: var(--tr-mono);
  color: var(--verdigris);
  font-variant-numeric: tabular-nums;
}
.kp__s { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--ink); }
.kp--do b { color: var(--vermilion); }

.excerpt {
  margin-block-start: var(--sp-2);
  padding-inline-start: var(--sp-3);
  border-inline-start: 2px solid var(--rule-hard);
  font-family: var(--mono);
  font-size: var(--fs-token);
  line-height: 1.7;
  color: var(--dust);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 15em;
  overflow: hidden;
}
.excerpt[data-open="1"] { max-height: none; }

.actbar {
  position: sticky;
  bottom: 0;
  z-index: 20;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 1px;
  background: var(--rule-hard);
  border-block-start: 1px solid var(--rule-hard);
}
.actbar button {
  min-height: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-3) var(--sp-2) calc(var(--sp-3) + var(--sab));
  background: var(--surface);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--fs-token);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
}
.actbar button.primary { background: var(--ink); color: var(--paper); }
.actbar button:disabled { color: var(--dust); cursor: default; }


/* ── 11. NARROW ────────────────────────────────────────────────────────── */
/* 360px is the floor: nothing may introduce a horizontal scrollbar there. */
@media (max-width: 372px) {
  :root { --fs-hero: 38px; --fs-title: 23px; }
  .kp li { grid-template-columns: 22px minmax(0, 1fr); gap: var(--sp-2); }
}

/* Wide viewport (desktop Telegram): the ledger stays a column, centred. */
@media (min-width: 620px) {
  .app { max-width: 620px; margin-inline: auto; border-inline: 1px solid var(--rule); min-height: 100dvh; }
}


/* ── 12. MOTION ────────────────────────────────────────────────────────── */

.rec { transition: background-color .12s linear; }
.rec__leaving { transition: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .skel > i { animation: none; background: var(--bar); }
}
