/* ═════════════════════════════════════════════════════════════════════════
   PHNTM in the Qiblah style — stage 1 component kit (2026-10-28)

   Ported from agent_workspace/design/qiblah-style/ui.css. Tokens live in
   tokens.css (the --ph-* block); this file only consumes them. Container
   queries from the mock become @media (min-width: 700px) in the real app.

   Scoping. The component layer sits under `.ph` so a page that opts in
   (home.html today) gets the new look, and the pages that still carry their
   own CSS (every other module in stage 1) do not pick up a .card or .row
   from here by accident. The .ph wrapper is explicit, not inferred.

   Nav. The desktop rail, the phone tab bar and the More sheet have their
   own class names (.phnav-*) and are NOT scoped under .ph, because the nav
   has to sit around every page whether or not that page is wrapped.
   ───────────────────────────────────────────────────────────────────────── */

/* ── Page frame (2026-10-28, stage 4e step 0) ────────────────────────────
   The user-agent 8px body margin showed as a lighter band around every
   Qiblah page (Listen was the loudest case, Sabaq had the same in 2f).
   Zero it here so every page gets the fix at once, not per module. */
html, body { margin: 0; }

/* ── frame ─────────────────────────────────────────────────────────────── */
.ph {
  box-sizing: border-box;
  width: 100%;
  background: var(--ph-bg);
  color: var(--ph-text);
  font-family: var(--ph-sans);
  font-size: var(--ph-t15);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  position: relative;
  font-feature-settings: "cv11", "ss01";
}
.ph *, .ph *::before, .ph *::after { box-sizing: border-box; }
.ph svg.i {
  width: 20px; height: 20px; stroke: currentColor; fill: none;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none;
}
.ph svg.i.sm { width: 16px; height: 16px; }
.ph svg.i.lg { width: 24px; height: 24px; }
.ph svg.i.xl { width: 32px; height: 32px; }
.ph a { color: inherit; text-decoration: none; }
.ph .num, .ph .tnum { font-variant-numeric: tabular-nums; }

/* ── layout and top header ────────────────────────────────────────────── */
.ph .top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--ph-s150);
  padding: var(--ph-s75) var(--ph-s200) var(--ph-s150);
}
.ph .top .tt { min-width: 0; }
.ph .top .tsub { font-size: var(--ph-t13); color: var(--ph-text-dim); margin-top: 2px; }
.ph .top .acts { display: flex; gap: var(--ph-s100); flex: none; }
.ph .top.pushed { justify-content: flex-start; }
.ph .top.pushed .h22 {
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ph .ibtn {
  width: 44px; height: 44px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-2); display: grid; place-items: center;
  color: var(--ph-text); flex: none; position: relative; border: 0;
  cursor: pointer; font: inherit;
}
.ph .ibtn.plain { background: transparent; }
.ph .ibtn.acc { background: var(--ph-accent); color: var(--ph-on-accent); }
.ph .ibtn .badge { position: absolute; top: 2px; right: 2px; }

/* ── type scale ───────────────────────────────────────────────────────── */
.ph .t34 {
  font-size: var(--ph-t34); line-height: 40px; font-weight: 700;
  letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ph .h22 { font-size: var(--ph-t22); line-height: 28px; font-weight: 700; letter-spacing: -0.01em; }
.ph .h20, .ph .sec { font-size: var(--ph-t20); line-height: 26px; font-weight: 700; letter-spacing: -0.01em; }
.ph .h17 { font-size: var(--ph-t17); line-height: 22px; font-weight: 600; }
.ph .b15 { font-size: var(--ph-t15); line-height: 1.5; }
.ph .s13, .ph .dim { font-size: var(--ph-t13); line-height: 1.45; color: var(--ph-text-dim); }
.ph .t11 { font-size: var(--ph-t11); line-height: 16px; font-weight: 600; }
.ph .big56 { font-size: var(--ph-t56); line-height: 1; font-weight: 300; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.ph .big40 { font-size: var(--ph-t40); line-height: 1.05; font-weight: 300; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.ph .big28 { font-size: var(--ph-t28); line-height: 1.1; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.ph .muted { color: var(--ph-text-dim); }
.ph .acc-t { color: var(--ph-tint-text); }
.ph .danger { color: var(--ph-danger-text); }
.ph .good-t { color: var(--ph-good); }
.ph .warn-t { color: var(--ph-warn); }
.ph .ar { font-family: var(--ph-arabic); direction: rtl; font-size: 26px; line-height: 1.5; }
.ph .ar.lg { font-size: 30px; line-height: 2.05; }
.ph .ar.sm { font-size: 21px; line-height: 1.6; }
.ph .bookt { font-family: var(--ph-book); font-size: var(--ph-t17); line-height: 1.7; }
.ph .mono { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--ph-t13); }
.ph .clamp2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ph .ell { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ph .sec {
  margin: var(--ph-s300) 0 var(--ph-s150);
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--ph-s150);
}
.ph .sec .lnk { font-size: var(--ph-t15); font-weight: 600; color: var(--ph-tint-text); }
.ph .sec:first-child { margin-top: var(--ph-s100); }
.ph .lede { font-size: var(--ph-t15); color: var(--ph-text-dim); margin-bottom: var(--ph-s200); max-width: 62ch; }

/* ── surfaces: cards, lists, rows, wells, sky ─────────────────────────── */
.ph .card {
  background: var(--ph-surface);
  border-radius: var(--ph-r-card);
  padding: var(--ph-s200);
  box-shadow: var(--ph-shadow);
}
.ph .card + .card,
.ph .card + .list,
.ph .list + .card,
.ph .list + .list { margin-top: var(--ph-s150); }
.ph .card.sel { background: var(--ph-sel); }
.ph .card.tight { padding: var(--ph-s150); }
.ph .card .ch { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--ph-s150); }
.ph .card .cf { display: flex; gap: var(--ph-s100); margin-top: var(--ph-s150); flex-wrap: wrap; }
.ph .well { background: var(--ph-surface-2); border-radius: var(--ph-r-btn); padding: var(--ph-s150); }
.ph .sky {
  border-radius: var(--ph-r-big);
  padding: var(--ph-s200) 18px;
  color: #fff;
  background: linear-gradient(160deg, #0A2147, #18427A 45%, #6E6A78 75%, #C98A52);
}
.ph .sky.night  { background: linear-gradient(160deg, #0B0D2A, #14173F 40%, #24224F 75%, #312B5A); }
.ph .sky.dawn   { background: linear-gradient(160deg, #1B2050, #3B3F7A 40%, #8E6A8C 75%, #D9967A); }
.ph .sky.midday { background: linear-gradient(160deg, #123C78, #1F5B9E 45%, #4A7FB8 75%, #86ABD2); }
.ph .sky.dusk   { background: linear-gradient(160deg, #1E2158, #4B3770 40%, #A0577A 75%, #EE9A5C); }
.ph .sky .k { font-size: var(--ph-t13); opacity: 0.88; }

/* lists: rows inside one surface, hairlines between */
.ph .list {
  background: var(--ph-surface);
  border-radius: var(--ph-r-card);
  overflow: hidden;
  box-shadow: var(--ph-shadow);
}
.ph .row {
  display: flex; align-items: center; gap: var(--ph-s150);
  padding: var(--ph-s150) var(--ph-s200);
  min-height: 56px; position: relative;
}
.ph .list .row + .row { border-top: 1px solid var(--ph-border); }
.ph .row.sel { background: var(--ph-sel); }
.ph .row .rm { flex: 1; min-width: 0; }
.ph .row .r1 { font-size: var(--ph-t15); line-height: 21px; font-weight: 600; }
.ph .row .r1.lg { font-size: var(--ph-t17); line-height: 22px; }
.ph .row .r2 { font-size: var(--ph-t13); line-height: 1.45; color: var(--ph-text-dim); margin-top: 1px; }
.ph .row .r3 { display: flex; gap: var(--ph-s75); flex-wrap: wrap; margin-top: var(--ph-s75); }
.ph .row .rt {
  flex: none; display: flex; align-items: center; gap: var(--ph-s100);
  color: var(--ph-text-dim); font-size: var(--ph-t13); font-variant-numeric: tabular-nums;
}
.ph .row .chev { color: var(--ph-text-dim); }
.ph .row .lead { flex: none; }
.ph .row.done .r1 { color: var(--ph-text-dim); text-decoration: line-through; }
.ph .gh {
  font-size: var(--ph-t13); font-weight: 600; color: var(--ph-text-dim);
  padding: var(--ph-s300) var(--ph-s50) var(--ph-s100);
  display: flex; justify-content: space-between;
}
.ph .gh:first-child { padding-top: var(--ph-s100); }

/* swatches, dots, avatars, icon tiles */
.ph .dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: none; background: var(--ph-accent); }
.ph .sw { width: 10px; height: 10px; border-radius: 3px; display: inline-block; flex: none; }
.ph .bar-l { position: absolute; left: 0; top: 12px; bottom: 12px; width: 3px; border-radius: 0 3px 3px 0; }
.ph .av {
  width: 40px; height: 40px; border-radius: 50%; background: var(--ph-surface-3);
  display: grid; place-items: center; font-size: var(--ph-t15); font-weight: 600;
  flex: none; color: var(--ph-text);
}
.ph .av.sm { width: 32px; height: 32px; font-size: var(--ph-t13); }
.ph .av.lg { width: 56px; height: 56px; font-size: 18px; }
.ph .av.acc { background: var(--ph-tint); color: var(--ph-tint-text); }
.ph .itile {
  width: 40px; height: 40px; border-radius: 12px; background: var(--ph-surface-2);
  display: grid; place-items: center; flex: none; color: var(--ph-text);
}
.ph .itile.acc  { background: var(--ph-tint); color: var(--ph-tint-text); }
.ph .itile.good { background: var(--ph-good-tint); color: var(--ph-good); }
.ph .itile.warn { background: var(--ph-warn-tint); color: var(--ph-warn); }
.ph .itile.bad  { background: var(--ph-bad-tint);  color: var(--ph-danger-text); }

/* ── pills, badges ────────────────────────────────────────────────────── */
.ph .pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--ph-t11); line-height: 16px; font-weight: 600;
  padding: 3px 9px; border-radius: var(--ph-r-pill);
  background: var(--ph-tint); color: var(--ph-tint-text); white-space: nowrap;
}
.ph .pill.q    { background: var(--ph-surface-2); color: var(--ph-text-dim); }
.ph .pill.good { background: var(--ph-good-tint); color: var(--ph-good); }
.ph .pill.warn { background: var(--ph-warn-tint); color: var(--ph-warn); }
.ph .pill.bad  { background: var(--ph-bad-tint);  color: var(--ph-danger-text); }
.ph .pill.solid { background: var(--ph-accent); color: var(--ph-on-accent); }
.ph .pill .sw { width: 8px; height: 8px; }
.ph .badge {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--ph-r-pill);
  background: var(--ph-accent); color: var(--ph-on-accent);
  font-size: var(--ph-t11); font-weight: 700;
  display: inline-grid; place-items: center; line-height: 1;
}
.ph .badge.bad { background: var(--ph-danger-text); color: #1A0006; }
.ph .badge.dotb { min-width: 10px; width: 10px; height: 10px; padding: 0; }

/* ── buttons ──────────────────────────────────────────────────────────── */
.ph .btn {
  height: 44px; padding: 0 18px; border-radius: var(--ph-r-btn);
  background: var(--ph-surface-2); color: var(--ph-text);
  font: 600 var(--ph-t15)/1 var(--ph-sans);
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px; border: 0; white-space: nowrap; cursor: pointer; text-decoration: none;
}
.ph .btn.pri   { background: var(--ph-accent); color: var(--ph-on-accent); }
.ph .btn.ghost { background: transparent; color: var(--ph-tint-text); padding: 0 10px; }
.ph .btn.dng   { color: var(--ph-danger-text); background: var(--ph-surface-2); }
.ph .btn.dngf  { background: var(--ph-danger-text); color: #1A0006; }
.ph .btn.sm    { height: 36px; padding: 0 14px; font-size: var(--ph-t13); border-radius: 12px; }
.ph .btn.xs    { height: 30px; padding: 0 11px; font-size: var(--ph-t13); border-radius: 10px; }
.ph .btn.blk   { display: flex; width: 100%; }
.ph .btn.dis   { opacity: 0.45; pointer-events: none; }
.ph .btns      { display: flex; gap: var(--ph-s100); flex-wrap: wrap; }
.ph .btns.end  { justify-content: flex-end; }
.ph .btns.stack { flex-direction: column; }
.ph .btns.stack .btn { width: 100%; }

/* ── segmented, chips ─────────────────────────────────────────────────── */
.ph .seg {
  display: flex; background: var(--ph-surface-2); border-radius: var(--ph-r-btn);
  padding: 3px; gap: 3px;
}
.ph .seg > span, .ph .seg > button {
  flex: 1; height: 36px; display: grid; place-items: center;
  border-radius: 11px; font-size: var(--ph-t13); font-weight: 600;
  color: var(--ph-text-dim); white-space: nowrap; padding: 0 10px;
  background: transparent; border: 0; cursor: pointer; font-family: var(--ph-sans);
}
.ph .seg > span.on, .ph .seg > button.on {
  background: var(--ph-surface); color: var(--ph-text); box-shadow: var(--ph-shadow);
}
.ph[data-theme="dark"] .seg > span.on,
.ph:not([data-theme]) .seg > span.on,
.ph[data-theme="dark"] .seg > button.on,
.ph:not([data-theme]) .seg > button.on { background: var(--ph-surface-3); }
.ph .seg.fit { display: inline-flex; }
.ph .seg.fit > span, .ph .seg.fit > button { flex: none; }
.ph .chips {
  display: flex; gap: var(--ph-s100); overflow-x: auto; scrollbar-width: none;
  margin: 0 calc(-1 * var(--ph-s200)); padding: 0 var(--ph-s200);
}
.ph .chips::-webkit-scrollbar { display: none; }
.ph .chips.wrap { flex-wrap: wrap; overflow: visible; margin: 0; padding: 0; }
.ph .chip {
  height: 36px; padding: 0 14px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-2); color: var(--ph-text);
  font-size: var(--ph-t13); font-weight: 500;
  display: inline-flex; align-items: center; gap: 7px;
  white-space: nowrap; flex: none; cursor: pointer; border: 0; font-family: var(--ph-sans);
}
.ph .chip.on { background: var(--ph-tint); color: var(--ph-tint-text); font-weight: 600; }
.ph .chip .n { color: var(--ph-text-dim); font-size: var(--ph-t13); font-variant-numeric: tabular-nums; }
.ph .chip.on .n { color: var(--ph-tint-text); opacity: 0.8; }

/* ── stats ────────────────────────────────────────────────────────────── */
.ph .stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--ph-s100); }
.ph .stats.c3 { grid-template-columns: repeat(3, 1fr); }
.ph .stat {
  background: var(--ph-surface); border-radius: var(--ph-r-card);
  padding: var(--ph-s200); box-shadow: var(--ph-shadow);
}
.ph .stat .v {
  font-size: var(--ph-t28); line-height: 1.15; font-weight: 700;
  letter-spacing: -0.02em; font-variant-numeric: tabular-nums;
}
.ph .stat .v.sm { font-size: var(--ph-t22); }
.ph .stat .l { font-size: var(--ph-t13); color: var(--ph-text-dim); margin-top: 2px; }

/* ── forms ────────────────────────────────────────────────────────────── */
.ph .field { display: flex; flex-direction: column; gap: 6px; }
.ph .field + .field { margin-top: var(--ph-s200); }
.ph .lbl { font-size: var(--ph-t13); font-weight: 600; color: var(--ph-text-dim); }
.ph .input,
.ph .select,
.ph .ta {
  height: 48px; border-radius: var(--ph-r-btn);
  background: var(--ph-surface-2); color: var(--ph-text);
  font: 400 var(--ph-t15) var(--ph-sans);
  padding: 0 14px; display: flex; align-items: center; gap: 10px;
  border: 0; width: 100%; min-width: 0;
}
.ph .input .ph-t, .ph .ta .ph-t { color: var(--ph-text-dim); }
.ph .select { justify-content: space-between; }
.ph .ta { height: auto; min-height: 104px; align-items: flex-start; padding: 12px 14px; line-height: 1.5; }
.ph input.input, .ph textarea.ta, .ph select.select { outline: none; }
.ph input.input:focus, .ph textarea.ta:focus, .ph select.select:focus {
  box-shadow: 0 0 0 2px var(--ph-tint-text);
}
.ph textarea.ta { font-family: inherit; }
.ph .search {
  height: 44px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-2); display: flex; align-items: center;
  gap: 10px; padding: 0 16px; color: var(--ph-text-dim); font-size: var(--ph-t15);
}
/* The .ph .search wrapper already draws the pill (background, radius) and the
   magnifier icon. The inner input must sit on top with no chrome of its own.
   Two older rulesets fight us for that control and both need overriding here:
     - shell.css gives every input[type=search] a background, border, and
       radius (the inner pill in the screenshots).
     - hig.css at <= 767px paints a second pill AND a second magnifier via
       background-image, with !important everywhere (the second icon).
   Reset the input to a transparent slot inside the wrapper. The !important
   mirrors hig.css so the mobile cascade is actually overridden. Also strip
   the browser's own search decorations (iOS magnifier, Chromium clear-x). */
.ph .search input,
.ph .search input[type="search"] {
  appearance: none !important;
  -webkit-appearance: none !important;
  background: transparent !important;
  background-image: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  height: 100% !important;
  min-height: 0 !important;
  color: inherit;
  font: inherit;
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  outline: none;
}
.ph .search input::placeholder { color: var(--ph-text-dim); }
.ph .search input::-webkit-search-decoration,
.ph .search input::-webkit-search-cancel-button,
.ph .search input::-webkit-search-results-button,
.ph .search input::-webkit-search-results-decoration {
  display: none;
  -webkit-appearance: none;
}
.ph .help { font-size: var(--ph-t13); color: var(--ph-text-dim); }
.ph .tgl {
  width: 51px; height: 31px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-3); position: relative; flex: none;
  display: inline-block; cursor: pointer; border: 0;
}
.ph .tgl::after {
  content: ""; position: absolute; width: 27px; height: 27px; border-radius: 50%;
  background: #fff; top: 2px; left: 2px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.ph .tgl.on { background: var(--ph-accent); }
.ph .tgl.on::after { left: 22px; }
.ph .chk {
  width: 24px; height: 24px; border-radius: 8px; background: var(--ph-surface-3);
  display: grid; place-items: center; flex: none; color: transparent;
  box-shadow: inset 0 0 0 1.5px var(--ph-text-dim);
}
.ph .chk.on { background: var(--ph-accent); color: var(--ph-on-accent); box-shadow: none; }
.ph .chk.round { border-radius: 50%; }
.ph .radio {
  width: 22px; height: 22px; border-radius: 50%; background: var(--ph-surface-3);
  flex: none; position: relative;
}
.ph .radio.on { background: var(--ph-accent); }
.ph .radio.on::after {
  content: ""; position: absolute; inset: 7px; border-radius: 50%; background: var(--ph-on-accent);
}

/* ── progress ─────────────────────────────────────────────────────────── */
.ph .prog { height: 6px; border-radius: 3px; background: var(--ph-surface-3); overflow: hidden; }
.ph .prog > i { display: block; height: 100%; border-radius: 3px; background: var(--ph-accent); }
.ph .prog.good > i { background: var(--ph-good); }
.ph .prog.warn > i { background: var(--ph-warn); }
.ph .prog.bad > i  { background: var(--ph-danger-text); }
.ph .prog.thin { height: 4px; }

/* ── key value, table ─────────────────────────────────────────────────── */
.ph .kv {
  display: flex; justify-content: space-between; gap: var(--ph-s200);
  padding: var(--ph-s150) 0; font-size: var(--ph-t15);
}
.ph .kv + .kv { border-top: 1px solid var(--ph-border); }
.ph .kv .k { color: var(--ph-text-dim); }
.ph .kv .v { font-weight: 500; text-align: right; font-variant-numeric: tabular-nums; }
.ph .tw { overflow-x: auto; scrollbar-width: none; }
.ph table.tbl { width: 100%; border-collapse: collapse; font-size: var(--ph-t13); font-variant-numeric: tabular-nums; }
.ph table.tbl th {
  font-size: var(--ph-t13); font-weight: 600; color: var(--ph-text-dim);
  text-align: left; padding: var(--ph-s150); white-space: nowrap;
}
.ph table.tbl td { color: var(--ph-text); padding: var(--ph-s150); border-top: 1px solid var(--ph-border); white-space: nowrap; }
.ph table.tbl tr.sel td { background: var(--ph-sel); }
.ph table.tbl td.r, .ph table.tbl th.r { text-align: right; }

/* ── grids and layout helpers ─────────────────────────────────────────── */
.ph .g2, .ph .g3, .ph .g4 { display: grid; gap: var(--ph-s150); }
.ph .g2 { grid-template-columns: 1fr; }
.ph .g3 { grid-template-columns: 1fr; }
.ph .g4 { grid-template-columns: repeat(2, 1fr); }
.ph .gm2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--ph-s100); }
.ph .gm3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--ph-s100); }
.ph .split { display: block; }
.ph .split > .pane2 { display: none; }
.ph .hstack { display: flex; align-items: center; gap: var(--ph-s100); }
.ph .hstack.sb { justify-content: space-between; }
.ph .vstack { display: flex; flex-direction: column; gap: var(--ph-s150); }
.ph .mt8  { margin-top: var(--ph-s100); }
.ph .mt12 { margin-top: var(--ph-s150); }
.ph .mt16 { margin-top: var(--ph-s200); }
.ph .mt24 { margin-top: var(--ph-s300); }
.ph .rail-h {
  display: flex; gap: var(--ph-s150); overflow-x: auto; scrollbar-width: none;
  margin: 0 calc(-1 * var(--ph-s200)); padding: 0 var(--ph-s200);
}
.ph .rail-h::-webkit-scrollbar { display: none; }

/* ── overlays: scrim, sheet, pop, toast, banner, empty ────────────────── */
/* z-index above .phnav-tabs (40) and .phnav-sheet (51) so a sheet covers the
   phone tab bar; otherwise the tabs read through the bottom of the sheet.
   Dispatch adopted the same two numbers in stage 3b for the same reason. */
.ph .scrim { position: fixed; inset: 0; background: var(--ph-scrim); z-index: 60; }
.ph .sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  max-height: 88%; background: var(--ph-surface);
  border-radius: var(--ph-r-big) var(--ph-r-big) 0 0;
  box-shadow: var(--ph-shadow-sheet); z-index: 61;
  padding: 10px var(--ph-s200) var(--ph-s400);
  overflow: auto; scrollbar-width: none;
}
.ph .sheet.full { top: 0; max-height: none; }
.ph .sheet .grab { width: 40px; height: 5px; border-radius: 3px; background: var(--ph-surface-3); margin: 0 auto var(--ph-s150); }
.ph .sheet .sh {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--ph-s150); margin-bottom: var(--ph-s200);
}
.ph .sheet .sh .h20 { flex: 1; min-width: 0; }
.ph .sheet .sf {
  position: sticky; bottom: calc(-1 * var(--ph-s400));
  background: var(--ph-surface); padding: var(--ph-s150) 0 0; margin-top: var(--ph-s200);
}
.ph .pop {
  position: absolute; z-index: 21; background: var(--ph-surface);
  border-radius: 18px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
  padding: var(--ph-s100); min-width: 220px;
}
.ph .pop .pi {
  display: flex; align-items: center; gap: var(--ph-s150);
  height: 44px; padding: 0 var(--ph-s150); border-radius: 12px; font-size: var(--ph-t15);
}
.ph .pop .pi.on { background: var(--ph-sel); }
.ph .pop .pi .dim { margin-left: auto; }
.ph .pop hr { border: 0; border-top: 1px solid var(--ph-border); margin: var(--ph-s50) 0; }
.ph .toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: 100px;
  background: var(--ph-text); color: var(--ph-bg);
  border-radius: var(--ph-r-pill); padding: 10px 18px;
  font-size: var(--ph-t13); font-weight: 600; z-index: 30;
  display: flex; gap: 14px; align-items: center; white-space: nowrap;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.ph .toast b { color: var(--ph-accent); }
.ph .banner {
  display: flex; gap: var(--ph-s150); align-items: flex-start;
  background: var(--ph-tint); color: var(--ph-tint-text);
  border-radius: var(--ph-r-card); padding: var(--ph-s150) var(--ph-s200);
  font-size: var(--ph-t13); line-height: 1.45;
}
.ph .banner.warn { background: var(--ph-warn-tint); color: var(--ph-warn); }
.ph .banner.bad  { background: var(--ph-bad-tint);  color: var(--ph-danger-text); }
.ph .banner.good { background: var(--ph-good-tint); color: var(--ph-good); }
.ph .banner .bt { flex: 1; }
.ph .empty {
  text-align: center; padding: var(--ph-s600) var(--ph-s300);
  display: flex; flex-direction: column; align-items: center; gap: var(--ph-s100);
}
.ph .empty .eic {
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--ph-surface-2); display: grid; place-items: center;
  color: var(--ph-text-dim); margin-bottom: var(--ph-s100);
}
.ph .empty .h17 { max-width: 30ch; }
.ph .empty .dim { max-width: 40ch; }
.ph .empty .btn { margin-top: var(--ph-s150); }
.ph .skel { height: 14px; border-radius: 7px; background: var(--ph-surface-2); }
.ph .spin {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2.5px solid var(--ph-surface-3); border-top-color: var(--ph-accent);
  display: inline-block; flex: none;
  animation: ph-spin 0.8s linear infinite;
}
.ph .spin.sm {
  width: 12px; height: 12px; border-width: 2px;
}
@keyframes ph-spin { to { transform: rotate(360deg); } }
.ph .code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12.5px; line-height: 1.55;
  background: var(--ph-surface-2); border-radius: var(--ph-r-btn);
  padding: var(--ph-s150); white-space: pre-wrap;
  color: var(--ph-text); overflow: auto;
}
.ph .quote { border-radius: var(--ph-r-btn); background: var(--ph-surface-2); padding: var(--ph-s150) var(--ph-s200); font-size: var(--ph-t15); line-height: 1.5; }
.ph .hr { height: 1px; background: var(--ph-border); margin: var(--ph-s200) 0; }
.ph .tick { color: var(--ph-good); }

/* ── fab ─────────────────────────────────────────────────────────────── */
.ph .fab {
  position: fixed; right: var(--ph-s200);
  bottom: calc(84px + var(--ph-s200));
  width: 56px; height: 56px; border-radius: var(--ph-r-pill);
  background: var(--ph-accent); color: var(--ph-on-accent);
  display: grid; place-items: center; z-index: 6;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  border: 0; cursor: pointer;
}

/* ── 700px breakpoint: rail-and-multi-column kicks in ─────────────────── */
@media (min-width: 700px) {
  .ph .g2 { grid-template-columns: repeat(2, 1fr); }
  .ph .g3 { grid-template-columns: repeat(3, 1fr); }
  .ph .g4 { grid-template-columns: repeat(4, 1fr); }
  .ph .stats { grid-template-columns: repeat(4, 1fr); }
  .ph .stats.c3 { grid-template-columns: repeat(3, 1fr); }
  .ph .split { display: grid; grid-template-columns: minmax(320px, 400px) 1fr; gap: var(--ph-s300); align-items: start; }
  .ph .split.even { grid-template-columns: 1fr 1fr; }
  .ph .split.wide { grid-template-columns: 1fr 340px; }
  .ph .split > .pane2 { display: block; }
  .ph .narrow { max-width: 760px; }
  .ph .top { padding: var(--ph-s300) var(--ph-s400) var(--ph-s200); }
  .ph .rail-h { margin: 0; padding: 0; }
  .ph .sheet {
    left: 50%; right: auto; bottom: auto; top: 50%; transform: translate(-50%, -50%);
    width: 560px; max-height: 84%; border-radius: var(--ph-r-big); padding: var(--ph-s300);
  }
  .ph .sheet.wide { width: 760px; }
  .ph .sheet.full { top: 50%; max-height: 84%; }
  .ph .sheet .grab { display: none; }
  .ph .sheet .sf { bottom: calc(-1 * var(--ph-s300)); }
  .ph .toast { bottom: var(--ph-s300); }
  .ph .fab { display: none; }
  .ph .m-only { display: none !important; }
}
@media (max-width: 699px) {
  .ph .d-only { display: none !important; }
}

/* kit niceties */
.ph .g2 > *, .ph .g3 > *, .ph .g4 > *, .ph .split > *, .ph .gm2 > *, .ph .gm3 > * { min-width: 0; }
.ph .g2 > .card, .ph .g3 > .card, .ph .g4 > .card,
.ph .split > .card,
.ph .g2 > .list, .ph .g3 > .list, .ph .g4 > .list { margin-top: 0; }
.ph .sheet .stat, .ph .sheet .card { background: var(--ph-surface-2); }

/* ═════════════════════════════════════════════════════════════════════════
   NAVIGATION — rail (desktop), tabs (phone), More sheet
   Not scoped under .ph, because the nav lives outside the page wrapper.
   The desktop rail is 232px; the phone tab bar is 84px.
   ───────────────────────────────────────────────────────────────────────── */

.phnav-rail {
  position: fixed; left: 0; top: 0; bottom: 0;
  width: 232px; z-index: 40;
  background: var(--ph-rail-bg);
  display: flex; flex-direction: column;
  padding: var(--ph-s200) var(--ph-s150);
  gap: 2px; overflow-y: auto; overflow-x: hidden; scrollbar-width: none;
  font-family: var(--ph-sans); color: var(--ph-text);
  min-height: 100vh;
}
.phnav-rail::-webkit-scrollbar { display: none; }
html[data-theme="light"] .phnav-rail { border-right: 1px solid var(--ph-border); }
.phnav-rail .brand {
  display: flex; align-items: center; gap: 10px;
  flex: none;
  font-size: var(--ph-t17); font-weight: 700;
  padding: var(--ph-s100) var(--ph-s100) var(--ph-s200);
  color: var(--ph-text); text-decoration: none;
}
.phnav-rail .brand .wm { font-size: var(--ph-t15); font-weight: 600; letter-spacing: 0.32em; }
.phnav-rail .grp {
  font-size: var(--ph-t13); color: var(--ph-text-dim);
  flex: none;
  padding: var(--ph-s200) var(--ph-s150) var(--ph-s50);
}
.phnav-rail .ri {
  display: flex; align-items: center; gap: var(--ph-s150);
  flex: none; height: 36px; min-height: 36px;
  padding: 0 var(--ph-s150); border-radius: 12px;
  font-size: var(--ph-t15); font-weight: 500; color: var(--ph-text);
  text-decoration: none; position: relative;
}
.phnav-rail .ri svg { color: var(--ph-text-dim); flex: none; }
.phnav-rail .ri.on { background: var(--ph-tint); color: var(--ph-tint-text); font-weight: 600; }
.phnav-rail .ri.on svg { color: var(--ph-tint-text); }
.phnav-rail .ri .badge { margin-left: auto; }

/* Phone tab bar — bottom-anchored, 84 tall. */
.phnav-tabs {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  height: 84px; background: var(--ph-tab-bg);
  display: flex; justify-content: space-around;
  padding-top: 8px; box-shadow: var(--ph-shadow);
  font-family: var(--ph-sans);
}
html[data-theme="light"] .phnav-tabs { border-top: 1px solid var(--ph-border); }
.phnav-tabs .tab {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  font-size: var(--ph-t11); font-weight: 600; color: var(--ph-text-dim);
  width: 66px; text-decoration: none; background: transparent; border: 0;
  cursor: pointer; font-family: inherit;
}
.phnav-tabs .tab .ic {
  width: 52px; height: 30px; border-radius: var(--ph-r-pill);
  display: grid; place-items: center; position: relative;
}
.phnav-tabs .tab.on { color: var(--ph-tint-text); }
.phnav-tabs .tab.on .ic { background: var(--ph-tint); }
.phnav-tabs .tab .badge { position: absolute; top: -4px; right: 6px; }
.phnav-tabs .tab .badge.dotb {
  min-width: 10px; width: 10px; height: 10px; padding: 0;
  top: 0; right: 12px;
}

/* The More sheet. Full-height bottom sheet on phone, centred dialog on
   desktop (where it never actually opens because the rail is the nav).
   Every child carries a phnav- prefix so no page stylesheet can reach in:
   .tile, .grid, .mt, .badge and .theme-row are all generic class names and
   were being redressed by shell.css, theme.css, hig.css and per-page CSS,
   which was the cause of the ragged tiles reported on 2026-11-11. */
.phnav-more-wrap { display: none; }
.phnav-more-wrap.is-open { display: block; }
.phnav-more-wrap .phnav-scrim {
  position: fixed; inset: 0; background: var(--ph-scrim); z-index: 50;
}
.phnav-sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  top: 0; max-height: none;
  background: var(--ph-surface);
  border-radius: var(--ph-r-big) var(--ph-r-big) 0 0;
  box-shadow: var(--ph-shadow-sheet); z-index: 51;
  padding: 10px var(--ph-s200) 120px;
  overflow: auto; scrollbar-width: none;
  font-family: var(--ph-sans); color: var(--ph-text);
}
.phnav-sheet::-webkit-scrollbar { display: none; }
.phnav-sheet .phnav-grab { width: 40px; height: 5px; border-radius: 3px; background: var(--ph-surface-3); margin: 0 auto var(--ph-s150); }
.phnav-sheet .phnav-sh {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--ph-s150); margin-bottom: var(--ph-s200);
}
.phnav-sheet .phnav-sh-title { flex: 1; min-width: 0; font-size: var(--ph-t20); line-height: 26px; font-weight: 700; letter-spacing: -0.01em; }
.phnav-sheet .phnav-close {
  width: 44px; height: 44px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-2); display: grid; place-items: center;
  color: var(--ph-text); border: 0; cursor: pointer;
}
.phnav-sheet .phnav-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--ph-s100); position: relative;
}
.phnav-sheet .phnav-mt { position: relative; display: block; }
.phnav-sheet .phnav-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--ph-s75);
  width: 100%; box-sizing: border-box;
  height: calc(var(--ph-s400) + var(--ph-s600));
  padding: var(--ph-s100) var(--ph-s50);
  border-radius: var(--ph-r-btn); background: var(--ph-surface-2);
  color: var(--ph-text); text-decoration: none;
  font-size: var(--ph-t13); text-align: center; line-height: 1.2;
  position: relative; border: 0; cursor: pointer; font-family: inherit;
}
.phnav-sheet .phnav-tile svg { color: var(--ph-text); }
.phnav-sheet .phnav-tile .phnav-tile-lb {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; word-break: break-word;
}
.phnav-sheet .phnav-tile .phnav-tile-badge {
  position: absolute; top: var(--ph-s75); right: var(--ph-s100);
}
.phnav-sheet .phnav-after-grid { margin-top: var(--ph-s200); }
.phnav-sheet .phnav-theme-row {
  background: var(--ph-surface-2); border-radius: var(--ph-r-card);
  display: flex; align-items: center; gap: var(--ph-s150);
  padding: var(--ph-s150) var(--ph-s200); min-height: 56px;
  color: var(--ph-text); border: 0; width: 100%;
  font-family: inherit; cursor: pointer;
}
.phnav-sheet .phnav-theme-row .phnav-theme-lead { flex: none; display: inline-grid; place-items: center; }
.phnav-sheet .phnav-tgl {
  width: 51px; height: 31px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-3); position: relative; flex: none;
  display: inline-block; border: 0;
}
.phnav-sheet .phnav-tgl::after {
  content: ""; position: absolute; width: 27px; height: 27px; border-radius: 50%;
  background: #fff; top: 2px; left: 2px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.phnav-sheet .phnav-tgl.on { background: var(--ph-accent); }
.phnav-sheet .phnav-tgl.on::after { left: 22px; }
.phnav-sheet .phnav-theme-row .phnav-theme-rm { flex: 1; min-width: 0; text-align: left; display: block; }
.phnav-sheet .phnav-theme-row .phnav-theme-r1 { display: block; font-size: var(--ph-t15); line-height: 21px; font-weight: 600; }
.phnav-sheet .phnav-theme-row .phnav-theme-r2 { display: block; font-size: var(--ph-t13); color: var(--ph-text-dim); margin-top: 1px; }

/* Phone layout: hide rail, show tabs. Body padding is set outside this file
   (via _nav.html) because the padding is a page-level knob. */
@media (max-width: 699px) {
  .phnav-rail { display: none; }
  .phnav-tabs { display: flex; }
  .phnav-more-wrap { position: fixed; inset: 0; z-index: 50; }
}
@media (min-width: 700px) {
  .phnav-tabs { display: none; }
  .phnav-more-wrap { display: none !important; }
}

/* Legacy pages (not inside .ph) still have their own tops; the rail sits
   left of them, which is correct. */
.phnav-page {
  padding-left: 232px;
}
@media (max-width: 699px) {
  .phnav-page {
    padding-left: 0;
    padding-bottom: 84px;
  }
}

/* ── Qiblah page header (used by _pagehead.html when ph_mode is set) ──── */
/* flex-wrap: nowrap overrides primitives.css `header { flex-wrap: wrap }`, which
   otherwise drops the round buttons onto a second row at phone width when the
   subtitle is long. The title ellipsizes instead; Digest found this in 3f and
   patched per-page, lifted here so no page needs its own override. */
.phhead {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: nowrap;
  gap: var(--ph-s150);
  /* bottom padding is the kit's 16px gap to the first block of page content
     (stage 5m: lifted from 12px because the Imports lede was sitting on the
     header's divider line, and every page should get the same breathing room). */
  padding: var(--ph-s200) var(--ph-s200) var(--ph-s200);
  font-family: var(--ph-sans); color: var(--ph-text); background: var(--ph-bg);
}
.phhead .tt { min-width: 0; }
.phhead .t34 {
  font-size: var(--ph-t34); line-height: 40px; font-weight: 700;
  letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--ph-text);
}
.phhead .tsub {
  font-size: var(--ph-t13); color: var(--ph-text-dim); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Round header buttons are 44px pills on var(--ph-surface-2); the Qiblah kit
   pairs them with an 8px gap (see design/qiblah-style/ui.css: `.ph .top .acts
   { gap: var(--s100) }`) so the two sit as one pair without their hover rings
   overlapping. Stage 5o moves them into a kit-owned container, .phhead-acts,
   with a scoped reset that forbids anything inside it from overriding the
   button width, height or margin. Four earlier pages (Dispatch, Digest,
   Ledger, Cortex) had reached this layer with a page-local class that
   nudged the pair into touching; the scoped reset shuts that path for good.
   The old .acts selector is kept as a quiet fallback for any page that
   still ships the old DOM. */
header.phhead > .phhead-acts,
header.phhead > .acts {
  display: flex; gap: var(--ph-s100); flex: none; align-items: center;
}
header.phhead > .phhead-acts > *,
header.phhead > .phhead-acts > * > .ibtn { margin: 0; flex: none; }
header.phhead > .phhead-acts > .ibtn,
header.phhead > .phhead-acts > a.ibtn,
header.phhead > .phhead-acts > button.ibtn,
header.phhead > .phhead-acts > .theme-toggle {
  width: var(--ph-target); height: var(--ph-target);
}
.phhead.pushed { justify-content: flex-start; }
.phhead.pushed .h22 {
  font-size: var(--ph-t22); line-height: 28px; font-weight: 700; letter-spacing: -0.01em;
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--ph-text);
}
.phhead .ibtn {
  width: 44px; height: 44px; border-radius: var(--ph-r-pill);
  background: var(--ph-surface-2); display: grid; place-items: center;
  color: var(--ph-text); flex: none; position: relative; border: 0;
  cursor: pointer; text-decoration: none;
}
.phhead .ibtn.plain { background: transparent; }
.phhead .ibtn.acc { background: var(--ph-accent); color: var(--ph-on-accent); }
/* The dark/light toggle (added by /static/js/theme-toggle.js on every page
   that loads the script) lands in `.phhead` as a plain button. The default
   skin from theme.css is a 32px square with a 2px-rounded border, which
   does not match the Qiblah header's 44px round pills. Re-skin it here so
   every page carrying the new header gets a toggle that reads as part of
   the same row of controls (Learn surfaced this; the rule is global so no
   per-page sheet needs to repeat it). */
.phhead .theme-toggle {
  width: var(--ph-target); height: var(--ph-target);
  border-radius: var(--ph-r-pill);
  background: var(--ph-surface-2);
  color: var(--ph-text);
  border: 0; margin: 0; padding: 0;
  display: grid; place-items: center;
  flex: none;
}
.phhead .theme-toggle:hover {
  background: var(--ph-surface-3);
  border-color: transparent;
  color: var(--ph-text);
}
.phhead .theme-toggle svg {
  width: var(--ph-t20); height: var(--ph-t20);
}
@media (min-width: 700px) {
  .phhead { padding: var(--ph-s300) var(--ph-s400) var(--ph-s200); }
}
