/* ============================================================================
   Opus Bench — app chrome.
   media="screen" is set on the <link>: exported and printed DOCUMENTS never
   read these tokens. exports.js writes its own literal CSS into a standalone
   file, so a manuscript is black-on-white on paper no matter what the app
   looks like on screen. Adding a rule here can never change a submission.
   ========================================================================= */

/* ---------- Design tokens ---------------------------------------------- */
:root{
  color-scheme:light;

  /* Brand. Emory navy, shared with the sibling apps; the manuscript app's own
     identity comes from --quill (the editorial accent used for revision marks
     and the active rail), not from a different brand colour. */
  --navy:#012169; --navy-2:#0b2f7e; --blue:#2c5cc5; --blue-lt:#e8eefb;
  /* THE FILE-CATEGORY BLUE, and its own tokens rather than var(--blue),
     because --blue is re-pointed at the accent further down so the whole
     stylesheet follows the palette — reusing it here would have handed back
     the accent colour the bubbles already were. A category is a CLASSIFICATION
     rather than app chrome, so it holds still while the accent moves, exactly
     as tracked insertions do (Alex, 2026-08-16). */
  --cat-ink:#2c5cc5; --cat-wash:#e8eefb; --cat-line:#b9c9ec; --cat-on:#ffffff;
  /* The full text's own bubble: the same STEP away from the row that the blue
     one makes, in neutral. --surface-3 was two units off the row behind it and
     read as no fill at all. */
  --cat-grey-ink:#5c6371; --cat-grey-wash:#ecedf2; --cat-grey-line:#ced3dd;
  --blue-line:#b9c9ec; --nav-fill:#012169;
  --quill:#7b1e3c; --quill-bg:#fbeef2; --quill-line:#e2b9c6;
  /* Sign-in buttons, drawn from the app-icon gradient (slate-blue + rose). */
  --gate-blue:#3f5583; --gate-blue-h:#354a73; --gate-rose:#a86b7b; --gate-rose-h:#96606e;

  /* Surfaces, lightest to most recessed. */
  --bg:#f4f5f8; --panel:#ffffff;
  --surface-2:#fafbfc; --surface-3:#fcfcfd; --surface-hover:#fafbfd; --surface-sel:#f2f6fd;
  --input-bg:#ffffff; --input-line:#868e9e;

  /* Hairlines. */
  --line:#dde1e8; --line-2:#eceef2; --line-strong:#c9cfda; --dash-line:#b9c1cf; --rail:#cfd8ea;

  /* Ink. */
  --ink:#1c2433; --ink-2:#5a6475; --ink-3:#5c6371; --ink-4:#8b93a3; --on-accent:#ffffff;

  /* Semantic triples: ink / tinted ground / border. */
  --green:#1e7a3c; --green-bg:#e7f4ec; --green-line:#bcdcc8;
  --red:#b3261e;   --red-bg:#fbeae9;   --red-line:#e5b6b3;
  --amber:#8a5c00; --amber-bg:#fff3d6; --amber-line:#e6d09a;
  --find-hl:#ffe9a8; --find-cur:#ffc94d; --find-cur-ink:#3a2c00;
  --purple:#5b3fa8;--purple-bg:#efeafa;--purple-line:#c3b2ee;

  /* The manuscript page itself — deliberately a different material from the
     app chrome so the writing surface reads as paper even inside the shell. */
  --paper:#ffffff; --paper-ink:#161a22; --paper-line:#e3e6ec; --paper-shadow:rgba(20,28,48,.08);
  --paper-rule:#eef0f4;

  /* Toolbar, its own strip material (not --panel) so a card scrolling under it
     still reads as a separate surface. Two cues carry "this is a control" — a
     fill step AND a hairline — because at 28px either alone is deniable. */
  --tb-bg:#fbfcfd; --tb-line:#c9cfda; --tb-sep:#d7dce4;
  --tb-btn-bg:#ffffff; --tb-btn-line:#868e9e;
  --tb-btn-hover:#eef1f6; --tb-btn-active:#e3e8f0;
  --tb-menu-bg:#ffffff;
  --menu-ink:#4e6481;          /* the logo's darkest blue, sampled from the mark */

  --toast-bg:#1c2433; --toast-ink:#ffffff; --scroll-thumb:#c8cdd6;
  --hero-bg:#012169; --hero-ink-2:#9fb0d8; --nav-edge:#012169;
  --viewer-bg:#2a2f3a; --frame-bg:#525659;

  --radius:10px; --radius-sm:6px;
  --shadow:0 1px 2px rgba(16,24,40,.06),0 1px 3px rgba(16,24,40,.10);
  --shadow-lg:0 8px 28px rgba(16,24,40,.16),0 2px 8px rgba(16,24,40,.08);

  /* Type scale, named by ROLE — new work picks a role, not a pixel value. */
  --fs-micro:10px; --fs-tag:10.5px; --fs-cap:11px; --fs-meta:11.5px;
  --fs-sm:12px; --fs-ui:12.5px; --fs-base:13px; --fs-md:13.5px;
  --fs-title:14px; --fs-lead:15px;

  /* Spacing ladder. Odd values elsewhere are deliberate optical nudges. */
  --sp-1:2px; --sp-2:4px; --sp-3:6px; --sp-4:8px; --sp-5:10px; --sp-6:12px;
  --sp-7:14px; --sp-8:16px; --sp-9:18px; --sp-10:20px; --sp-12:24px; --sp-16:32px;

  --ui-font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --doc-font:"Times New Roman",Times,Georgia,serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  --sidebar-w:264px;
}

:root[data-theme="dark"]{
  color-scheme:dark;
  --navy:#8aa6e8; --navy-2:#9db6ee; --blue:#7ea3ef; --blue-lt:#1b2540;
  --cat-ink:#8fb3f5; --cat-wash:#18233c; --cat-line:#33436b; --cat-on:#0d1119;
  --cat-grey-ink:#a6b0c0; --cat-grey-wash:#242a36; --cat-grey-line:#3a4250;
  --blue-line:#33436b; --nav-fill:#0d1526;
  --quill:#e79ab2; --quill-bg:#2c1621; --quill-line:#5b2c3d;

  --bg:#0e1420; --panel:#161d2b;
  --surface-2:#1a2130; --surface-3:#1c2433; --surface-hover:#1e2636; --surface-sel:#1e2a44;
  --input-bg:#111827; --input-line:#5b6577;

  --line:#28303f; --line-2:#222a38; --line-strong:#3a4353; --dash-line:#3e4757; --rail:#33415e;

  --ink:#e6e9ef; --ink-2:#a8b1c1; --ink-3:#9aa3b3; --ink-4:#79839a; --on-accent:#0e1420;

  --green:#5fce8b; --green-bg:#12291c; --green-line:#2c5b3d;
  --red:#f08a82;   --red-bg:#2d1614;   --red-line:#5e2c28;
  --amber:#e8b44f; --amber-bg:#2b2110; --amber-line:#5b4a20;
  --find-hl:#4a3a10; --find-cur:#8a6a1a; --find-cur-ink:#fff3d6;
  --purple:#b39cf0;--purple-bg:#221b38;--purple-line:#443a6b;

  --paper:#141b27; --paper-ink:#e3e7ee; --paper-line:#2a3242; --paper-shadow:rgba(0,0,0,.5);
  --paper-rule:#222a38;

  --tb-bg:#131a27; --tb-line:#2f3a4c; --tb-sep:#28303f;
  --tb-btn-bg:#1b2331; --tb-btn-line:#5b6577;
  --tb-btn-hover:#232c3d; --tb-btn-active:#2a3548;
  --tb-menu-bg:#1b2331;
  --menu-ink:#7990ae;          /* the brand blue, lifted only as far as AA needs */

  --toast-bg:#e6e9ef; --toast-ink:#0e1420; --scroll-thumb:#3a4353;
  --hero-bg:#131c30; --hero-ink-2:#8fa3cf; --nav-edge:#0b1220;
  --viewer-bg:#0b0f17; --frame-bg:#0b0f17;

  --shadow:0 1px 2px rgba(0,0,0,.5),0 1px 3px rgba(0,0,0,.4);
  --shadow-lg:0 10px 34px rgba(0,0,0,.6),0 2px 8px rgba(0,0,0,.45);
}

/* Author palette. Eight hues that stay distinguishable side by side and keep
   >=4.5:1 against their own tint in BOTH themes — tracked changes and comment
   avatars are colour-coded by author, so these are load-bearing, not decorative. */
:root{
  --au-1:#1f5fbf; --au-1-bg:#e7effc;
  --au-2:#a3341f; --au-2-bg:#fcece8;
  --au-3:#1d7a52; --au-3-bg:#e4f4ec;
  --au-4:#7a3fa8; --au-4-bg:#f1e9fa;
  --au-5:#96631a; --au-5-bg:#fbf0dc;
  --au-6:#00707f; --au-6-bg:#e0f3f5;
  --au-7:#a82a6a; --au-7-bg:#fce9f2;
  --au-8:#41567a; --au-8-bg:#eaeef5;
}
:root[data-theme="dark"]{
  --au-1:#7fb0f5; --au-1-bg:#16233c;
  --au-2:#f0917c; --au-2-bg:#33201a;
  --au-3:#63cb9c; --au-3-bg:#122a20;
  --au-4:#c3a2ef; --au-4-bg:#241c38;
  --au-5:#dfae5c; --au-5-bg:#2c2312;
  --au-6:#5cc3ce; --au-6-bg:#0f2a2d;
  --au-7:#ef8fbc; --au-7-bg:#331a26;
  --au-8:#9fb2d4; --au-8-bg:#1c2436;
}

/* ---------- Reset / base ------------------------------------------------ */
*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:var(--fs-base)/1.5 var(--ui-font);
  -webkit-font-smoothing:antialiased;
  overflow:hidden;
}
button,input,select,textarea{font:inherit;color:inherit}
a{color:var(--blue);text-decoration:none}
a:hover{text-decoration:underline}
h1,h2,h3,h4{margin:0;font-weight:640;letter-spacing:-.01em}
p{margin:0}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:var(--scroll-thumb);border-radius:6px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-track{background:transparent}

/* One universal focus ring. Deliberately does NOT set border-radius — doing so
   squared off every button in a sibling app. */
:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* ---------- Boot watchdog ---------------------------------------------- */
#boot{position:fixed;inset:0;display:grid;place-items:center;background:var(--bg);z-index:9000}
.boot-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--sp-12) var(--sp-16);box-shadow:var(--shadow);min-width:300px;text-align:center}
.boot-title{font-size:var(--fs-lead);font-weight:680;color:var(--ac-ink)}
.boot-msg{margin-top:var(--sp-4);color:var(--ink-2);font-size:var(--fs-ui)}
.boot-actions{margin-top:var(--sp-8)}
.boot-err{margin-top:var(--sp-8);text-align:left;font:var(--fs-cap)/1.5 var(--mono);
  color:var(--red);background:var(--red-bg);border:1px solid var(--red-line);
  border-radius:var(--radius-sm);padding:var(--sp-5);max-width:520px;max-height:180px;overflow:auto;white-space:pre-wrap}

/* ---------- App frame --------------------------------------------------- */
/* A COLUMN now: the suite's bar on top, then the app's row. Everything that
   overlays (drawer, scrim, peeked rail) anchors to #appRow, so the suite bar
   is never covered by the app's own furniture. */
#app{display:flex;flex-direction:column;height:100%;position:relative}
#appRow{display:flex;flex:1 1 auto;min-height:0;position:relative}

/* The suite bar — minimal, identical in every app. The brand at its left IS
   the all-apps control; the account corner rides its right. */
/* BUILT LIKE .hub-bar ON PURPOSE — same padding, same tallest child (34px),
   so the two bars come out the same height and the suite mark lands on the
   SAME PIXELS on the landing page and inside an app. Crossing from one to the
   other must not make the logo appear to jump. Measured: icon at x=24, y=15
   on both. Change this padding and you must change .hub-bar's with it. */
#obBar{flex:0 0 auto;display:flex;align-items:center;gap:var(--sp-6);
  padding:var(--sp-6) var(--sp-12);background:var(--panel);
  border-bottom:1px solid var(--line)}
/* The suite brand is the BARE mark on the bar, exactly as on the landing
   page — no chip behind it (the dark fill read as a weird floating block).
   The APP chip in the collapsed accordion is the exception below: its white
   name needs the rail fill to be legible. ONE rule set per property — two
   same-specificity .ob-brand blocks fighting over `background` is how the
   chip lost to `background:none` the first time. */
/* The negative margin cancels this button's OWN left padding exactly, so the
   padding is pure hover decoration and the mark itself sits on the bar's
   padding edge — the same 24px the landing page's brand starts at. The 3px
   vertical keeps the button 34px tall (28 + 3 + 3), which is what makes the
   two bars the same height. */
.ob-brand{display:flex;align-items:center;gap:8px;border:0;padding:3px 7px;
  margin-left:-7px;font-family:inherit;cursor:pointer;border-radius:var(--radius-sm);
  background:none}
div.ob-brand{cursor:default}
button.ob-brand:hover{background:var(--surface-hover)}
button.ob-brand:focus-visible{outline:2px solid var(--ob-edge);outline-offset:2px}
.ob-name{font-size:15px;font-weight:750;letter-spacing:-.01em;color:#fff}
/* The breadcrumb — Opus Bench › Opus Stylus — is on the bar ALWAYS now, not
   only while the rail is collapsed (Alex liked reading the hierarchy up
   there). Not on narrow: the drawer is closed at rest there and the
   hamburger already owns that corner. */
.ob-sep,.ob-appchip{display:none}
/* The separator sits on the BAR, not on a chip — it must be ink, not white. */
#app:not(.narrow) .ob-sep{display:flex;align-items:center;
  color:var(--ink-4);font-size:16px;margin:0 2px 0 8px}
#app:not(.narrow) .ob-appchip{display:flex;margin-left:0;padding:3px 10px 3px 6px}
/* Transparent on the bar, dark name (Alex's answer to the judgment call —
   the chip used to keep the rail fill for its white name). */
.ob-appchip{background:none}
.ob-appchip .ob-name{font-size:14px;color:var(--ink)}
#obBar .tb-acct{display:flex;align-items:center;gap:var(--sp-4)}
#sidebar{
  width:var(--sidebar-w);flex:0 0 auto;background:var(--nav-fill);color:#dbe3f5;
  border-right:1px solid var(--nav-edge);display:flex;flex-direction:column;overflow:hidden;
  transition:width .16s ease;
}
#app.nav-collapsed #sidebar{width:0;border-right:0}
/* The rail only sweeps when the person toggles it — see ui.js stillFrame().
   Boot, re-renders and resizes set the class inside a still frame, so the
   rail is simply already where it belongs and never flashes shut. */
#app.nav-still #sidebar{transition:none}

/* The collapse control in the sidebar head, and its twin in the topbar. The
   topbar one is always present because once the sidebar is gone it is the only
   way back — and on a narrow screen it is the only way in at all. */
.nav-headtxt{min-width:0;flex:1 1 auto}
.nav-collapse{flex:0 0 auto;width:26px;height:26px;border-radius:6px;border:0;cursor:pointer;
  background:#ffffff14;color:#dbe3f5;line-height:1;display:grid;place-items:center}
.nav-collapse:hover{background:#ffffff24;color:#fff}
/* Sized to balance the action row on the right (Alex, 2026-08-15: this side
   "feels too small" against it on desktop/iPad) — the phone media query
   below already sets its OWN 42px/24px pair, so this only touches the wider
   screens it was about. */
.tb-nav{flex:0 0 auto;width:34px;height:34px;margin-right:var(--sp-5);border-radius:var(--radius-sm);
  border:1px solid transparent;background:none;cursor:pointer;color:var(--ink-3);
  display:grid;place-items:center}
.tb-nav svg{width:20px;height:20px;display:block}
.tb-nav:hover{background:var(--surface-hover);color:var(--ink);border-color:var(--line)}
/* GONE WHEN THE SIDEBAR IS THERE. It is the way back to the rail, so it belongs
   on screen exactly when the rail is not — which `.nav-collapsed` already says
   for both the desktop collapse and the narrow drawer. Offering to show
   something already filling a third of the window is what made it read as
   decoration. */
#app:not(.nav-collapsed) .tb-nav{display:none}

/* THE BREADCRUMB HAD NO RULES AT ALL, which is why "Cite›Citation library" ran
   together — the separator was a bare character between two bare spans. The
   group is the quieter half (it is where you are, not what you are looking at),
   the leaf carries the weight, and the chevron gets air on both sides and a
   lighter ink so it separates rather than competing. */
.tb-crumb-g{color:var(--ink-3);font-weight:600}
.tb-crumb-sep{display:inline-block;margin:0 var(--sp-4);color:var(--ink-4);font-weight:400}
.tb-crumb-l{color:var(--ink);font-weight:700}

/* Peek: point at the left edge and the sidebar slides back OVER the content, so
   a quick look costs no click and the writing surface never moves. */
#navPeek{position:absolute;left:0;top:0;bottom:0;width:12px;z-index:40;display:none}
#app.nav-collapsed:not(.narrow) #navPeek{display:block}
/* The peeked rail is the SAME rail, so it is the width you dragged it to —
   otherwise peeking a widened sidebar snapped it back to the default.
   ONLY WHEN COLLAPSED. Peek is what an absent rail offers; taking an
   already-visible sidebar out of flow drops #main to full width and slides
   the whole page left, which is the opposite of "the writing surface never
   moves" and reads as the sidebar closing by itself. */
#app.nav-peek.nav-collapsed:not(.narrow) #sidebar{width:var(--rail-w, var(--sidebar-w));position:absolute;left:0;top:0;bottom:0;
  z-index:60;box-shadow:0 10px 40px rgba(16,24,40,.28);border-right:1px solid var(--nav-edge)}

/* Narrow: the sidebar becomes a drawer over the content, because there is no
   room to give it. It always starts closed — a drawer restored open would
   cover a phone screen entirely. */
#navScrim{position:absolute;inset:0;background:rgba(16,24,40,.42);z-index:50;display:none}
#app.narrow.nav-open #navScrim{display:block}
#app.narrow #sidebar{position:absolute;left:0;top:0;bottom:0;z-index:60;
  width:min(300px,86vw);border-right:1px solid var(--nav-edge);
  transform:translateX(-100%);transition:transform .18s ease}
#app.narrow.nav-open #sidebar{transform:none;box-shadow:0 10px 40px rgba(16,24,40,.34)}
/* Collapsed is the resting state on narrow, so the width-zero rule must not win. */
#app.narrow.nav-collapsed #sidebar{width:min(300px,86vw);border-right:1px solid var(--nav-edge)}
@media (prefers-reduced-motion:reduce){#sidebar{transition:none}}

#main{flex:1 1 auto;display:flex;flex-direction:column;min-width:0}
#topbar{flex:0 0 auto}
/* RESERVE THE SCROLLBAR'S WIDTH, ALWAYS. ::-webkit-scrollbar gives this app a
   classic 10px scrollbar rather than macOS's overlay one, so it takes real
   width — and a surface that only sometimes scrolls therefore only sometimes
   loses 10px, sliding its centred cards sideways whenever a card, a count or
   an async load crosses the viewport height. It reads exactly like the rail
   moving. `stable` keeps the gutter there whether it scrolls or not, so the
   centre never moves. */
#content{flex:1 1 auto;overflow:auto;position:relative;scrollbar-gutter:stable}

/* ---------- Sidebar ----------------------------------------------------- */
.nav-head{padding:var(--sp-10) var(--sp-10) var(--sp-4);display:flex;align-items:center;gap:var(--sp-5)}
/* The app icon is a FINISHED tile — its own rounded rect, gradient and margin
   are baked into the artwork. Boxing it in a second translucent rounded
   square left it floating off-centre inside a visible frame. No box: the
   artwork fills the slot and centres itself. */
.nav-mark{width:28px;height:28px;display:grid;place-items:center;
  font-weight:800;font-size:var(--fs-cap);letter-spacing:.02em;color:#fff;flex:0 0 auto}
.nav-title{font-size:var(--fs-md);font-weight:660;color:#fff;letter-spacing:-.01em}
.nav-sub{font-size:var(--fs-micro);color:#9fb0d8;text-transform:uppercase;letter-spacing:.08em}
.nav-scroll{flex:1 1 auto;overflow:auto;padding:var(--sp-4) var(--sp-5) var(--sp-10)}
.nav-sec{margin-top:var(--sp-8)}
/* A section head is a CONTROL now, not a caption — it opens and shuts the
   section. It was a <div>, so it needs the button reset. */
/* The heading and its + share a row; the head still stretches, so folding by
   clicking the label works exactly as before. */
.nav-sec-row{display:flex;align-items:center}
.nav-sec-row .nav-sec-head{flex:1 1 auto;min-width:0}
/* THE + IS THE SAME CONTROL AS THE ROW MENU, in the same place, revealed the
   same way — it is "add here" where ⋯ is "do something to this". Its width is
   reserved so appearing on hover cannot shift the count under the pointer, the
   same rule the outline's + follows. */
/* The group bar and its tools share a row; the head still stretches, so folding
   and going to the group home behave exactly as before. */
.nav-group-row{display:flex;align-items:center}
.nav-group-row .nav-group{flex:1 1 auto;min-width:0}
/* Slightly brighter here than on a section heading, because the group bar's own
   ink is brighter — a tool must not look fainter than the label beside it. */
.nav-group-row .nav-tool{opacity:.95;align-self:center;margin-right:var(--sp-2)}
.nav-group-row .nav-tool:hover,.nav-group-row .nav-tool.on{opacity:1}

/* A SECTION'S OWN TOOLS, on its heading. Always visible where the + is
   hover-revealed: the + makes a new thing and can wait to be looked for, but
   these ARE the section's other destinations and hiding them would be the
   pinned row they replaced, only harder to find. Same 22px box as the + so the
   heading's right edge is one rhythm. */
.nav-tool{flex:0 0 auto;position:relative;display:inline-flex;align-items:center;
  justify-content:center;width:22px;height:22px;padding:0;border:0;
  border-radius:var(--radius-sm);background:none;color:inherit;cursor:pointer;opacity:.72}
.nav-tool:hover{background:#ffffff1f;opacity:1}
.nav-tool.on{opacity:1;background:#ffffff26}
.nav-tool .mk{display:inline-flex}
.nav-tool svg{width:19px;height:19px;display:block}
/* The count rides the corner rather than taking width — a heading has three
   controls on it now and none of them may push the label. */
.nav-tool-n{position:absolute;top:-1px;right:-2px;font-size:9px;font-weight:700;
  line-height:1;padding:1px 2px;border-radius:4px;background:var(--rail);color:#0d1420}
/* PERMANENT, not hover-revealed (Alex, 2026-08-14): a control that fades in
   when the exact row is hovered is a control most people never learn exists,
   and at 60% ink it failed contrast on the rail anyway. Sized with the rail's
   other icons; the hover still brightens, it just is not the reveal. */
.nav-add{flex:0 0 auto;width:24px;height:24px;margin-right:var(--sp-3);padding:0;
  border:0;border-radius:var(--radius-sm);background:none;color:inherit;
  font:600 17px/1 inherit;cursor:pointer;opacity:.9}
.nav-add:focus-visible{opacity:1}
.nav-add:hover{background:#ffffff1f;opacity:1}
/* A SECTION HEADING OUTRANKS ITS CONTENTS HERE TOO. Same defect the citation
   rail had and the same fix: 10px headings over 12.5px rows meant the label
   for a group was smaller than the things inside it, so the column had no
   hierarchy to read (Alex, 2026-08-16: "upgrade the WRITE side panes like
   that too, as well as REVIEW and EDIT"). Matches the rows in size and wins
   on weight, case and colour. */
.nav-sec-head{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-4) var(--sp-5);
  font-size:var(--fs-ui);text-transform:uppercase;letter-spacing:.06em;color:#a8bbe4;font-weight:800;
  width:100%;background:none;border:0;font-family:inherit;cursor:pointer;text-align:left;
  border-radius:var(--radius-sm)}
.nav-sec-head:hover{background:#ffffff10;color:#cdd8ee}
.nav-sec-head:focus-visible{outline:2px solid #ffffff5c;outline-offset:-2px}
/* The count stays readable while the section is shut — it is the whole reason
   you would leave one closed, so hiding it with the contents defeats the point. */
/* One count column on this rail as well: right-aligned, tabular, one minimum
   width, so the numbers stack instead of floating after each label. */
.nav-sec-head .cnt{margin-left:auto;font-weight:700;letter-spacing:0;
  font-size:var(--fs-cap);min-width:2.2em;text-align:right;
  font-variant-numeric:tabular-nums;opacity:.85}
.nav-sec-head .lbl{flex:0 0 auto}
.nav-sec-head .tw{width:10px;flex:0 0 auto;font-size:8px;opacity:.75;
  transition:transform .14s ease;transform:rotate(90deg)}
.nav-sec.is-collapsed .nav-sec-head .tw{transform:rotate(0deg)}

/* The guide line down a nested group, straight from the Expense Suite rail:
   it is what makes six indented rows read as belonging to the heading above
   rather than as six more top-level rows that happen to be inset. */
.nav-children{position:relative;padding-left:var(--sp-5)}
/* The guide line is the ACCENT everywhere a list is open — the clear red
   hierarchy line the Write group wears is now the house treatment for every
   group. Dimmed at rest; the on-path rules lift it to full strength, so the
   breadcrumb still reads as the one bright path down the rail. */
.nav-children::before{content:"";position:absolute;left:calc(var(--sp-5) - 3px);top:2px;bottom:2px;
  width:2px;background:var(--ac-edge, #c9a0a8);opacity:.45;border-radius:1px}

/* "Nothing yet" is a row, not an absence. An empty section that renders nothing
   looks broken; one that says so looks finished. */
.nav-row.is-empty{color:#8fa3cf;font-style:italic;cursor:default;opacity:.75}
.nav-row.is-empty:hover{background:none;color:#8fa3cf}

/* The locker sits a step in from the documents it serves, so it reads as a
   reference shelf rather than a fifth kind of paper. */
.nav-row.nav-locker{margin-top:var(--sp-3);color:#b9c7e6}
.nav-row.nav-locker .mk{opacity:.7}
.nav-row.nav-locker .cnt{margin-left:auto;font-size:var(--fs-tag);color:#9fb0d8}
.nav-row{display:flex;align-items:center;gap:var(--sp-5);padding:var(--sp-4) var(--sp-5);
  border-radius:var(--radius-sm);cursor:pointer;color:#cdd8ee;font-size:var(--fs-ui);
  border:1px solid transparent;user-select:none}
.nav-row:hover{background:#ffffff12;color:#fff}
.nav-row.sel{background:#ffffff1f;color:#fff;border-color:#ffffff26;font-weight:600}
.nav-row .mk{width:16px;flex:0 0 auto;display:grid;place-items:center;opacity:.9}
.nav-row .lbl{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav-row .val{font-size:var(--fs-cap);color:#9fb0d8;flex:0 0 auto;
  min-width:2.2em;text-align:right;font-variant-numeric:tabular-nums}
/* ONE LEFT EDGE for every label on the rail. Rows that carry a mark and rows
   that do not sat at two different x, exactly as the citation rail did — a
   row whose label comes first is inset by the width a mark would have taken. */
.nav-row > .lbl:first-child{margin-left:calc(16px + var(--sp-5))}
.nav-foot{flex:0 0 auto;border-top:1px solid #ffffff1f;padding:var(--sp-5)}

/* ---------- Topbar ------------------------------------------------------ */
/* The bar WRAPS before it clips. overflow:clip on its own silently amputated
   the right-hand group: between roughly 760px and 900px that took Export with
   it — the only way to get a manuscript out of the app — with no scroll to
   bring it back. Wrapping costs a second row at those widths and loses nothing.
   The clip stays as a last resort against a stray unshrinkable child. */
.tb{background:var(--tb-bg);border-bottom:1px solid var(--tb-line);
  padding:var(--sp-5) var(--sp-8);display:flex;align-items:center;gap:var(--sp-6);
  flex-wrap:wrap;row-gap:var(--sp-4);
  overflow:clip;overflow-clip-margin:8px}
.tb-crumb{flex:1 1 0;min-width:0}
.tb-sec{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.08em;color:var(--ink-4);font-weight:700}
/* One step above --fs-title (the same size card and modal headings use) so
   this reads at the same weight as the action row opposite it — a fork
   scoped to just the topbar crumb/title, not the shared token, since card
   and modal headings were not part of what looked small. Phones keep their
   own smaller --fs-md override below, untouched. */
.tb-name{font-size:calc(var(--fs-title) + 2px);font-weight:660;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* CENTRED, because this row mixes text with a control. Without align-items a
   flex child STRETCHES to the tallest item — the picker — and its text then
   sits at the top of a box twice the height of the words next to it. That is
   why "2580 words" and "3 open comments" did not sit on the same line as the
   dropdown beside them (Alex, 2026-08-18). */
.tb-facts{font-size:var(--fs-cap);color:var(--ink-3);display:flex;align-items:center;
  gap:var(--sp-5);flex-wrap:wrap}
.tb-facts b{font-weight:640;color:var(--ink-2)}
/* THE SELECT IS NOT A SELECT BY THE TIME IT IS DRAWN. U.upgradeSelects swaps
   every one for a .pickbtn, so this compact rule — 20px tall, caption-sized,
   written for a status line — matched nothing, and the citation-style picker
   rendered at the standard 34px form-control height in a row of 12px text.
   Both selectors are kept: the native one still applies wherever a select
   survives (data-native, or before the upgrade runs). */
.tb-style select,.tb-style .pickbtn,.tb-style .pickbtn.wide{font-size:var(--fs-cap);
  padding:0 var(--sp-4);height:22px;min-height:0;line-height:1;width:auto;
  border-radius:var(--radius-sm);border:1px solid var(--line);background:var(--surface-2);
  color:var(--ink-2);max-width:130px;gap:4px}
.tb-style .pickbtn svg{width:10px;height:10px;flex:0 0 auto}
.tb-style .pickbtn>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tb-style .pickwrap{display:inline-flex;vertical-align:middle}
/* The action group wraps internally too. `flex:0 0 auto` made it one
   unshrinkable block, so a single over-wide group still ran past the clip and
   took the last button (Send back, on a co-author copy) off-screen. */
.tb-right{display:flex;align-items:center;gap:var(--sp-6);
  flex:0 1 auto;min-width:0;flex-wrap:wrap;row-gap:var(--sp-4);justify-content:flex-end}
/* Related controls sit together and are separated from the next group by a
   rule, so the bar reads as three decisions rather than six loose buttons. */
.tb-group{display:inline-flex;align-items:center;gap:var(--sp-3)}
/* A SEGMENTED pill: buttons that are one idea render as one control — Track
   with its markup mode, the faces with ＋ Co-authors. Joined borders, shared
   corners, no interior gap; each half keeps its own action and title
   (Alex, 2026-08-15: the row read as a junk drawer of lookalike buttons). */
/* THE WHOLE-DOCUMENT BUTTON LIVES BESIDE THE TITLE, not out at the far right
   (Alex, 2026-08-16: "it feels like a long way to reach with the mouse" on a
   full-screen display). Title, then this, then the stage — the three things
   that say what you are looking at, together. It was phones-only before; it is
   everywhere now, because the reach problem is worst on the widest screen.

   align-self:center because the row is baseline-aligned. That is correct for
   the WORDS on it, and wrong for a box with an icon in it: a flex item's
   baseline is its last line box, so an inline-flex button full of SVG gets
   hoisted above the text it sits next to. Centring this one item leaves the
   words sharing their baseline and puts the icon on the title's optical
   middle (Alex, 2026-08-16: "slightly higher, like its on the same text
   line"). */
.tb-wholebtn{display:inline-flex;flex:0 0 auto;padding:2px 6px;line-height:1;
  align-self:center}
.tb-wholebtn svg{display:block}
.tb-addwrap{display:none}
.tb-seg{gap:0}
.tb-seg .btn{border-radius:0;margin-left:-1px;position:relative}
.tb-seg .btn:first-child{border-radius:var(--radius-sm) 0 0 var(--radius-sm);margin-left:0}
.tb-seg .btn:last-child{border-radius:0 var(--radius-sm) var(--radius-sm) 0}
.tb-seg .btn:only-child{border-radius:var(--radius-sm)}
.tb-seg .btn:hover,.tb-seg .btn.on{z-index:1}
/* The stage word on the identity line — a door styled as a word, not a chip.
   It inherits the line's micro caps; the underline says "press me" without
   adding a third button weight to the corner. */
.tb-stagelink{border:0;background:none;padding:0;cursor:pointer;
  font:inherit;letter-spacing:inherit;text-transform:inherit;
  color:var(--ac-ink);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--ac-edge)}
.tb-stagelink:hover{text-decoration-color:var(--ac-ink)}
/* THE ONE-ROW HEADER (write view). The crumb is a baseline row, not a
   column: title truncates, the mini words and the stage door sit beside it,
   and the saved/words/style cluster reads as one quiet phrase on the right
   before the action pills. The whole band is a single shelf again. */
/* CENTRED, NOT BASELINE. The stage word and the status are small caps beside a
   title two sizes bigger; sitting them on its baseline hangs them off the
   bottom of the line. Centring reads as one row (Alex, 2026-08-17: "needs to be
   center vertically to the text size of the title"). */
.tb-onerow{display:flex;align-items:center;gap:var(--sp-4);min-width:0}
/* Last in the row and the only thing allowed to be long: it takes what is left
   and truncates into it rather than pushing the controls along. */
.tb-onerow .tb-name{flex:0 1 auto;min-width:0}
.tb-onerow .tb-wholebtn{flex:0 0 auto}
.tb-mini{flex:0 0 auto;font-size:var(--fs-micro);text-transform:uppercase;
  letter-spacing:.08em;color:var(--ink-4);font-weight:700;white-space:nowrap}
.tb-onerow .tb-stagelink{flex:0 0 auto;font-size:var(--fs-micro);
  text-transform:uppercase;letter-spacing:.08em;font-weight:700}
.tb-quiet{display:inline-flex;align-items:center;gap:var(--sp-4);white-space:nowrap}
.tb-quiet .tb-facts{flex-wrap:nowrap}
/* The old inter-group separator died here: drawn as ::before OF THE NEXT
   ELEMENT, it rendered INSIDE a following button's box — the stray "|" glyph
   living in the Export button on every screen (Alex, 2026-08-15). The
   segmented pills group the bar now; nothing needs a drawn divider. */
/* A control that opens a menu says so. A bare ⋯ gave no reason to press it. */
/* The menu caret. It was a 9px glyph at 60% opacity — the smallest, faintest
   thing on the toolbar, on a row of buttons whose whole job is to say "there is
   more behind me". Drawn now, at a size you can actually see, inheriting the
   button's ink rather than being dimmed out of it. */
.tb-car{display:inline-flex;align-items:center;margin-left:3px;opacity:.75}
.tb-car svg{width:13px;height:13px;display:block}
.btn:hover .tb-car{opacity:1}
/* Save state. Shape and wording carry it, not colour alone — the tick and the
   word read the same to someone who cannot tell red from grey. */
.save-ind{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-cap);
  color:var(--ink-3);white-space:nowrap}
.save-ind.bad{color:var(--red);font-weight:640}
.save-ind.bad .btn{margin-left:var(--sp-2)}

/* ---------- Buttons / controls ------------------------------------------ */
.btn{
  display:inline-flex;align-items:center;gap:var(--sp-4);
  background:var(--tb-btn-bg);border:1px solid var(--tb-btn-line);color:var(--ink);
  padding:5px 11px;border-radius:var(--radius-sm);cursor:pointer;font-size:var(--fs-ui);
  font-weight:520;line-height:1.35;white-space:nowrap
}
.btn:hover{background:var(--tb-btn-hover)}
.btn:active{background:var(--tb-btn-active)}
.btn[disabled]{opacity:.45;cursor:default;pointer-events:none}
/* The three accent roles in one rule, which is the clearest place to see why
   they have to be three: the fill needs 3:1 against the panel behind it, and
   the label on top needs 4.5:1 against the FILL — which in dark mode means a
   near-black label on a bright button, not white. */
.btn.primary{background:var(--ac-fill);border-color:var(--ac-fill);color:var(--ac-on);font-weight:600}
.btn.primary:hover{background:var(--ac-fill-hover);border-color:var(--ac-fill-hover)}
.btn.danger{background:var(--red-bg);border-color:var(--red-line);color:var(--red);font-weight:600}
.btn.ghost{background:transparent;border-color:transparent;color:var(--ink-2)}
.btn.ghost:hover{background:var(--tb-btn-hover);color:var(--ink)}
.btn.sm{padding:3px 8px;font-size:var(--fs-sm)}
.btn.on{background:var(--surface-sel);border-color:var(--blue);color:var(--ac-ink);font-weight:640}

input[type=text],input[type=email],input[type=number],input[type=date],input[type=search],select,textarea{
  background:var(--input-bg);border:1px solid var(--input-line);border-radius:var(--radius-sm);
  padding:5px 8px;font-size:var(--fs-ui);width:100%
}
textarea{resize:vertical;line-height:1.5}
label.fld{display:block;margin-bottom:var(--sp-6)}
label.fld > span{display:block;font-size:var(--fs-cap);color:var(--ink-2);font-weight:600;margin-bottom:var(--sp-2)}
.row{display:flex;gap:var(--sp-6);flex-wrap:wrap}
.row > *{flex:1 1 160px;min-width:0}
.hint{font-size:var(--fs-cap);color:var(--ink-3)}
.spacer{flex:1 1 auto}

/* ---------- Cards / layout --------------------------------------------- */
.page{padding:var(--sp-12) var(--sp-16);max-width:1180px;margin:0 auto}
.page.wide{max-width:none}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);margin-bottom:var(--sp-12);position:relative}
.card-head{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-8) var(--sp-10);
  border-bottom:1px solid var(--line-2)}
.card-head h3{font-size:var(--fs-title)}
.card-body{padding:var(--sp-10)}
.card.collapsed > :not(.card-head){display:none}
.card.collapsed .card-head{border-bottom:0}
.empty{padding:var(--sp-16);text-align:center;color:var(--ink-3);font-size:var(--fs-ui)}

.tag{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-tag);font-weight:650;
  padding:1px 7px;border-radius:999px;border:1px solid var(--line-strong);background:var(--surface-2);color:var(--ink-2)}
.tag.green{background:var(--green-bg);border-color:var(--green-line);color:var(--green)}
.tag.amber{background:var(--amber-bg);border-color:var(--amber-line);color:var(--amber)}
.tag.red{background:var(--red-bg);border-color:var(--red-line);color:var(--red)}
.tag.blue{background:var(--blue-lt);border-color:var(--blue-line);color:var(--ac-ink)}
.tag.purple{background:var(--purple-bg);border-color:var(--purple-line);color:var(--purple)}

.notice{border:1px solid var(--line);border-left:3px solid var(--ink-4);background:var(--surface-2);
  border-radius:var(--radius-sm);padding:var(--sp-6) var(--sp-8);font-size:var(--fs-ui);margin-bottom:var(--sp-8)}
.notice.info{border-left-color:var(--blue);background:var(--blue-lt)}
.notice.warn{border-left-color:var(--amber);background:var(--amber-bg)}
.notice.bad{border-left-color:var(--red);background:var(--red-bg)}
.notice.good{border-left-color:var(--green);background:var(--green-bg)}

table.grid{width:100%;border-collapse:collapse;font-size:var(--fs-ui)}
table.grid th{text-align:left;font-size:var(--fs-cap);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700;padding:var(--sp-4) var(--sp-6);border-bottom:1px solid var(--line-strong)}
table.grid td{padding:var(--sp-5) var(--sp-6);border-bottom:1px solid var(--line-2);vertical-align:top}
table.grid tr:hover td{background:var(--surface-hover)}

/* ==== The card tables (Manuscripts, Reviews, Abstracts…) on a PHONE ========
   Alex's screenshot: a long title ate the table's whole column-width budget,
   wrapped to eight lines, and Journal/Words/Updated were squeezed to slivers
   or nothing — the browser's table column algorithm has no idea a phone is
   involved. The rows become flex-wrapping CARDS instead of table cells: the
   identity column (title, journal…) takes the full width and wraps on its
   own terms, the meta columns flow as compact chips below it sized to their
   OWN content instead of a shared grid, and any per-row action grows to a
   real touch target. `.hu-table` is EXCLUDED — the platform roster already
   solved its own width problem by scrolling sideways inside its card
   (Alex's earlier ask), and stacking it too would fight that. */
@media (max-width:640px){
  .card table.grid:not(.hu-table) thead{display:none}
  .card table.grid:not(.hu-table),
  .card table.grid:not(.hu-table) tbody{display:block;width:100%}
  .card table.grid:not(.hu-table) tr{
    display:flex;flex-wrap:wrap;align-items:center;
    column-gap:10px;row-gap:4px;
    padding:12px 2px;border-bottom:1px solid var(--line-2);
  }
  .card table.grid:not(.hu-table) tr:last-child{border-bottom:0}
  .card table.grid:not(.hu-table) td{
    display:block;padding:0;border:0;vertical-align:baseline;
    flex:0 1 auto;min-width:0;text-align:left!important;
  }
  /* The identity cell — title, or journal/meeting name — always takes the
     row's own line and wraps normally; nothing fights it for width. */
  .card table.grid:not(.hu-table) td:first-child{flex:1 1 100%}
  .card table.grid:not(.hu-table) td .tag{font-size:var(--fs-cap)}
  /* A per-row action (Open, ⋯) sits at the end of its line and is a real
     touch target, not a 24px table-cell button. */
  .card table.grid:not(.hu-table) td:last-child:has(.btn){margin-left:auto}
  .card table.grid:not(.hu-table) td .btn{min-height:34px}
}

/* ---------- Toasts ------------------------------------------------------ */
#toasts{position:fixed;bottom:var(--sp-12);left:50%;transform:translateX(-50%);z-index:8000;
  display:flex;flex-direction:column;gap:var(--sp-4);align-items:center;pointer-events:none}
.toast{background:var(--toast-bg);color:var(--toast-ink);padding:var(--sp-5) var(--sp-10);
  border-radius:999px;font-size:var(--fs-ui);font-weight:560;box-shadow:var(--shadow-lg);
  animation:toastIn .16s ease-out;max-width:70vw}
.toast.bad{background:var(--red);color:#fff}
.toast.good{background:var(--green);color:#fff}
/* 'warn' has been passed by three call sites since before this rule existed
   (js/citeui.js, js/screens.js, and now js/app.js's unreachable-server
   notice). MS.toast writes the kind straight into the class, so all three
   rendered as the plain grey toast — the one styling that says "nothing
   notable here", on the messages that are partial failures. */
/* Ink is the amber's PAIRED TINT, not white — the same rule corner.css
   states for the bell badge. --amber inverts between themes (#8a5c00
   light, #e8b44f dark), so a hardcoded #fff reads fine in light and sits
   near 2:1 in dark, which is how this defect ships: reviews happen in
   light mode. The pair moves together and both directions stay legible. */
.toast.warn{background:var(--amber);color:var(--amber-bg)}
@keyframes toastIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ---------- Modals ------------------------------------------------------ */
.scrim{position:fixed;inset:0;background:rgba(12,18,32,.42);backdrop-filter:blur(2px);
  z-index:7000;display:grid;place-items:center;padding:var(--sp-16)}
/* dvh AS WELL AS vh, and this is the whole reason the Send button was
   unreachable on a phone (Alex, 2026-08-16). On iOS, 1vh is a hundredth of the
   viewport WITH Safari's toolbars retracted — a height the page does not
   actually have while they are showing — so an 86vh dialog is taller than the
   screen and its footer sits underneath the browser chrome, scrollable body
   and all. dvh is the height that actually exists right now. The vh line stays
   first as the fallback for anything that does not know dvh. */
.modal{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-lg);width:min(640px,100%);max-height:86vh;max-height:86dvh;
  display:flex;flex-direction:column;animation:menuIn .14s ease-out}
.modal.lg{width:min(980px,100%)}
/* Narrower than the default, for a dialog whose whole content is one field —
   a note box the width of a page reads as an address bar. */
.modal.sm{width:min(460px,100%)}
.modal.xl{width:min(1240px,100%)}
.modal-head{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-8) var(--sp-10);
  border-bottom:1px solid var(--line-2)}
.modal-head h3{font-size:var(--fs-title);flex:1 1 auto}
.modal-body{padding:var(--sp-10);overflow:auto;flex:1 1 auto}
/* flex:0 0 auto so the footer can never be squeezed to nothing by a long body
   — it is the row with the button that finishes the job. */
.modal-foot{display:flex;align-items:center;gap:var(--sp-5);padding:var(--sp-8) var(--sp-10);
  border-top:1px solid var(--line-2);justify-content:flex-end;flex:0 0 auto;
  background:var(--panel)}
@keyframes menuIn{from{opacity:0;transform:scale(.98) translateY(-4px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.modal,.toast{animation:none}}

/* ---------- Dropdown menus --------------------------------------------- */
.dropmenu{position:fixed;z-index:7500;background:var(--tb-menu-bg);border:1px solid var(--line-strong);
  border-radius:8px;box-shadow:var(--shadow-lg);padding:var(--sp-3);min-width:175px;
  max-height:70vh;overflow:auto;animation:menuIn .12s ease-out}
/* THE MENU'S OWN INK, and the one place the logo's darkest blue is used as
   type. Sampled from img/app-suite.png rather than guessed — #4e6481 is the
   darkest colour that occupies real area in the mark, and it clears AA on every
   ground a menu opens over (6.1:1 on white, 5.0:1 on the darkened grey).

   Dark mode cannot use it as-is: #4e6481 on the dark menu ground is 2.6:1, well
   under the 4.5:1 a label needs. So it is lifted along ONE axis — hue 214 and
   saturation 0.246 both held, lightness raised from 0.41 to 0.56 — until it
   clears AA with a small margin, and no further. #7990ae is 4.8:1 on the dark
   ground and 76 units from the brand colour where the earlier tint was 169:
   the closest thing to the logo's blue that can still be read. */
.dropmenu button{display:flex;align-items:center;gap:var(--sp-5);width:100%;text-align:left;
  background:none;border:0;padding:var(--sp-4) var(--sp-6);border-radius:6px;
  cursor:pointer;font-size:var(--fs-ui);white-space:nowrap;color:var(--menu-ink)}
.dropmenu button:hover{background:var(--surface-hover)}
.dropmenu button.danger{color:var(--red)}
.dropmenu .sep{height:1px;background:var(--line-2);margin:var(--sp-3) 0}
.dropmenu .grp{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.08em;
  color:var(--ink-4);font-weight:700;padding:var(--sp-4) var(--sp-6) var(--sp-2)}

/* A MENU WITH AN ICON COLUMN. The icons sit on a fixed rail so the labels line
   up whatever each glyph's width is — a ragged text edge is what makes an
   icon menu look assembled rather than designed. Roomier rows, because a menu
   carrying a second line of explanation is read, not just clicked. */
/* Capped, so the explanation wraps to a second line instead of stretching the
   menu to the width of its longest sentence — a 590px menu clamps to the left
   edge of the window and stops looking like it belongs to the button that
   opened it. */
.dropmenu.has-icons{min-width:270px;max-width:340px;padding:var(--sp-4)}
.dropmenu.has-icons button{align-items:flex-start;gap:var(--sp-6);
  padding:var(--sp-5) var(--sp-6);white-space:normal}
.mi-ic{flex:0 0 20px;display:flex;align-items:center;justify-content:center;
  color:var(--ink-3);margin-top:1px}
.dropmenu button:hover .mi-ic{color:var(--ac-ink)}
.mi-tx{display:flex;flex-direction:column;gap:2px;min-width:0}
.mi-hint{font-size:var(--fs-cap);color:var(--ink-3);line-height:1.4;white-space:normal}

/* THE BARE OVERFLOW. No border, no fill, no button box — it is a way in, not a
   command, and it should read as quieter than everything it sits beside. The
   hit area stays a full 30px square; only the chrome goes. */
/* A SELECT THAT IS OURS. Shaped like the app's own controls rather than the
   operating system's popup, and it opens a .dropmenu like every other menu —
   which is the whole point: one control that looked foreign was the only one
   the OS was drawing. */
.pickbtn{display:inline-flex;align-items:center;gap:var(--sp-4);flex:0 0 auto;
  height:34px;padding:0 10px;border:1px solid var(--line-strong);
  border-radius:var(--radius-sm);background:var(--panel);color:var(--ink);
  font:inherit;font-size:var(--fs-ui);cursor:pointer;max-width:170px}
.pickbtn > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* In a form field it fills the row, the way the <select> it replaced did. */
.pickwrap{display:block}
.pickbtn.wide{display:flex;width:100%;max-width:none;justify-content:space-between;height:auto;
  min-height:34px;padding:6px 10px}
.fld .pickbtn.wide{width:100%}
.pickbtn svg{flex:0 0 auto;color:var(--ink-3)}
.pickbtn:hover{background:var(--surface-hover)}
.pickbtn:focus-visible{outline:2px solid var(--ac-fill);outline-offset:1px}

.iconbtn{display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;padding:0;border:0;background:none;color:var(--ink-3);
  border-radius:var(--radius-sm);cursor:pointer;flex:0 0 auto}
.iconbtn:hover{background:var(--surface-hover);color:var(--ink)}
.iconbtn:focus-visible{outline:2px solid var(--ac-fill);outline-offset:1px}
.kebab{display:block}

/* ============================================================================
   The manuscript editor
   ========================================================================= */
.ed{display:flex;height:100%;min-height:0}
/* THE EDITOR IS A COLUMN, NOT A BLOCK WITH A STOWAWAY.

   .ed asks for 100% of #content, and the presence strip is its SIBLING — so
   whenever that strip had any height at all, the two together came to more than
   the box holding them and #content became scrollable by exactly the strip's
   height. That is the "pull-down" gap: dragging anywhere in the editor slid the
   whole assembly, manuscript header and all, and let daylight in at the top.

   Scoped with :has() rather than making #content a flex column everywhere,
   because every other screen is a single block child that lays out correctly as
   one and would be re-flowed for nothing. Now the strip takes its own height,
   the writing columns take the rest, and nothing overflows — so there is no
   scroll to pull. min-height:0 so the columns may shrink below their content
   instead of pushing the overflow back. */
#content:has(> .ed){display:flex;flex-direction:column}
#content:has(> .ed) > .ed-presence{flex:0 0 auto}
#content:has(> .ed) > .ed{flex:1 1 auto;height:auto;min-height:0}
.ed-outline{width:230px;flex:0 0 auto;border-right:1px solid var(--line);background:var(--surface-2);
  overflow:auto;position:relative;transition:width .14s ease}
/* The citation library's full-text bucket and its attachment mark. The bucket
   is a drop target AND a button: the file arrives by drag when somebody has
   it in a Finder window, and by picker when they do not. Dashed, because a
   dashed border is the one shape a person already reads as "put something
   here" without a label telling them so. */
/* The same cap as the file rows and the small buckets. This one was missed —
   .cite-drop.sm got a max-width and the full-size bucket did not, so the box
   that appears when a reference has NO full text stretched the whole pane
   while every row beside it stopped at 42% (Alex, 2026-08-16). */
.cite-drop{display:flex;align-items:center;gap:var(--sp-5);
  padding:var(--sp-6) var(--sp-7);border:1.5px dashed var(--line-strong);
  border-radius:var(--radius);background:var(--surface-2);color:var(--ink-3);
  cursor:pointer;transition:border-color .12s,background .12s,color .12s;
  max-width:min(100%, max(380px, 42%))}
.cite-drop:hover,.cite-drop:focus-visible{border-color:var(--ac-fill);
  background:var(--ac-wash);color:var(--ink-2)}
.cite-drop b{color:var(--ink);font-size:var(--fs-ui)}
/* ARMED = you went out to the publisher for this reference and have just come
   back to the tab. Louder than :hover deliberately — hover answers "can I drop
   here", this has to answer "here is the errand you left on" to somebody whose
   attention is still in the other window. Not a dragover state: the desktop
   shell swallows those before the page sees them. */
.cite-drop.armed{border-color:var(--ac-fill);background:var(--ac-wash);
  color:var(--ink-2);box-shadow:0 0 0 3px var(--ac-wash)}
.ci-clip{display:inline-flex;align-items:center;color:var(--ac-ink);flex:0 0 auto}

.cite-more{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-8);
  border-top:1px solid var(--line-2);flex-wrap:wrap}
.cite-more .hint{flex:1 1 auto;min-width:0}

/* ==== FILES ON A REFERENCE ==============================================
   One row shape for the full text, supplements and everything else, because
   they are the same verbs — a list whose controls move around is a list you
   have to read instead of scan. */
/* A FILE ROW IS AS WIDE AS IT NEEDS TO BE, not as wide as the pane. Stretched
   across a full-screen citation pane the Open and ⋯ ended up an inch from the
   name they belong to, so the row read as two unrelated things (Alex,
   2026-08-16). Capped, with the name taking the slack and its full text in the
   tooltip. */
.cd-file{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-4) var(--sp-5);
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface-2);
  margin-bottom:var(--sp-3);max-width:min(100%, max(380px, 42%))}
/* Just under half the pane on a desktop, never below a usable 380px, never
   wider than the pane itself. The floor matters as much as the percentage:
   at 460px it, not the 52%, was what actually set the width on a full-screen
   display — so trimming only the percentage would have changed nothing there
   (Alex, 2026-08-16: "50% was too far, cut it down about 10%"). 380px still
   holds the bubble, a readable stretch of filename, Open and the ⋯. */
.cite-drop.sm{max-width:min(100%, max(380px, 42%))}
.cd-file.is-dragging{opacity:.45}
/* EVERY BUBBLE THE SAME SIZE, its word centred — a column of pills that each
   hug their own text makes the filenames beside them start in a different
   place on every row, and the eye reads that as disorder rather than as data.
   Sized to hold "Data Dictionary", the longest of the standard set; anything
   longer is cut with an ellipsis (Alex, 2026-08-16). */
.cd-file-cat{flex:0 0 auto;width:104px;padding:2px 8px;border-radius:999px;
  background:var(--cat-wash);color:var(--cat-ink);border:1px solid var(--cat-line);
  font-size:var(--fs-micro);font-weight:700;white-space:nowrap;text-align:center;
  overflow:hidden;text-overflow:ellipsis;box-sizing:border-box;
  font-family:inherit;line-height:1.6}
/* It is a button, so it says so on approach — but only on approach: a row of
   pills that all look pressable at rest reads as a toolbar, not as data. */
button.cd-file-cat{cursor:pointer;transition:background .12s,border-color .12s}
button.cd-file-cat:hover{background:var(--cat-ink);color:var(--cat-on);
  border-color:var(--cat-ink)}
.cd-file-n{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:var(--fs-cap);font-family:var(--mono, ui-monospace, Menlo, monospace)}
.cd-file-more{flex:0 0 auto;padding:0 7px;line-height:1}
/* The grip LEADS the row and stays quiet until the row is touched — a column
   of permanent handles is a column of furniture, but one hiding beside the ⋯
   put "move this" next to "delete this", and a mis-hit there is expensive.
   Negative margin so it hangs in the gutter: the bubbles below still line up
   with each other, which is the whole reason they are one width. */
.cd-file-grip{flex:0 0 auto;display:inline-flex;align-items:center;color:var(--ink-4);
  cursor:grab;opacity:.35;transition:opacity .12s;margin-left:calc(var(--sp-4) * -1)}
.cd-file:hover .cd-file-grip{opacity:.9}
.cd-file-grip:active{cursor:grabbing}
.cd-files{margin-bottom:var(--sp-5)}

/* The (i) beside a section heading. Small, low-contrast, and only ever a
   question — it explains, it never changes anything. */
.cd-info{margin-left:6px;padding:0;border:0;background:none;color:var(--ink-4);
  cursor:pointer;display:inline-flex;align-items:center;vertical-align:-2px}
.cd-info:hover{color:var(--ac-ink)}
.cd-conv{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--sp-5) var(--sp-6);font-size:var(--fs-cap);overflow-x:auto;white-space:pre;
  font-family:var(--mono, ui-monospace, Menlo, monospace);margin:0 0 var(--sp-6)}
.cd-conv-rules{margin:0 0 var(--sp-6);padding-left:1.2em;font-size:var(--fs-ui);line-height:1.65}
.cd-conv-rules code{background:var(--surface-2);border-radius:3px;padding:0 4px;
  font-size:var(--fs-micro)}

/* The sandboxed preview frame. Tall enough to be a preview rather than a
   letterbox, and it owns its own scrolling. */
.file-frame{width:100%;height:min(62vh, 560px);border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--panel)}

/* THE FULL TEXT, READ IN PLACE. Taller than the file preview beside it and
   flush to the dialog's edges — a paper is read a page at a time, so the
   viewer wants every pixel the modal has rather than sitting in a card with
   air around it. The dialog clears its own padding for this one. */
.pdf-frame{display:block;width:100%;height:min(78vh, 900px);border:0;
  background:var(--panel)}

/* ==== THE SMALL RICH-TEXT BOX ==========================================
   Its toolbar is the server's allowlist and nothing more, so every button
   here produces something that survives to the email. */
.richbox{border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--panel);overflow:hidden}
.richbox-bar{display:flex;gap:2px;padding:4px;border-bottom:1px solid var(--line-2);
  background:var(--surface-2)}
.richbtn{min-width:26px;height:24px;padding:0 6px;border:1px solid transparent;
  border-radius:var(--radius-sm);background:none;color:var(--ink-2);cursor:pointer;
  font:inherit;font-size:var(--fs-cap);line-height:1}
.richbtn:hover{background:var(--surface-3);border-color:var(--line);color:var(--ink)}
.richbox-in{min-height:96px;max-height:260px;overflow:auto;padding:var(--sp-6);
  font-size:var(--fs-ui);line-height:1.6;color:var(--ink);outline:none}
.richbox-in:empty::before{content:attr(data-ph);color:var(--ink-4)}
.richbox-in p{margin:0 0 var(--sp-5)}
.richbox-in p:last-child{margin-bottom:0}
.richbox-in ul,.richbox-in ol{margin:0 0 var(--sp-5);padding-left:1.4em}
.richbox-in a{color:var(--ac-ink)}

/* ==== APPEARANCE IN THE ACCOUNT CORNER =================================
   Three states side by side rather than a switch, because "follow the device"
   is the default and has to be as reachable as the other two. Sits above the
   actions, separated by a rule: it changes how things look, not what happens. */
.hub-pop-theme{display:flex;gap:4px;padding:10px 12px;margin:0;
  border-top:1px solid var(--line-2)}
.hub-theme-b{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;
  gap:3px;padding:8px 4px;border:1px solid transparent;border-radius:var(--radius-sm);
  background:none;color:var(--ink-3);font:inherit;font-size:var(--fs-micro);
  font-weight:600;cursor:pointer;transition:background .12s,color .12s,border-color .12s}
.hub-theme-b:hover{background:var(--surface-hover);color:var(--ink)}
.hub-theme-b.on{background:var(--ac-wash);border-color:var(--ac-fill);color:var(--ac-ink)}
.hub-theme-b svg{display:block}

/* ==== WHERE A REFERENCE LIVES =========================================
   Two lines, one per axis, each naming itself. Collections and projects were
   one undifferentiated row of chips — "REACH" could be a topic or a paper and
   the chip did not say. The key column is fixed so both lines align, and only
   what the reference is actually IN is drawn: the picker behind ＋ is what
   scales to thirty of each. */
.cd-in{display:flex;align-items:flex-start;gap:var(--sp-5);margin:var(--sp-4) 0}
/* min-width:0 as well as the basis. A flex item's default min-width is
   min-content, so "COLLECTIONS" — wider than 78px at this tracking — simply
   pushed past the basis and the two keys came out different widths, which is
   the one thing a key column must not do. */
.cd-in-k{flex:0 0 92px;min-width:0;padding-top:3px;font-size:var(--fs-micro);
  text-transform:uppercase;letter-spacing:.08em;color:var(--ink-4);font-weight:700;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cd-in-chips{flex:1 1 auto;min-width:0;display:flex;flex-wrap:wrap;gap:var(--sp-3);
  align-items:center}
/* Pushed to the row's right edge and held on the first line, so it stays put
   when the chips beside it wrap onto a second. */
.cd-in-add{flex:0 0 auto;margin-left:auto;align-self:flex-start;
  padding:0 8px;line-height:1.6;font-size:14px}
/* The two axes are told apart by colour as well as by their label — blue for a
   collection, the accent for a project, matching the marks each already wears
   elsewhere in the app. */
.cd-chip{display:inline-flex;align-items:center;gap:5px;padding:2px 9px;cursor:pointer;
  border-radius:999px;font:inherit;font-size:var(--fs-micro);font-weight:700;
  max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cd-chip.is-coll{background:var(--cat-wash);color:var(--cat-ink);
  border:1px solid var(--cat-line)}
.cd-chip.is-coll:hover{background:var(--cat-ink);color:var(--cat-on);border-color:var(--cat-ink)}
.cd-chip.is-proj{background:var(--ac-wash);color:var(--ac-ink);border:1px solid var(--ac-fill)}
.cd-chip.is-proj:hover{background:var(--ac-fill);color:var(--ac-on);border-color:var(--ac-fill)}
/* A membership that comes from citing the paper is stated, not offered: no
   pointer, no hover, and a word saying why it is there. */
.cd-chip.is-cited{cursor:default;opacity:.85;background:var(--surface-3);
  color:var(--ink-3);border-color:var(--line-strong)}
.cd-chip.is-cited:hover{background:var(--surface-3);color:var(--ink-3)}
.cd-chip-x{font-weight:500;opacity:.75;font-size:var(--fs-micro)}

/* ==== TABLE NOTES ======================================================
   A journal table carries several marked notes, and the marker is the thing
   that ties one to a cell — so it leads each row, in a fixed-width box, and
   the rows line up into a column you can read down. */
.tnotes{margin:var(--sp-8) 0 var(--sp-6);padding-top:var(--sp-6);
  border-top:1px solid var(--line-2)}
.tnotes-head{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-5)}
.tnotes-head select{width:auto;flex:0 0 auto}
.tnote-row{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-4)}
.tnote-mk{flex:0 0 auto;width:30px;text-align:center;font-weight:800;
  color:var(--ac-ink);font-size:var(--fs-ui)}
.tnote-in{flex:1 1 auto;min-width:0}
/* The marker as it appears IN a cell: small, raised, and unmistakably not
   part of the number beside it. */
.mstable sup.tnote{font-size:.72em;line-height:0;vertical-align:super;
  color:var(--ac-ink);font-weight:700;padding-left:1px}
/* And as it appears in the list under the table. */
.tnote-list{display:block}
.tnote-item{margin-right:var(--sp-6);white-space:normal}
.tnote-item sup{font-weight:700;padding-right:2px}

/* ==== COLLAPSIBLE SECTIONS IN A RECORD =================================
   Tags, Notes and the two file lists fold, so a record opens as the reference
   rather than as every drawer around it. The summary is styled as the section
   heading it replaces, so folding changed the behaviour and not the look. */
.cd-fold{border-top:1px solid var(--line-2);margin-top:var(--sp-6)}
.cd-fold > summary{cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:var(--sp-4);padding:var(--sp-6) 0 var(--sp-5);
  font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.09em;
  color:var(--ink-4);font-weight:700}
.cd-fold > summary::-webkit-details-marker{display:none}
.cd-fold > summary:hover{color:var(--ink-2)}
/* The twisty is drawn, and rotates — the disclosure triangle the browser draws
   is a different shape and size in every engine. */
.cd-fold > summary::before{content:"";width:0;height:0;flex:0 0 auto;
  border-left:4.5px solid currentColor;border-top:3.5px solid transparent;
  border-bottom:3.5px solid transparent;transition:transform .12s;
  transform-origin:2px 50%}
.cd-fold[open] > summary::before{transform:rotate(90deg)}
.cd-fold-t{flex:0 0 auto}
/* The count is on the SUMMARY because it is most of the reason you would open
   it — a fold that hides how much it hides has to be opened to be read. */
.cd-fold-n{flex:0 0 auto;min-width:16px;padding:0 5px;border-radius:999px;
  background:var(--surface-3);color:var(--ink-3);font-size:var(--fs-micro);
  font-weight:700;text-align:center;letter-spacing:0}
.cd-fold summary .cd-info{margin-left:auto}
.cd-fold-b{padding-bottom:var(--sp-6)}

/* The full text's own bubble: same shape, grey. Every other bubble is a
   category chosen among several; this one is the paper itself, and there is
   only ever one — so it names the row without claiming to be a choice. */
.cd-file-cat.is-primary{background:var(--cat-grey-wash);color:var(--cat-grey-ink);
  border-color:var(--cat-grey-line)}

/* The abstract, folded and indented under the facts — it belongs to them, and
   the indent says so without a label saying it. */
.cd-abs{margin-top:var(--sp-6);padding-left:var(--sp-8);
  border-left:2px solid var(--line-2)}
.cd-abs summary{cursor:pointer;font-size:var(--fs-micro);text-transform:uppercase;
  letter-spacing:.09em;color:var(--ink-4);font-weight:700;padding:var(--sp-3) 0;
  display:flex;align-items:center;gap:var(--sp-4);list-style:none}
.cd-abs summary::-webkit-details-marker{display:none}
.cd-abs summary:hover{color:var(--ink-2)}
.cd-abs summary .hint{text-transform:none;letter-spacing:0;font-weight:400}
/* Three states, not two: filled = the text is here, hollow = never asked.
   Without the difference, "no abstract" and "not fetched" look the same and
   only one of them is worth pressing. */
.cd-dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto;
  border:1.5px solid var(--ink-4);background:transparent}
.cd-dot.on{background:var(--green, #2f8f5b);border-color:var(--green, #2f8f5b)}
.cd-abs-body{font-size:var(--fs-ui);line-height:1.65;color:var(--ink-2);
  padding-bottom:var(--sp-5)}
.cd-abs-body p{margin:0 0 var(--sp-5)}
.cd-abs-body p:last-child{margin-bottom:0}
/* A structured abstract reads as sections: the label carries the weight, its
   text is indented under it, and a small gap separates one from the next. */
.ab-h{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.07em;
  font-weight:800;color:var(--ink-2);margin:var(--sp-6) 0 2px}
.ab-h:first-child{margin-top:0}
.ab-p{margin:0 0 var(--sp-3);padding-left:var(--sp-7)}
.ab-p:last-child{margin-bottom:0}

/* The compact bucket the file sections use — same shape as the full-text one,
   less vertical weight, because a screen with three of them should not be
   three-quarters drop zone. */
.cite-drop.sm{padding:var(--sp-4) var(--sp-6);gap:var(--sp-4)}
.cite-drop.sm b{font-size:var(--fs-cap)}

/* ==== EDITOR CHROME SCALE — for eyes, not for the paper =================
   Alex, 2026-08-15: the bars you NAVIGATE by (Sections, Viewers, the pane
   headers, the rows under them) are small, and someone who cannot read them
   comfortably has no way to make them bigger — while the document text itself
   already has its own controls (Appearance's Comfort view, --srf-scale).

   So this multiplier is scoped to the editor's FURNITURE and must never reach
   the writing surface. Two fences, deliberately:

     1. It is declared on `.ed` — the three-column editor frame — so it cannot
        touch the app rail, the topbar, the hub, or any other screen. The left
        sidebar is explicitly out of scope ("not the left side bar").
     2. Nothing under `.sheet`, `.blk .bd` or the export surface reads
        --ed-ui. The paper renders at the size the paper is; a person who
        scaled their menus must not discover their manuscript reflowed, and a
        setting that changed both would be unusable for the one job this app
        has. The document's own size lives in the --srf-*/--doc-* regimes and
        stays there.

   Comments DO scale, because a comment is something you read in the margin
   rather than text you are setting. */
.ed{--ed-ui:1}
:root[data-edscale="medium"] .ed{--ed-ui:1.12}
:root[data-edscale="large"] .ed{--ed-ui:1.28}
:root[data-edscale="xlarge"] .ed{--ed-ui:1.5}

/* The rows under Sections, and the pane furniture. Sized off --ed-ui so one
   setting moves the whole navigable surface together. */
.ed .out-row{font-size:calc(var(--fs-sm) * var(--ed-ui))}
.ed .out-row .n{font-size:calc(var(--fs-ui) * var(--ed-ui));
  width:calc(20px * var(--ed-ui))}
.ed .out-row .wc{font-size:calc(var(--fs-cap) * var(--ed-ui))}
.ed .pane-bar{font-size:calc(var(--fs-cap) * var(--ed-ui))}
.ed .pane-bar select,.ed .pane-bar .btn{font-size:calc(var(--fs-cap) * var(--ed-ui))}
/* Comments and the other pane bodies — read in the margin, not typeset. */
.ed .cmt-item,.ed .cmt-text,.ed .cmt-who,.ed .chg-item,.ed .lint-item{
  font-size:calc(var(--fs-sm) * var(--ed-ui))}

/* The header row the chevron and "Sections" share. Same vertical rhythm as
   .pane-head opposite it, so the two columns' titles sit on one line across
   the whole editor. */
.outline-head{flex:0 0 auto;display:flex;align-items:center;gap:var(--sp-3);
  padding:var(--sp-4) var(--sp-5)}
/* The body no longer pays a 34px left inset to clear an absolutely-positioned
   chevron — the chevron is in the header now, so the rows come back in to a
   normal gutter (Alex: "decrease the indent... its too far in"). */
.ed-outline .outline-body{padding:0 var(--sp-5) var(--sp-6)}
/* Captions that SORT the outline's lower half: what you set up, where you go.
   Muted and small — they name shelves, they are not rows. */
.out-grp{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-3);margin:10px 2px 2px}
/* A heading kept for organising but absent from the output: legible, editable,
   and visibly not quite part of the paper. */
.sh-title.sh-hidden{opacity:.55;text-decoration:underline dashed;text-underline-offset:4px}
/* THE WRITING COLUMN, which is now a column: the screen, then the notes pane
   docked under it. .ed-main keeps `flex:1 1 auto` so it still takes the space
   left over — the difference is that the space left over is now vertical. */
.ed-mid{flex:1 1 auto;display:flex;flex-direction:column;min-width:0;min-height:0}
.ed-main{flex:1 1 auto;overflow:auto;min-width:0;min-height:0}

/* The dialog says which method it opened on, and offers the way back to the
   picker — a form that changed shape with no label would leave you working out
   what you had chosen from the shape of the blanks. */
.cg-method{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-5);
  padding-bottom:var(--sp-4);border-bottom:1px solid var(--line-2);
  font-size:var(--fs-cap);letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3)}
.cg-method .btn{margin-left:auto;text-transform:none;letter-spacing:0}

/* An affiliation and, pushed to the far right of the same line, the address of
   whoever corresponds from it. `gap` keeps them apart when the line is short;
   `margin-left:auto` keeps the address right when it is not. */
.mast-aff{display:flex;align-items:baseline;gap:var(--sp-8);justify-content:space-between}
.mast-mail{margin-left:auto;white-space:nowrap;color:var(--ink-3)}

/* The approval form's own sub-heading, and its fields in rows that wrap. */
.shv-sub{font-size:var(--fs-cap);letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3);font-weight:700;margin:12px 0 6px}
.shv-fields{display:flex;flex-wrap:wrap;gap:var(--sp-5)}
.shv-fields .fld{flex:1 1 180px;min-width:0}

/* What they sent back, against what the paper says. The two values sit either
   side of an arrow so the direction of the change is the thing you read first. */
.rec-p{border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 12px;
  margin:0 0 10px;background:var(--surface-2)}
.rec-row{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;
  padding:6px 0;border-top:1px solid var(--line-2)}
.rec-k{flex:0 0 96px;font-size:var(--fs-cap);text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-3);font-weight:700}
.rec-mine{color:var(--ink-3);text-decoration:line-through}
.rec-arrow{color:var(--ink-4)}
.rec-theirs{color:var(--ink);font-weight:600}
.rec-row .btn{margin-left:auto}

.ft-row{display:flex;align-items:flex-start;gap:var(--sp-5);padding:8px 0;
  border-bottom:1px solid var(--line-2)}
.ft-row:last-child{border-bottom:0}
.ft-cite{flex:1 1 auto;min-width:0;font-size:var(--fs-ui);line-height:1.5}
.ft-row .btn{flex:0 0 auto}

.by-who{margin:6px 0 12px;padding-left:20px;color:var(--ink)}
.by-who li{margin:2px 0}

/* ------------------------------------------ the standing rounds record -- */
.rt-round{border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:10px 12px;margin:0 0 10px;background:var(--surface-2)}
.rt-head{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;margin-bottom:8px}
/* Full width so it sits under the row rather than squeezing into it. */
.rt-fin{flex:1 1 100%;font-size:var(--fs-cap);color:var(--ink-3)}
table.rt{width:100%;border-collapse:collapse;font-size:var(--fs-ui)}
table.rt th{text-align:left;font-size:var(--fs-cap);text-transform:uppercase;
  letter-spacing:.06em;color:var(--ink-3);font-weight:700;padding:4px 10px 4px 0;
  white-space:nowrap;border-bottom:1px solid var(--line-2)}
table.rt td{padding:6px 10px 6px 0;border-bottom:1px solid var(--line-2);vertical-align:top}
table.rt tr:last-child td{border-bottom:0}
/* Green for done and a grey dash for not-yet: the dash is the point — an empty
   cell reads as a rendering fault, "not yet" is a fact. */
.rt-yes{color:var(--green);font-weight:700}
.rt-no{color:var(--ink-4)}

/* --------------------------------------------- what came back in a round -- */
.rr-reply{border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:8px 10px;margin:6px 0;background:var(--surface-2)}
.rr-reply-head{font-size:var(--fs-ui);margin-bottom:4px}
.rr-note{margin:6px 0 0;padding-left:9px;border-left:2px solid var(--line-2)}
/* The reader's quotation of the paper, not their words — set apart so the two
   can never be misread as one sentence. */
.rr-quote{font-size:var(--fs-cap);color:var(--ink-3);font-style:italic;
  margin-bottom:2px}
.rr-said{font-size:var(--fs-ui);color:var(--ink);white-space:pre-wrap}

/* ------------------------------------------------------------ notes pane -- */
/* Shut, it is a bar with a centred chevron and the word Notes. Open, it holds
   one or two writing boxes and can be dragged taller by its top edge. */
.ed-notes{flex:0 0 auto;display:flex;flex-direction:column;min-height:0;
  height:var(--notes-h,240px);border-top:1px solid var(--line);background:var(--surface-2)}
.ed-notes.shut{height:auto}
.notes-grip{flex:0 0 5px;cursor:row-resize;position:relative}
.ed-notes.shut .notes-grip{display:none}
.notes-grip::after{content:"";position:absolute;inset:2px 0;background:var(--line);
  opacity:0;transition:opacity .12s}
.notes-grip:hover::after{opacity:1}
body.rowresizing{cursor:row-resize;user-select:none}
/* Three columns so the chevron is centred on the PANE, not on whatever happens
   to be beside it — a chevron that drifts when the button label changes from
   "Two panes" to "One pane" reads as a different control. */
.notes-bar{flex:0 0 auto;display:grid;grid-template-columns:1fr auto 1fr;
  align-items:center;gap:var(--sp-2);padding:5px var(--sp-3);cursor:pointer;
  user-select:none}
.notes-bar:hover{background:var(--surface-hover)}
/* Sized off --ed-ui like the rest of the editor's furniture: this pane is
   chrome, and a person who set the panels to Extra large because the outline
   was too small to read did not mean "except the notes". */
.notes-name{font-size:calc(var(--fs-cap) * var(--ed-ui, 1));letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-3);white-space:nowrap}
.notes-chev{justify-self:center;display:flex;color:var(--ink-3);transition:transform .15s}
.notes-chev svg{width:calc(14px * var(--ed-ui, 1));height:calc(14px * var(--ed-ui, 1))}
.notes-tools .btn{font-size:calc(var(--fs-cap) * var(--ed-ui, 1))}
/* The notes themselves are WRITING, not chrome — but they are the person's own
   writing, not the manuscript's, so they follow the panel scale rather than the
   document's point size. */
.notes-half .richbox-in{font-size:calc(var(--fs-ui) * var(--ed-ui, 1))}
.notes-half .richbtn{font-size:calc(var(--fs-cap) * var(--ed-ui, 1));
  min-width:calc(26px * var(--ed-ui, 1));height:calc(24px * var(--ed-ui, 1))}
.ed-notes:not(.shut) .notes-chev{transform:rotate(180deg)}
.notes-tools{justify-self:end}
.ed-notes.shut .notes-tools{visibility:hidden}
.notes-body{flex:1 1 auto;display:flex;gap:var(--sp-3);min-height:0;
  padding:0 var(--sp-3) var(--sp-3)}
.ed-notes.shut .notes-body{display:none}
.notes-half{flex:1 1 0;min-width:0;display:flex}
/* The boxes fill the pane instead of the 96–260px they take in a dialog: here
   the height is the person's, set by dragging, not the content's. */
.notes-half .richbox{flex:1 1 auto;display:flex;flex-direction:column;min-height:0}
.notes-half .richbox-in{flex:1 1 auto;min-height:0;max-height:none;overflow:auto}
.notes-right{display:none}
.ed-notes.split .notes-right{display:flex}

/* ON A PHONE THERE IS ONE PANE, whatever the preference says. Split at 375px
   leaves two 174px columns, which is not two places to think — it is one
   unusable one twice. The stored preference is untouched, so the same account
   still opens two panes on the desktop; it simply does not apply at a width
   that cannot hold them, and the button that would promise it is hidden rather
   than left offering something that will not happen.

   The height is capped against the VIEWPORT too: 240px out of an 812px phone
   left the manuscript 406px, and the pane exists to serve the writing, not to
   crowd it. dvh rather than vh for the reason the modal learned the hard way —
   iOS counts the toolbars it is currently showing. */
@media (max-width:760px){
  .ed-notes.split .notes-right{display:none}
  .notes-tools{display:none}
  .ed-notes{max-height:38vh;max-height:38dvh}
  .notes-grip{display:none}
}
/* WIDTH IS NOT ANIMATED WHILE YOU DRAG IT. A transition on `width` meant every
   pointermove was chasing a 140ms animation, so the edge lagged the cursor —
   and it made the width untestable in an automated browser, where transition
   clocks are frozen and the property therefore never leaves its start value at
   all. The animation is worth keeping for the one case it was written for: the
   collapse chevron, where the pane jumps between 34px and its full width. So it
   is scoped to that — a class the collapse toggles — and a drag moves the edge
   with the pointer, which is what a drag is. */
.ed-side{width:340px;flex:0 0 auto;border-left:1px solid var(--line);background:var(--surface-2);
  display:none;flex-direction:column;min-width:240px;overflow:hidden;position:relative}
.ed-side.animate{transition:width .14s ease}
.ed.show-side .ed-side{display:flex}
/* THE COLUMN SITS SQUARE IN ITS PANE. It had 34px on the left and nothing on
   the right — the gutter that keeps content clear of the collapse chevron was
   being paid for down the whole column, so every card sat shoved right with its
   edge against the window (Alex, on iPad: "too much padding on left and not
   enough on right"). The chevron is at the TOP of the gutter, so only the top
   needs to clear it: the body keeps a modest, equal margin and the pane head
   keeps the full 34px. */
.ed-side .ed-side-body{display:flex;flex-direction:column;min-height:0;flex:1 1 auto;
  padding-left:12px;padding-right:12px;min-width:0}
.ed-side .pane-head{padding-left:34px}

/* FIVE PIXELS WAS A DARE. The rule stays thin and the grabbable area is three
   times it — the same trick .pane-grip already uses between the stacked panes,
   where it was got right first. Negative margin so widening the target does not
   move the columns apart. */
.ed-grip{flex:0 0 15px;margin:0 -5px;cursor:col-resize;background:transparent;
  position:relative;z-index:5}
.ed-grip::after{content:"";position:absolute;inset:0 6px;background:var(--line);
  opacity:0;transition:opacity .12s}
.ed-grip:hover::after{opacity:1}
/* While dragging, the whole window keeps the cursor — otherwise it flickers
   back to a caret the moment the pointer outruns the 15px strip. */
body.colresizing{cursor:col-resize;user-select:none}
/* THE ADD-COMMENT BUTTON. Sized to be pressed, not stretched across the pane:
   a control that spans the full width under the pane's own dropdown row reads
   as a continuation of that row. Air above separates the two. The colours are
   Alex's (2026-08-17) and are literal hex on purpose — they are brand values
   picked against the sketch, not theme tokens, and must not drift when a theme
   changes underneath them. */
/* The manuscript's own id, on the screen that exists to answer "what happened
   to this document" — and copyable, because it is only useful transcribed. */
/* The rounds/stages/versions explainer: a definition list, because that is what
   it is — five words and what each one means. */
.rmap{display:flex;flex-direction:column;gap:var(--sp-5)}
.rmap-row{display:grid;grid-template-columns:130px 1fr;gap:var(--sp-6);align-items:start}
.rmap-k{font-size:var(--fs-cap);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700;padding-top:2px}
.rmap-v{font-size:var(--fs-sm);color:var(--ink-2);line-height:1.55}
@media (max-width:760px){ .rmap-row{grid-template-columns:1fr;gap:2px} }

/* ============ NOTHING SPILLS OUT OF THE WRITING COLUMN =====================

   Alex, 2026-08-17: "items and buttons still cross over past where they
   should … at a certain point you should just make them disappear."

   Three rules, in order of how much they give up. First nothing is allowed to
   push the column wider than it is — a flex or grid child defaults to a minimum
   size of its CONTENT, which is what lets a long button or a wide table shove
   the whole card out of view; min-width:0 is the fix and it costs nothing.
   Second, anything that is genuinely wider than the space — a table — scrolls
   inside its own box rather than taking the page with it. Only then, and only
   below 560px, do things start to go: the captions on the stage readings, the
   secondary buttons, the columns of a roster that are not the person's name. */
.ed-main,.ed-main .page,.ed-main .card,.ed-main .card-head,.ed-main .card-body{min-width:0}
.ed-main .card-head{flex-wrap:wrap;row-gap:var(--sp-4)}
.ed-main .btn{max-width:100%;overflow:hidden;text-overflow:ellipsis}
/* A table is the one thing allowed to be wider than the column, inside its own
   scroller. .tw already wraps them; this makes the wrapper do its job. */
.ed-main .tw{max-width:100%;overflow-x:auto}
.ed-main table{max-width:none}

.mid-narrow .stg-k{display:none}
.mid-narrow .stg-head{gap:var(--sp-4)}
.mid-narrow .stg-pair{flex-direction:row;align-items:baseline;gap:4px}
/* Full width and stacked: two half-width buttons side by side in 400px are two
   buttons nobody can read the labels of. */
.mid-narrow .card-head .btn{width:100%}
.mid-narrow .card-head .spacer{display:none}
/* The roster keeps who and what; when they answered is a column you can lose
   before you lose their name. */
.mid-narrow table.rt th:nth-child(n+3),
.mid-narrow table.rt td:nth-child(n+3){display:none}
.mid-narrow .rmap-row{grid-template-columns:1fr;gap:2px}

/* THE STAGE HEAD: caption above value, so a long round label cannot balloon a
   rounded tag into a three-line circle. */
.stg-head{flex-wrap:wrap;row-gap:var(--sp-4)}
.stg-pair{display:flex;flex-direction:column;gap:1px;min-width:0;flex:0 0 auto}
.stg-k{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-4);font-weight:700;white-space:nowrap}
.stg-v{font-size:var(--fs-ui);font-weight:660;color:var(--ink);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
@media (max-width:900px){
  /* On an iPad the buttons take their own line rather than squeezing the two
     readings into nothing. */
  .stg-head .spacer{flex-basis:100%;height:0}
  .stg-v{font-size:var(--fs-sm)}
}

.aud-id{display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap;
  margin:0 0 var(--sp-5);padding:8px 10px;border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--surface-2)}
.aud-id-k{font-size:var(--fs-cap);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700}
.aud-id-v{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:var(--fs-sm);background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius-sm);padding:2px 8px;cursor:pointer;color:var(--ink)}
.aud-id-v:hover{border-color:var(--blue);color:var(--ac-ink)}

.cmt-addwrap{padding:14px 12px 10px;display:flex}
.cmt-add{display:inline-flex;align-items:center;gap:8px;min-height:38px;
  padding:8px 16px;white-space:nowrap;
  background:#e9edf1;border:1.5px solid #2f5686;color:#1e3a5c;font-weight:600;
  border-radius:var(--radius-sm)}
.cmt-add:hover{background:#dde4ec;border-color:#24456d}
.cmt-add img{width:20px;height:20px;flex:0 0 auto;object-fit:contain}
/* In a dark theme the sketch is near-black on a light chip, which is right —
   the chip keeps its own light background, so the mark stays legible. */

/* ---- the authors block: folds, and fits a phone ---- */
/* The head is the control, like every other card on this screen. */
.au-head{cursor:pointer;user-select:none}
.au-head:hover{background:var(--surface-hover)}
.au-head .btn{cursor:pointer}
.au-card.shut .card-body{display:none}
.au-count{flex:0 0 auto;font-size:var(--fs-cap);font-weight:700;color:var(--ink-3);
  background:var(--surface-2);border:1px solid var(--line);border-radius:999px;padding:0 8px}
/* Shut, the head is a summary — the six controls belong to the open list. */
.au-card.shut .au-2nd,.au-card.shut .au-more{display:none}
.au-more{display:none}
@media (max-width:760px){
  /* One primary action and an overflow, instead of six buttons in three ragged
     rows of different widths. */
  .au-2nd{display:none}
  .au-more{display:inline-flex}
  .au-head h3{font-size:var(--fs-ui)}
}
body.colresizing *{cursor:col-resize!important}

/* A NARROW PANE HIDES THE WORDS AND KEEPS THE CONTROLS. Below ~300px the head
   was a truncated title fighting three buttons and a select for the same row,
   which left every one of them unusable. The title is the first thing that can
   go: the pane's contents say what it is. */
.ed-side.narrow .pane-title{display:none}
.ed-side.narrow .pane-head{padding-left:34px;padding-right:6px;gap:4px}
.ed-side.narrow .pane-head select{min-width:0;flex:1 1 auto;width:auto}
.ed-side.narrow .cmt{padding:8px}
.ed-side.narrow .ed-side-body{padding-left:8px;padding-right:8px}

/* ==== Outline / viewer collapse — a narrow permanent strip, not width:0 =====
   Alex, 2026-08-15: "default open... without any auto hide/open functions...
   or at least shrink that down to a very small vertical pane" for the section
   outline, and the same for the viewer column so it can give the editor its
   width back. Both chevrons live OUTSIDE the collapsible body they control
   (.outline-body / .ed-side-body), absolutely positioned at the top of a
   fixed 34px gutter that is there whether open or shut — so the button that
   closed the panel is always exactly where the button that reopens it will
   be, never a floating control to go hunting for.

   `!important` on .ed-side's collapsed width is deliberate: #edSide carries
   an INLINE width (the drag-resize handle in js/screens.js writes
   `style.width` directly, and the initial render sets one too), and an inline
   style outranks a plain class selector — without it the collapse class would
   be silently overridden by whatever width the panel happened to be dragged
   to before it was shut. */
.ed-outline-tog,.ed-side-tog{flex:0 0 auto;
  width:calc(22px * var(--ed-ui, 1));height:calc(22px * var(--ed-ui, 1));
  padding:0;border:0;border-radius:var(--radius-sm);
  background:none;color:var(--ink-3);cursor:pointer;display:grid;place-items:center;
  transition:transform .14s ease}
.ed-outline-tog svg,.ed-side-tog svg{width:calc(14px * var(--ed-ui, 1));height:calc(14px * var(--ed-ui, 1))}
.ed-outline-tog:hover,.ed-side-tog:hover{background:var(--surface-hover);color:var(--ink)}
.ed.outline-shut .ed-outline{width:34px}
.ed.outline-shut .ed-outline .outline-body,
.ed.outline-shut .outline-head .pane-title{display:none}
.ed.outline-shut .outline-head{padding-left:6px;padding-right:6px}
.ed.outline-shut .ed-outline-tog{transform:rotate(180deg)}
.ed.side-shut .ed-side{width:34px!important;min-width:34px}
.ed.side-shut .ed-side .ed-side-body,
.ed.side-shut .pane-head .pane-title,
.ed.side-shut .pane-head .btn{display:none}
.ed.side-shut .pane-head{padding-left:6px;padding-right:6px;border-bottom:0}
.ed.side-shut .pane-head::after{display:none}
.ed.side-shut .ed-side-tog{transform:rotate(180deg)}
/* A grip that resizes a 34px strip looks broken — the strip is not meant to
   be dragged, only reopened. */
.ed.side-shut .ed-grip{pointer-events:none;opacity:.3}

@media (max-width:640px){.ed-outline{display:none}}
@media (max-width:900px){.ed-side,.ed-grip{display:none !important}}

/* ---------- Pane stack ---------------------------------------------------
   One editor in the centre, N read-only viewers on the right. Each pane owns
   its own scroll, so reading Methods in one pane never moves Table 2 in
   another. Panes are viewers by construction: a second editable surface over
   the same blocks would put two carets on one paragraph. */
.pane-head{flex:0 0 auto;display:flex;align-items:center;gap:var(--sp-4);
  padding:var(--sp-4) var(--sp-6);border-bottom:1px solid var(--line);background:var(--surface-2)}
/* Sized from --ed-ui (below), not a fixed token: these headings are chrome a
   person NAVIGATES rather than text they edit, and at --fs-micro they were
   10px of tracked-out capitals (Alex, 2026-08-15: "increase the font size").
   min-width:0 so a long word truncates instead of shoving the ＋ off the row. */
.pane-title{font-size:calc(var(--fs-sm) * var(--ed-ui, 1));text-transform:uppercase;
  letter-spacing:.07em;color:var(--ink-3);font-weight:700;flex:1 1 auto;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pane-stack{flex:1 1 auto;display:flex;flex-direction:column;overflow:hidden;min-height:0}
.pane{flex:1 1 0;display:flex;flex-direction:column;min-height:0;
  border-bottom:1px solid var(--line)}
.pane:last-child{border-bottom:0}
.pane[data-collapsed]{flex:0 0 auto}
/* THE HANDLE BETWEEN TWO PANES. Four pixels of visible rule, ten of grab —
   a 1px target is a dare, and the hit area is padding so the rule does not
   move when it grows. */
.pane-grip{flex:0 0 auto;height:9px;margin:-4px 0;position:relative;z-index:1;
  cursor:row-resize;touch-action:none}
.pane-grip::after{content:'';position:absolute;left:0;right:0;top:4px;height:1px;
  background:var(--line);transition:background .12s ease}
.pane-grip:hover::after{background:var(--ac-edge);height:2px}
/* While dragging, nothing else on the page should select or take the cursor. */
body.row-resizing{cursor:row-resize;user-select:none}
body.row-resizing *{pointer-events:none}
body.row-resizing .pane-grip{pointer-events:auto}
.pane[data-collapsed] .pane-body{display:none}
.pane-bar{flex:0 0 auto;display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-4);background:var(--surface-3);border-bottom:1px solid var(--line-2)}
/* A REAL TARGET, NOT THREE GREY PIXELS. 18px wide holding a text triangle made
   the fold control the hardest thing on the pane to see or hit. 22px square with
   a drawn 14px chevron that ROTATES — same shape open or closed, at a weight
   that survives a Retina panel. */
.pane-fold{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;padding:0;border:0;border-radius:var(--radius-sm);
  background:none;color:var(--ink-3);cursor:pointer}
.pane-fold svg{width:14px;height:14px;display:block;transition:transform .14s ease}
.pane-fold.open svg{transform:rotate(90deg)}
.pane-fold:hover{background:var(--surface-hover);color:var(--ink-2)}
.pane-pick{flex:1 1 auto;min-width:0;font-size:var(--fs-sm);padding:2px 6px;
  border-color:var(--line-strong);background:var(--panel)}
.pane-body{flex:1 1 auto;overflow:auto;min-height:0}
/* The Word preview SPANS its pane: the body becomes a column, the iframe box
   takes the slack, and the iframe's height:100% finally has a height to be
   100% OF. With one pane open that is the whole viewer column. */
.pane-t-docx .pane-body{display:flex;flex-direction:column;overflow:hidden}
.pane-t-docx [data-panedocx]{flex:1 1 auto;min-height:0;display:flex}
.pane-t-docx [data-panedocx] iframe{flex:1 1 auto;min-height:0}
.pv{padding:var(--sp-6) var(--sp-8);font-family:var(--doc-font);font-size:14px;line-height:1.6}
.pv-p{margin:0 0 var(--sp-6)}
.pv-h2{font-family:var(--ui-font);font-size:14px;font-weight:680;margin:var(--sp-8) 0 var(--sp-3)}
.pv-h3{font-family:var(--ui-font);font-size:12px;font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;color:var(--ink-2);margin:var(--sp-7) 0 var(--sp-2)}
.pv-meta{padding:var(--sp-4) var(--sp-8);font-size:var(--fs-cap);color:var(--ink-3);
  border-bottom:1px solid var(--line-2);background:var(--surface-2)}
.pane-body .tblbox{margin:var(--sp-6) var(--sp-6) 0}
.pane-body .figbox{margin:var(--sp-6)}
.pane-body .cap{padding:0 var(--sp-8) var(--sp-6)}

.out-row{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-4) var(--sp-5);
  border-radius:var(--radius-sm);cursor:pointer;font-size:var(--fs-sm);color:var(--ink-2);user-select:none}
.out-row:hover{background:var(--surface-hover)}
.out-row.sel{background:var(--surface-sel);color:var(--ac-ink);font-weight:640}
.out-row .n{width:20px;text-align:right;color:var(--ink-3);font-size:var(--fs-ui);flex:0 0 auto}
.out-row .lbl{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.out-row .wc{font-size:var(--fs-micro);color:var(--ink-4);flex:0 0 auto}
.out-row .wc.over{color:var(--red);font-weight:700}
/* THE WIDTH IS RESERVED WHETHER OR NOT THE + IS SHOWING. An in-flow button that
   appears on hover shifts the label and the word count sideways under the
   pointer — the defect .nav-more papers over by dimming instead. Here the slot
   is always there and only the ink changes, so nothing moves. */
.out-add{flex:0 0 auto;width:22px;height:22px;padding:0;border:0;background:none;
  border-radius:var(--radius-sm);cursor:pointer;line-height:1;
  color:var(--ink-4);font-size:var(--fs-ui);transition:color .12s ease,background .12s ease}
.out-row:hover .out-add{color:var(--ink-3)}
.out-add:hover{background:var(--ac-wash);color:var(--ac-ink)}
/* Keyboard reach: focus must show it even when the row is not hovered, or the
   control exists for a mouse only. */
.out-add:focus-visible{color:var(--ac-ink);outline:2px solid var(--ac-edge);outline-offset:1px}
/* A finger has no hover, so on touch it is simply always visible. */
@media (hover:none) and (pointer:coarse){ .out-add{color:var(--ink-4)} }
.out-row.drag{opacity:.45}
.out-row.drop-before{box-shadow:inset 0 2px 0 var(--blue)}
.out-row.drop-after{box-shadow:inset 0 -2px 0 var(--blue)}

/* The paper. A manuscript section is a sheet, not a form field. */
/* The writing surface runs the full width between the outline and the viewers,
   with only a hair of separation — the measure is controlled by the sheet's own
   generous side padding rather than by a narrow column. */
.sheetwrap{padding:4px 4px 40vh;display:flex;flex-direction:column;align-items:stretch}
.sheetbox{width:100%;display:flex;flex-direction:column;margin-bottom:var(--sp-6)}
.sheet{background:var(--paper);color:var(--paper-ink);border:1px solid var(--paper-line);
  border-radius:8px;box-shadow:0 1px 3px var(--paper-shadow);width:100%;
  padding:var(--sp-16) 56px var(--sp-16)}
.sheet.narrow{width:100%}
/* Justified body text. The alignment lives on the block MODEL and this class
   is applied at render — never written into the stored HTML, which the
   sanitiser would strip. */
.bd.just{text-align:justify;text-justify:inter-word}

/* The citations for this section, in their own bubble UNDER the sheet — the
   footnote strip you glance at while writing. Never the document's own
   typography: it is apparatus, not text on the page, and it must not read as
   part of the manuscript. Open by default, because the whole point is not
   having to go and ask for it. */
.citefoot{margin-top:6px;background:var(--surface-2);border:1px solid var(--line);
  border-radius:10px;padding:0 var(--sp-8) var(--sp-2);
  font-family:var(--ui-font);font-size:var(--fs-sm)}
.cf-head{display:flex;align-items:center;gap:var(--sp-4);width:100%;background:none;border:0;
  padding:var(--sp-6) 0 var(--sp-4);cursor:pointer;color:var(--ink-3);
  font:inherit;font-weight:650;text-align:left}
.citefoot:not(.closed) .cf-head{border-bottom:1px solid var(--line-2)}
.cf-head:hover{color:var(--ink-2)}
/* Same family as every other fold: drawn, rotating, and big enough to see. */
.cf-caret{flex:0 0 auto;width:16px;height:16px;display:inline-flex;align-items:center;
  justify-content:center;color:var(--ink-4)}
.cf-caret svg{width:13px;height:13px;display:block;transition:transform .14s ease}
.cf-caret.open svg{transform:rotate(90deg)}
.cf-count{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--ink-4);font-weight:600}
.cf-list{padding-bottom:var(--sp-4)}
.cf-row{display:flex;gap:var(--sp-5);align-items:flex-start;padding:var(--sp-3) 0;
  line-height:1.45;color:var(--ink-2)}
.cf-row + .cf-row{border-top:1px solid var(--line-2)}
.cf-n{flex:0 0 22px;text-align:right;font-variant-numeric:tabular-nums;font-weight:700;
  color:var(--ink-3)}
.cf-t{flex:1 1 auto;min-width:0}
.cf-row .btn{flex:0 0 auto;opacity:0;padding:0 5px}
.cf-row:hover .btn,.cf-row:focus-within .btn{opacity:1}
.cf-missing .cf-t{color:var(--red)}

/* The cite-a-reference picker: one search box over this paper, your library
   and a bare DOI/PMID. Keyboard-first, so the selected row is a real state
   and not just a hover. */
.pc-list{max-height:46vh;overflow:auto;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2)}
.pc-row{display:flex;gap:var(--sp-5);align-items:flex-start;width:100%;text-align:left;
  background:none;border:0;border-bottom:1px solid var(--line-2);padding:var(--sp-5) var(--sp-6);
  cursor:pointer;font:inherit;font-size:var(--fs-sm);color:var(--ink-2);line-height:1.45}
.pc-row:last-child{border-bottom:0}
.pc-row:hover{background:var(--surface-hover)}
.pc-row.on{background:var(--surface-sel);color:var(--ink)}
.pc-n{flex:0 0 26px;text-align:right;font-variant-numeric:tabular-nums;font-weight:700;
  color:var(--ink-3)}
.pc-tag{flex:0 0 auto;font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.07em;
  font-weight:700;color:var(--ink-4);border:1px solid var(--line);border-radius:999px;
  padding:1px 6px;margin-top:1px}
.pc-tag.pc-new{color:var(--ac-ink);border-color:var(--ac-fill)}
.pc-t{flex:1 1 auto;min-width:0}

/* ---------- Conference abstracts ---------------------------------------- */
/* Everything that governs an abstract — the meeting, the deadline, the limit
   and how much of it is spent — sits on the page you are typing on. The
   number is the whole job, so it is never behind a menu. */
.abs-wrap{height:100%;overflow:auto}
.abs-main{max-width:900px;margin:0 auto;padding:var(--sp-10) var(--sp-12) 60px}
.abs-head .card-body{padding-bottom:var(--sp-6)}
.abs-meter{display:flex;align-items:center;gap:var(--sp-6);margin-top:var(--sp-4)}
.abs-bar{flex:1 1 auto;height:6px;border-radius:999px;background:var(--line-2);overflow:hidden}
.abs-bar-fill{height:100%;width:0;background:var(--ink-4);border-radius:999px;
  transition:width .15s ease}
.abs-bar-fill.good{background:var(--green)}
.abs-bar-fill.warn{background:var(--amber)}
.abs-bar-fill.bad{background:var(--red)}
.abs-count{flex:0 0 auto;font-size:var(--fs-ui);color:var(--ink-3);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.abs-count b{color:var(--ink);font-weight:700}
.abs-count.bad,.abs-count.bad b{color:var(--red)}
.abs-count.warn b{color:var(--amber)}
.abs-over{color:var(--red);font-weight:700}
.abs-left{color:var(--ink-4)}
/* The sheet inside an abstract is short: no page furniture, just the text. */
.abs-main .sheet{width:100%;padding:var(--sp-12) var(--sp-16)}
.sh-head{display:flex;align-items:baseline;gap:var(--sp-6);border-bottom:1px solid var(--paper-rule);
  padding-bottom:var(--sp-6);margin-bottom:var(--sp-10)}
.sh-kind{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-4);font-weight:700}
.sh-title{font-size:19px;font-weight:680;font-family:var(--ui-font);letter-spacing:-.015em;flex:1 1 auto}
.sh-count{font-size:var(--fs-cap);color:var(--ink-3);font-variant-numeric:tabular-nums}
.sh-count.over{color:var(--red);font-weight:700}

/* Blocks. Every block carries a durable id in data-bid — the whole tracked-change,
   comment-anchor and sync model hangs off it, so it must never be regenerated. */
/* ============ THE MARGIN RULE — where a paragraph starts and stops ==========

   Alex, 2026-08-17: "the white space between paragraphs is hard to know where
   to put the cursor to start … it needs to look pretty, like a professional
   newspaper editor type thing."

   The gap between two blocks and the gap INSIDE a wrapped one looked identical,
   so the only way to find the top of a paragraph was to click and see where the
   caret landed. A copy desk solves this with a rule down the margin rather than
   with lines between paragraphs: the mark belongs beside the text, in the space
   already reserved for the gutter controls, where it separates without cutting
   the page into boxes.

   THREE STATES, EACH EARNING ITS INK. At rest a hairline sits in the margin for
   the paragraph's full height — enough to see the block's extent out of the
   corner of your eye, not enough to read as a border. On hover it darkens. With
   the caret in it, it takes the accent and thickens: the paragraph you are
   writing in is the one with a solid rule beside it, which is the whole point.

   ::before, not a border, because a border would move the text and change the
   line breaks the moment focus arrived. */
.blk{position:relative;margin:0 0 var(--sp-8);padding:2px 0 2px 0;border-radius:4px}
.blk::before{content:"";position:absolute;left:-14px;top:3px;bottom:3px;width:2px;
  border-radius:2px;color:var(--line);background:currentcolor;opacity:.55;
  transition:color .12s ease,opacity .12s ease,width .12s ease}
.blk:hover::before{opacity:1;color:var(--line-strong, var(--ink-4))}
.blk.focus::before{opacity:1;width:3px;color:var(--blue)}
/* A heading is a different kind of thing and says so: its rule is short, sitting
   at the cap height rather than running the block, so a section opening does not
   look like one more paragraph. */
.blk[data-t="h2"]::before,.blk[data-t="h3"]::before{bottom:auto;height:1.1em;
  width:3px;opacity:.8}
/* The first line of a paragraph gets a tick across the top of the rule — the
   mark a sub-editor makes to say "new par". It is what makes the START findable
   rather than merely the extent. */
/* PAINTED INTO THE RULE, NOT HUNG OFF ::after.

   An element has two pseudo-elements and this file was spending both: the tick
   here, and the invisible hover surface that keeps the gutter up while the
   pointer crosses the margin. The tick is the more specific selector, so on a
   PARAGRAPH — the block anyone actually hovers — it won, and the catch-area
   silently did not exist. Two backgrounds on the one box give the same ⌐ and
   hand ::after back.

   `currentcolor` for both layers so the hover and focus rules stay a
   one-property change instead of restating the gradients three times. */
.blk[data-t="p"]::before{width:9px;border-radius:0;background:
  linear-gradient(currentcolor,currentcolor) 0 0/2px 100% no-repeat,
  linear-gradient(currentcolor,currentcolor) 0 0/9px 2px no-repeat}
.blk[data-t="p"].focus::before{width:10px;background:
  linear-gradient(currentcolor,currentcolor) 0 0/3px 100% no-repeat,
  linear-gradient(currentcolor,currentcolor) 0 0/10px 3px no-repeat}
/* The gutter buttons live in the same margin and win it while they are up. */
.blk:hover .blk-gut,.blk.focus .blk-gut{z-index:2}
.blk .bd{font-family:var(--doc-font);font-size:16px;line-height:1.7;outline:none;
  min-height:1.7em;white-space:pre-wrap;word-wrap:break-word}
.blk[data-t="h2"] .bd{font-family:var(--ui-font);font-size:17px;font-weight:680;line-height:1.35}
.blk[data-t="h3"] .bd{font-family:var(--ui-font);font-size:14.5px;font-weight:680;
  text-transform:uppercase;letter-spacing:.05em;line-height:1.35;color:var(--ink-2)}
.blk[data-t="ul"] .bd,.blk[data-t="ol"] .bd{padding-left:22px}
.blk[data-t="quote"] .bd{border-left:3px solid var(--paper-line);padding-left:14px;color:var(--ink-2);font-style:italic}
.blk .bd:empty::before{content:attr(data-ph);color:var(--ink-4);font-style:italic;pointer-events:none}
.blk.focus{background:color-mix(in srgb,var(--surface-sel) 55%,transparent)}
/* THE GUTTER CONTROLS, made catchable (Alex, 2026-08-15: "it hides and shows
   too quick, you have to try to grab it"). Three mechanical fixes:
   - the ::after bridge below keeps .blk:hover TRUE across the empty margin
     between the text and the gutter — the buttons sat at -38px, OUTSIDE the
     block's hover box, so reaching for them crossed dead space and they
     vanished mid-reach;
   - showing is instant but hiding waits 0.4s (the transition-delay pair), so
     an overshoot or a wobble never loses them;
   - the targets are 24px, not a 13px glyph with 3px of padding.
   The caret's block keeps its controls pinned, as before (.blk.focus). */
/* NO 400ms WAIT. The gutter faded in after a four-tenths-of-a-second delay, so
   moving onto a paragraph and reaching for the comment button meant pressing a
   control that was not there yet — which reads as a button that does nothing
   (Alex, 2026-08-17: "the comment icon next to the paragraphs on desktop
   doesn't do anything"). It appears at once now and still fades out unhurried,
   which is the half of the delay that was doing useful work.

   AND IT CANNOT FALL OUTSIDE THE COLUMN. At left:-42px it lives in the writing
   surface's left margin, and .ed-main scrolls with overflow:auto — so whenever
   that margin is narrower than the gutter (a wide side pane, a small laptop),
   the buttons were clipped away entirely: invisible AND unclickable. The
   surface now reserves the space, so the margin can never be too small. */
/* CLEAR OF THE RULE. The column used to end at -6px while the rule sits at
   -14px, so a 24px button covered it: the marks that say where the paragraph
   starts and ends were behind the two controls that appear whenever you go
   near them (Alex, 2026-08-17, "that overlay is poor"). The column now ends
   at -22px, which is the rule's left edge less a clear 8px. */
.blk-gut{position:absolute;left:-46px;top:1px;width:24px;display:flex;flex-direction:column;
  align-items:center;gap:2px;opacity:0;transition:opacity .35s ease .25s}
.blk:hover .blk-gut,.blk.focus .blk-gut{opacity:1;transition:opacity .1s ease}
.blk::after{content:'';position:absolute;left:-52px;top:0;bottom:0;width:52px}
.blocks{padding-left:56px}
/* Very small, as asked — smaller than the 13px SVG it replaces, because an
   outline mark carries at a size a filled one cannot and this one sits in the
   margin beside a paragraph, where it should be findable rather than loud. */
.gut-cmt{display:block;width:12px;height:12px;background:currentColor;
  -webkit-mask:url(../img/comment-gutter.png) center/contain no-repeat;
  mask:url(../img/comment-gutter.png) center/contain no-repeat}
.blk-gut button{background:none;border:0;cursor:pointer;color:var(--ink-3, var(--ink-4));
  font-size:var(--fs-cap);
  width:22px;height:22px;display:grid;place-items:center;padding:0;border-radius:var(--radius-sm);line-height:1}
.blk-gut button:hover{background:var(--surface-hover);color:var(--ink)}

/* ON TOUCH there is no hover to fix, and the phone sheet's slim padding put
   the -42px gutter literally OFF-SCREEN — unhittable by geometry, not by
   finger. So: no hover gutter at all. Tap into a block and ITS two controls
   surface as a 38px-target pill above its right corner, inside the screen;
   selecting text floats a Comment chip at the selection (bound in editor.js).
   The hover bridge dies too — it would swallow left-edge taps. */
@media (hover:none) and (pointer:coarse){
  .blk::after{display:none}
  .blk-gut{display:none}
  .blk.focus .blk-gut{display:flex;opacity:1;flex-direction:row;gap:2px;
    left:auto;right:0;top:-38px;width:auto;
    background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-sm);
    padding:2px;box-shadow:0 4px 16px #00000022}
  .blk.focus .blk-gut button{width:38px;height:32px}
}
/* The selection Comment chip (touch; js/editor.js offerSelChip). */
.ed-selchip{position:fixed;z-index:400;display:inline-flex;align-items:center;gap:6px;
  padding:7px 14px;font-size:var(--fs-cap);font-weight:650;
  color:var(--ac-on);background:var(--ac-fill);border:0;border-radius:999px;
  cursor:pointer;box-shadow:0 4px 16px #00000033}
/* The accept/reject bar, pinned above the change the caret is in. Same
   floating-over-the-text idea as the comment chip, so it sits at the same
   z-layer and dies on the same scroll. */
.ed-tcbar{position:fixed;z-index:6000;display:flex;align-items:center;gap:6px;
  padding:5px 7px;border:1px solid var(--line-strong);border-radius:var(--radius-sm);
  background:var(--panel);box-shadow:0 6px 20px rgba(16,24,40,.16)}
.ed-tcwho{font-size:var(--fs-micro);color:var(--ink-3);font-weight:700;
  max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.blk.locked{background:var(--amber-bg);outline:1px dashed var(--amber-line)}
.blk-lock{position:absolute;right:-6px;top:-14px;font-size:var(--fs-micro);font-weight:700;
  background:var(--amber);color:#fff;padding:1px 6px;border-radius:999px}

/* Tracked changes, coloured by author. */
ins.tc{text-decoration:none;border-bottom:1.5px solid currentColor;background:var(--tc-bg,transparent);color:var(--tc-ink,var(--au-1))}
del.tc{text-decoration:line-through;opacity:.75;color:var(--tc-ink,var(--au-1))}
/* THE FOUR DISPLAY MODES. Displaying is never accepting — every mode leaves
   the marks exactly where they are, and switching back shows them again. That
   is the whole point: you can write in clean prose without giving up the record
   of what changed, which is the thing people turn tracking OFF to get.

   `.tc-all` needs no rules; it is the styling above.

   NONE and SIMPLE both show the text as it will READ once the changes are in —
   insertions plain, deletions gone. SIMPLE adds a bar in the margin so you can
   still see WHICH paragraphs were touched, which is the mode most people
   actually want while drafting. */
.tc-none ins.tc,.tc-simple ins.tc{border-bottom:0;background:none;color:inherit}
.tc-none del.tc,.tc-simple del.tc{display:none}
/* The change bar. :has() rather than a class stamped at render time, so it
   cannot drift out of step with the marks actually present in the block. */
.tc-simple .blk:has(ins.tc,del.tc),
.tc-simple .sh-title:has(ins.tc,del.tc){position:relative}
.tc-simple .blk:has(ins.tc,del.tc)::after{content:'';position:absolute;
  left:-10px;top:2px;bottom:2px;width:2px;border-radius:1px;background:var(--ac-edge)}

/* ORIGINAL is the mirror of NONE: the paper as it stood BEFORE this round —
   insertions not yet made, deletions still present and unstruck. It is how you
   answer "what did this actually say last week" without restoring a version. */
.tc-original ins.tc{display:none}
.tc-original del.tc{text-decoration:none;opacity:1;color:inherit;background:none}

/* The read-only banner for the two review modes, with the way out on it. */
.tc-ro{display:flex;align-items:center;gap:var(--sp-6);flex-wrap:wrap;
  margin:0 4px 8px;padding:var(--sp-5) var(--sp-8);border:1px solid var(--ac-edge);
  border-radius:var(--radius);background:var(--ac-wash);color:var(--ink-2);
  font-size:var(--fs-cap)}
.tc-ro .btn{margin-left:auto}

/* Kept because settings written before the four modes still carry it, and the
   desktop build may be older than the web one. Same meaning as .tc-none. */
.tc-hidden ins.tc{border-bottom:0;background:none;color:inherit}
.tc-hidden del.tc{display:none}
.cmt-mark{background:var(--amber-bg);box-shadow:inset 0 -2px 0 var(--amber);cursor:pointer;border-radius:2px}
/* A voice from outside the paper, marked as such wherever it is read. */
/* Alignment, beside the thing it aligns. Three buttons and a word — a select
   would hide the current answer behind a click. */
.sh-just{flex:0 0 auto}
.sh-just.on{background:var(--surface-sel);border-color:var(--blue);color:var(--ac-ink)}
.algn{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:8px 0 2px}
.algn-k{font-size:var(--fs-cap);color:var(--ink-2);font-weight:600;margin-right:2px}
.algn .btn.on{background:var(--surface-sel);border-color:var(--blue);color:var(--ac-ink)}

/* The comment control under the title field, and the label that says a comment
   is about the title rather than a paragraph. */
.ttl-cmt{display:flex;gap:6px;margin-top:6px;flex-wrap:wrap}
.ttl-cmt .gut-cmt{display:inline-block;vertical-align:-2px;margin-right:2px}
.cmt-where{font-size:var(--fs-cap);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700;margin-bottom:2px}

.cmt-ext{flex:0 0 auto;font-size:var(--fs-cap);font-weight:600;padding:1px 7px;
  border-radius:999px;background:var(--amber-bg);color:var(--amber);
  border:1px solid var(--amber-line);white-space:nowrap}
.cmt-mark.sel{background:var(--amber);color:#fff;box-shadow:none}
.cmt-mark.resolved{background:transparent;box-shadow:inset 0 -1px 0 var(--line-strong)}
.sp-bad{background:linear-gradient(transparent 88%,var(--red) 88%,var(--red) 96%,transparent 96%);cursor:pointer}
.gr-bad{background:linear-gradient(transparent 88%,var(--blue) 88%,var(--blue) 96%,transparent 96%);cursor:pointer}

/* Comment rail */
/* WHOSE NOTE THIS IS, AT A GLANCE. The spine down the left is the person's
   colour — the same one their tracked changes wear — so a thread with several
   people in it is legible without reading a single name. It is a border rather
   than a wash because the card also carries a selected and a resolved state,
   and a tinted background would have to fight both. */
.cmt{border:1px solid var(--line);border-left:3px solid var(--cmt-au, var(--line));
  background:var(--panel);border-radius:var(--radius-sm);
  padding:var(--sp-6);margin:0 var(--sp-6) var(--sp-6);font-size:var(--fs-sm)}
.cmt.sel{border-color:var(--blue);box-shadow:0 0 0 2px var(--blue-lt)}
.cmt.resolved{opacity:.58}
.cmt-top{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:var(--sp-4)}
.cmt-who{font-weight:660;color:var(--cmt-au, inherit)}
.cmt-when{font-size:var(--fs-micro);color:var(--ink-4);margin-left:auto}
.cmt-quote{font-size:var(--fs-cap);color:var(--ink-3);border-left:2px solid var(--amber);
  padding-left:var(--sp-5);margin-bottom:var(--sp-4);font-style:italic}
.cmt-body{white-space:pre-wrap}
.cmt-reply{margin-top:var(--sp-5);padding-top:var(--sp-5);border-top:1px solid var(--line-2);
  border-left:2px solid var(--cmt-au, transparent);padding-left:var(--sp-5);margin-left:-2px}
/* No `color` here on purpose: people.avatarHtml sets the paired --au-N-bg ink
   inline alongside the background, because only the pair is guaranteed 4.5:1 in
   BOTH themes. A default of #fff lived here and was unreadable in dark. */
.avatar{width:20px;height:20px;border-radius:999px;display:grid;place-items:center;flex:0 0 auto;
  font-size:var(--fs-micro);font-weight:800;letter-spacing:-.02em}
.avatar.has-photo{background:var(--surface-3);overflow:hidden}
.avatar.has-photo img{width:100%;height:100%;object-fit:cover;display:block}

/* Profile identity block in Settings */
.me-id{display:flex;gap:var(--sp-4);align-items:center;margin-bottom:var(--sp-4)}
.me-id-txt{min-width:0}
.me-photo{position:relative;width:56px;height:56px;border-radius:999px;padding:0;flex:0 0 auto;
  border:1px solid var(--line);background:var(--surface-3);cursor:pointer;overflow:hidden;display:block}
.me-photo:hover{border-color:var(--ac-fill)}
.me-photo img,.me-photo .me-mono{width:100%;height:100%;display:block;object-fit:cover}
.me-photo .me-mono{display:grid;place-items:center;color:#fff;font-weight:800;font-size:var(--fs-lead)}
.me-photo-cam{position:absolute;right:-1px;bottom:-1px;width:20px;height:20px;border-radius:999px;
  background:var(--ac-fill);color:#fff;display:grid;place-items:center;font-size:11px;
  border:2px solid var(--surface-2)}

/* Side panel tabs */
.sp-tabs{display:flex;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--surface-2);z-index:2}
.sp-tabs button{flex:1 1 0;background:none;border:0;border-bottom:2px solid transparent;
  padding:var(--sp-6) var(--sp-4);cursor:pointer;font-size:var(--fs-sm);font-weight:600;color:var(--ink-3)}
.sp-tabs button.on{color:var(--ac-ink);border-bottom-color:var(--ac-ink)}
.sp-body{padding:var(--sp-6) 0}

/* Diff view */
.diff{font-family:var(--doc-font);font-size:15px;line-height:1.7}
.diff ins{background:var(--green-bg);color:var(--green);text-decoration:none}
.diff del{background:var(--red-bg);color:var(--red)}
.diffcols{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-10)}
@media (max-width:900px){.diffcols{grid-template-columns:1fr}}

/* Tables & figures */
.tblbox{overflow-x:auto;border:1px solid var(--paper-line);border-radius:var(--radius-sm)}
table.mstable{border-collapse:collapse;width:100%;font-size:13px;font-family:var(--ui-font)}
table.mstable th,table.mstable td{border:1px solid var(--paper-line);padding:5px 8px;text-align:left;vertical-align:top}
table.mstable th{background:var(--surface-2);font-weight:660}
table.mstable td.num,table.mstable th.num{text-align:right;font-variant-numeric:tabular-nums}
.figbox{border:1px solid var(--paper-line);border-radius:var(--radius-sm);padding:var(--sp-6);
  background:var(--surface-3);text-align:center}
.figbox img{max-width:100%;height:auto;border-radius:4px}
.cap{font-size:var(--fs-sm);color:var(--ink-2);margin-top:var(--sp-5);text-align:left;line-height:1.5}
.cap b{color:var(--ink)}

/* PDF reader (peer review) */
.rvwrap{display:flex;height:100%;min-height:0}
.rv-pdf{flex:1 1 55%;background:var(--frame-bg);overflow:auto;padding:var(--sp-8);min-width:0}
.rv-pdf canvas{display:block;margin:0 auto var(--sp-8);max-width:100%;box-shadow:var(--shadow-lg);background:#fff}
.rv-form{flex:1 1 45%;overflow:auto;min-width:0;background:var(--bg)}
.pdftools{position:sticky;top:0;z-index:3;background:var(--tb-bg);border-bottom:1px solid var(--tb-line);
  padding:var(--sp-4) var(--sp-6);display:flex;align-items:center;gap:var(--sp-4);margin:calc(var(--sp-8) * -1) calc(var(--sp-8) * -1) var(--sp-8)}

/* Checklists */
.ck-row{display:flex;gap:var(--sp-6);padding:var(--sp-5) var(--sp-6);border-bottom:1px solid var(--line-2);
  align-items:flex-start;font-size:var(--fs-ui)}
.ck-row:hover{background:var(--surface-hover)}
.ck-no{width:34px;flex:0 0 auto;color:var(--ink-4);font-size:var(--fs-cap);font-weight:700;padding-top:2px}
.ck-txt{flex:1 1 auto;min-width:0}
.ck-st{flex:0 0 auto;display:flex;gap:2px}
.ck-st button{border:1px solid var(--line-strong);background:var(--panel);width:26px;height:22px;
  border-radius:4px;cursor:pointer;font-size:var(--fs-cap);line-height:1;padding:0}
.ck-st button.on[data-v="y"]{background:var(--green-bg);border-color:var(--green);color:var(--green);font-weight:800}
.ck-st button.on[data-v="p"]{background:var(--amber-bg);border-color:var(--amber);color:var(--amber);font-weight:800}
.ck-st button.on[data-v="n"]{background:var(--red-bg);border-color:var(--red);color:var(--red);font-weight:800}
.ck-st button.on[data-v="na"]{background:var(--surface-sel);border-color:var(--blue);color:var(--ac-ink);font-weight:800}

/* Portal-paste block: the text that gets copied into ScholarOne / Editorial Manager */
.paste{font:12.5px/1.6 var(--mono);white-space:pre-wrap;background:var(--surface-3);
  border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--sp-8);max-height:420px;overflow:auto}

/* Audit trail */
.aud{font-size:var(--fs-sm);display:grid;grid-template-columns:auto auto 1fr auto;gap:var(--sp-3) var(--sp-6);
  align-items:baseline}
.aud .t{color:var(--ink-4);font-variant-numeric:tabular-nums;font-size:var(--fs-cap);white-space:nowrap}
.aud .w{font-weight:640;white-space:nowrap}
.aud .d{color:var(--ink-2);min-width:0}
.aud .s{color:var(--ink-4);font-size:var(--fs-cap);white-space:nowrap}

/* ---------- Print ------------------------------------------------------- */
@media print{
  body{overflow:visible;background:#fff}
  #app,#toasts,#modals,#boot{display:none !important}
  #printRoot{display:block !important}
}
#printRoot{display:none}

/* ---------- Lint marks -------------------------------------------------
   Painted with the CSS Custom Highlight API over live Ranges, so the checker
   never writes a <span> into the paragraph — nothing it does can reach the
   saved HTML, the diff, or the .docx. Where the API is missing these rules
   simply never match and the side panel still lists every issue. */
::highlight(ms-spell){
  text-decoration:underline wavy var(--red);
  text-decoration-skip-ink:none;
  text-underline-offset:3px;
}
::highlight(ms-grammar){
  text-decoration:underline wavy var(--blue);
  text-decoration-skip-ink:none;
  text-underline-offset:3px;
}

/* ---------- Find matches (js/find.js) ---------------------------------
   Same mechanism as the lint marks — Highlight API over live Ranges, nothing
   written into the paragraph. The current match carries its own ink because
   the darker disc would otherwise fail contrast on the theme's text colour. */
::highlight(ms-find){background:var(--find-hl)}
::highlight(ms-find-cur){background:var(--find-cur);color:var(--find-cur-ink)}

/* The find bar floats over the work on <body> — it must survive every
   innerHTML rebuild of the editor and the panes, which is also why it binds
   its own listeners (a body child never hears the delegated ones). */
.findbar{
  position:fixed;top:64px;right:24px;z-index:200;   /* top/right re-docked inline to the searched surface */
  display:flex;align-items:center;gap:6px;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:6px 8px;box-shadow:0 8px 30px #00000022;
}
.findbar input{
  width:200px;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2);color:var(--ink);font-size:var(--fs-ui);
  padding:5px 8px;
}
.fb-scope{font-size:var(--fs-cap);color:var(--ink-3);white-space:nowrap;
  border-left:2px solid var(--ac-edge);padding-left:8px}
.fb-count{font-size:var(--fs-cap);color:var(--ink-3);min-width:64px;text-align:center}
.fb-btn{
  border:1px solid var(--line);background:var(--surface-2);color:var(--ink-2);
  border-radius:var(--radius-sm);width:26px;height:26px;line-height:1;
  font-size:15px;cursor:pointer;
}
.fb-btn:hover{background:var(--surface-hover);color:var(--ink)}

/* The whole-document heading carries the Find control on its right; the title
   and meta keep their centring from the middle slot of the flex row (layout
   merged into .wholehead's own rule — no duplicate selector). */
.wh-mid{flex:1 1 auto;min-width:0}
.wh-find{flex:0 0 auto}

/* Placeholder for a stub changelog before sync-app.sh generates the real one. */
.card-body code{font:var(--fs-sm)/1.4 var(--mono);background:var(--surface-2);
  padding:1px 4px;border-radius:3px}

/* ============================================================================
   Citation library — three columns: collections, hits, the selected record.
   The shape every reference manager converges on, because it is the one that
   lets you search, file and read without losing your place in any of the three.
   ========================================================================= */
.cite{display:flex;height:100%;min-height:0}
/* A column, so the summary can be pushed to the FOOT of the rail rather than
   trailing whatever section happens to be last. It is a statement about the
   whole library, not another way in, and it belongs where a footer belongs. */
.cite-side{width:230px;flex:0 0 auto;border-right:1px solid var(--line);
  background:var(--surface-2);overflow:auto;padding:var(--sp-6) 0;
  display:flex;flex-direction:column}
.cite-side > .cite-sec.is-foot{margin-top:auto}
.cite-list{width:380px;flex:0 0 auto;border-right:1px solid var(--line);
  display:flex;flex-direction:column;min-width:0;overflow:hidden}
.cite-detail{flex:1 1 auto;overflow:auto;min-width:0;background:var(--panel)}
@media (max-width:1200px){.cite-side{display:none}}
/* Below 860px the three columns will not fit, so the record used to be
   display:none — which quietly removed every per-record action (edit, PDF,
   copy, add-to-manuscript) with no way to reach them. Stack instead of delete:
   the list sits on top, the selected record reads underneath, and both keep
   their own scroll. Nothing becomes unreachable, it just becomes taller. */
@media (max-width:860px){
  .cite{flex-direction:column}
  .cite-list{flex:0 0 auto;width:auto;max-height:45%;border-right:0;
    border-bottom:1px solid var(--line)}
  .cite-detail{flex:1 1 auto;min-height:0}
}

/* A SECTION HEADING HAS TO OUTRANK WHAT IS UNDER IT. This was 10px against
   12.5px rows — the label for a group was literally smaller than its members,
   which is the whole reason the column read as sloppy (Alex, 2026-08-16: "the
   main section headers are tinier than the other writing"). Now it matches
   the rows in size and wins on weight, case and colour, and a hairline above
   each one does the separating that whitespace alone was failing at. */
.cite-sec{font-size:var(--fs-ui);text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-2);font-weight:800;
  padding:var(--sp-6) var(--sp-6) var(--sp-4);margin-top:var(--sp-6);
  border-top:1px solid var(--line-2);
  display:flex;align-items:center;gap:var(--sp-3)}
.cite-side > .cite-sec:first-child{border-top:0;margin-top:0;padding-top:var(--sp-4)}
.cite-sec .btn{margin-left:auto;padding:0 6px;font-size:14px;line-height:1;color:var(--ink-3)}
.cite-sec .btn:hover{color:var(--ac-ink)}

.cite-row{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6);
  cursor:pointer;font-size:var(--fs-ui);color:var(--ink-2);border-radius:var(--radius-sm);
  margin:0 var(--sp-3)}
.cite-row:hover{background:var(--surface-hover);color:var(--ink)}
.cite-row.sel{background:var(--surface-sel);color:var(--ac-ink);font-weight:640}
.cite-row .lbl{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Every mark on the same 14px box, so the labels start at one x all the way
   down — the glyphs this replaced were three different widths. */
.cite-row .ci-mk{flex:0 0 auto;width:14px;height:14px;display:inline-flex;
  align-items:center;justify-content:center;color:var(--ink-4)}
.cite-row.sel .ci-mk{color:var(--ac-ink)}
/* ONE LEFT EDGE FOR EVERY LABEL. Only the Library rows carry a mark, so
   without this the collections and projects below started 22px to the left of
   the rows above them — the ragged edge that kept the column looking thrown
   together after everything else was fixed. A row whose label comes first is
   inset by exactly the width a mark would have taken. */
.cite-row > .lbl:first-child{margin-left:calc(14px + var(--sp-4))}
/* A linked project's live mark — this list is whatever the paper cites, so it
   needs no filing and the dot says which ones are like that. It occupies a
   MARK'S BOX rather than sizing itself, or it would put the project labels at
   a third x of their own. (Its rule was lost when the old nested-rail block
   was replaced; the dot has been unstyled since.) */
.ci-live{flex:0 0 auto;width:14px;height:14px;display:inline-flex;align-items:center;
  justify-content:center;color:var(--green, #2f8f5b);font-size:9px;line-height:1}
/* The counts form a column: right-aligned, tabular, one width. */
.cite-row .n{font-size:var(--fs-cap);color:var(--ink-4);flex:0 0 auto;
  min-width:2.2em;text-align:right;font-variant-numeric:tabular-nums}
.cite-row.sel .n{color:var(--ac-ink);opacity:.75}

/* At a glance: label on the left, number on the right, one line each. Five
   figures separated by middots was a paragraph you had to parse. */
.cite-glance{margin:0;padding:0 var(--sp-6) var(--sp-8);
  display:grid;grid-template-columns:1fr auto;gap:2px var(--sp-6);
  font-size:var(--fs-cap)}
.cite-glance dt{color:var(--ink-4)}
.cite-glance dd{margin:0;color:var(--ink-2);font-weight:700;text-align:right;
  font-variant-numeric:tabular-nums}

/* ==== THE RAIL'S FOUR AXES =============================================
   Collections, projects, labels and saved searches are siblings, so their
   rows are identical and only the section heading distinguishes them. The ⋯
   on a row stays invisible until the row is under the pointer — a column of
   permanent controls stops being a list of names. */
/* THE ⋯ IS ALWAYS THERE, just quiet. Hidden until hover it was invisible —
   there is no hover on a touch screen at all, and on a desktop you cannot look
   for a control you have never seen (Alex, 2026-08-16: "not visible and also
   too small"). Bigger, too: 22px is a hittable target, 18px was not. */
.cite-row .ci-add{flex:0 0 auto;width:22px;height:22px;padding:0;border:0;background:none;
  color:var(--ink-4);cursor:pointer;border-radius:4px;line-height:1;font-size:16px;
  display:inline-flex;align-items:center;justify-content:center;
  opacity:.45;transition:opacity .12s,color .12s,background .12s}
.cite-row:hover .ci-add,.cite-row .ci-add:focus-visible{opacity:1}
.cite-row .ci-add:hover{color:var(--ac-ink);background:var(--surface-3);opacity:1}

/* Labels are names, so they are bubbles rather than rows — a wrapping cloud
   reads as "the vocabulary of this library" at a glance. */
.cite-labels{display:flex;flex-wrap:wrap;gap:var(--sp-3);padding:2px var(--sp-6) var(--sp-6)}
.ci-label{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;cursor:pointer;
  border:1px solid var(--line);border-radius:999px;background:var(--surface-2);
  color:var(--ink-2);font-size:var(--fs-micro);font-weight:600;
  font-family:inherit;line-height:1.6}
.ci-label:hover{border-color:var(--ac-fill);color:var(--ac-ink)}
.ci-label.on{background:var(--ac-wash);border-color:var(--ac-fill);color:var(--ac-ink)}
.ci-label .n{color:var(--ink-4);font-weight:500}
.ci-label.on .n{color:var(--ac-ink);opacity:.7}

.cite-bar{flex:0 0 auto;display:flex;gap:var(--sp-4);align-items:center;
  padding:var(--sp-5) var(--sp-6);border-bottom:1px solid var(--line);background:var(--tb-bg)}
/* The search wrap carries the magnifier INSIDE the field's border, the way
   every reference manager draws it; the input itself is borderless within. */
/* Search owns its own full-width first row — the EndNote/Zotero shape — so
   it can never be squeezed to nothing while the buttons clip off the edge,
   which is exactly what the one-row bar did in a narrow list pane. */
.cite-bar{flex-wrap:wrap}
/* Flexes beside the sort rather than claiming a row of its own. `flex:1 1 100%`
   with `order:-1` is what put search on line one and pushed four small controls
   onto two more lines below it. */
.cite-search{flex:1 1 90px;min-width:0;display:flex;align-items:center;gap:6px;
  border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2);padding:0 8px;color:var(--ink-3)}
.cite-search input[type=search]{flex:1 1 auto;min-width:0;border:0;background:none;
  color:var(--ink);padding:7px 0;font-size:var(--fs-ui);outline:none}
.cite-bar input[type=search]{flex:1 1 auto;min-width:0}
.cite-bar .btn svg{vertical-align:-2px;margin-right:2px}
/* Icon-only: square, and no room reserved for a label that is not there. */
.cite-bar .btn.icon{padding-left:0;padding-right:0;width:34px;justify-content:center}
.cite-bar .btn.icon svg{margin-right:0}
.cite-bar select{width:auto;flex:0 0 auto}
.cite-scroll{flex:1 1 auto;overflow:auto;min-height:0}

.cite-item{padding:var(--sp-6) var(--sp-8);border-bottom:1px solid var(--line-2);cursor:pointer}
.cite-item:hover{background:var(--surface-hover)}
.cite-item.sel{background:var(--surface-sel);box-shadow:inset 3px 0 0 var(--ac-fill)}
.ci-top{display:flex;align-items:center;gap:var(--sp-4);margin-bottom:2px}
.ci-au{font-size:var(--fs-ui);font-weight:660;color:var(--ink)}
/* The label on a row: a bubble, and clickable — seeing "ENRICH" and wanting
   the rest of ENRICH is the same impulse, one click apart. */
/* Label and paperclip travel together at the END of the row, in that order.
   Both answer "which row is this" at a glance, and a fixed column means the
   eye finds them without looking; a mark that floats between rows has to be
   located before it can be read. */
.ci-right{margin-left:auto;flex:0 0 auto;display:flex;align-items:center;gap:var(--sp-4);
  min-width:0}
.ci-lab{flex:0 1 auto;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  padding:1px 7px;border-radius:999px;background:var(--ac-wash);color:var(--ac-ink);
  border:1px solid var(--ac-fill);font-size:var(--fs-micro);font-weight:700;
  letter-spacing:.02em;cursor:pointer}
.ci-lab:hover{background:var(--ac-fill);color:var(--ac-on)}
/* The label field in the record: an input that does not look like a form
   until you touch it, so the fields table still reads as a table. */
.ci-lab-in{border:1px solid transparent;background:var(--surface-2);border-radius:999px;
  padding:2px 10px;font-size:var(--fs-ui);font-weight:640;color:var(--ac-ink);
  width:100%;max-width:260px}
.ci-lab-in::placeholder{color:var(--ink-4);font-weight:400}
.ci-lab-in:hover{border-color:var(--line)}
.ci-lab-in:focus{border-color:var(--ac-fill);background:var(--panel);outline:none}
.ci-yr{font-size:var(--fs-cap);color:var(--ink-3);font-variant-numeric:tabular-nums}
.ci-fav{color:var(--amber)}
.ci-ti{font-size:var(--fs-ui);line-height:1.4;color:var(--ink);margin-bottom:2px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ci-jo{font-size:var(--fs-cap);color:var(--ink-3);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}

.cd-head{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-5) var(--sp-8);
  border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--panel);z-index:2}
.cd-body{padding:var(--sp-8) var(--sp-10) 60px}
.cd-cite{font-family:var(--doc-font);font-size:15px;line-height:1.6;
  padding-bottom:var(--sp-8);border-bottom:1px solid var(--line-2)}
.cd-actions{display:flex;gap:var(--sp-4);flex-wrap:wrap;align-items:center;margin:var(--sp-8) 0}
.cd-actions select{width:auto;max-width:220px}
.cd-actions a.btn{text-decoration:none}
.cd-sec{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.09em;
  color:var(--ink-4);font-weight:700;margin:var(--sp-10) 0 var(--sp-4)}
.cd-chips{display:flex;flex-wrap:wrap;gap:var(--sp-3)}
/* The same small heading, for the settings cards and dialogs that need to
   divide one card into parts without promoting each part to its own card. */
.card-sub{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.09em;
  color:var(--ink-4);font-weight:700;margin:var(--sp-10) 0 var(--sp-4)}
table.cd-fields td{padding:var(--sp-3) var(--sp-5);font-size:var(--fs-ui)}
table.cd-fields td.k{width:110px;color:var(--ink-3);font-weight:600}

/* ============================================================================
   Formatting toolbar + whole-document view
   ========================================================================= */
.edwrap{display:flex;flex-direction:column;height:100%;min-height:0}
.edsurface{flex:1 1 auto;overflow:auto;min-height:0}
.fmtbar{flex:0 0 auto;display:flex;align-items:center;gap:2px;flex-wrap:wrap;
  padding:var(--sp-3) var(--sp-6);background:var(--tb-bg);
  border-bottom:1px solid var(--tb-line);position:sticky;top:0;z-index:6}
.fmtbar .tbb{background:var(--tb-btn-bg);border:1px solid transparent;color:var(--ink);
  min-width:28px;height:26px;border-radius:var(--radius-sm);cursor:pointer;
  font-size:var(--fs-ui);line-height:1;padding:0 6px;display:inline-flex;
  align-items:center;justify-content:center}
/* An inline box inside the flex button, so sup/sub can sit where they belong. */
.fmtbar .tbb-l{display:inline-block;line-height:1;white-space:nowrap}
.fmtbar .tbb-l sup{font-size:.68em;vertical-align:super}
.fmtbar .tbb-l sub{font-size:.68em;vertical-align:sub}
.fmtbar .tbb:hover{background:var(--tb-btn-hover);border-color:var(--tb-btn-line)}
.fmtbar .tbb.on{background:var(--surface-sel);border-color:var(--blue);color:var(--ac-ink)}
.fmtbar .tbsel{width:auto;min-width:120px;font-size:var(--fs-sm);padding:3px 6px;
  background:var(--tb-btn-bg);border-color:var(--tb-btn-line)}
.fmtbar .tbsep{width:1px;height:18px;background:var(--tb-sep);margin:0 var(--sp-3)}
.fmtbar .tbstate{font-size:var(--fs-cap);color:var(--ink-3);padding-right:var(--sp-4)}
.fmtbar mark,.paste mark{background:var(--amber-bg);color:var(--amber);border-radius:2px}

/* Whole-document view: the sections run continuously, each still its own sheet
   so you can see where one ends and the next begins. */
.wholehead{width:100%;margin:0 auto var(--sp-8);text-align:center;display:flex;align-items:center;gap:var(--sp-4)}
.wh-title{font-size:20px;font-weight:680;letter-spacing:-.015em;color:var(--ink)}
.wh-meta{font-size:var(--fs-cap);color:var(--ink-3);margin-top:var(--sp-2)}
.sheet.cont{margin-bottom:var(--sp-12)}
.sheet.cont .sh-head{position:sticky;top:0;background:var(--paper);z-index:3;
  padding-top:var(--sp-6);margin-top:calc(var(--sp-16) * -1 + var(--sp-6))}

/* ============================================================================
   Compare and merge returned versions
   ========================================================================= */
.vstrip{display:flex;gap:var(--sp-6);flex-wrap:wrap}
.vcard{flex:1 1 190px;min-width:170px;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:var(--sp-6);background:var(--surface-2)}
.vcard.base{background:var(--blue-lt);border-color:var(--blue-line)}
.vcard.off{opacity:.5}
.vname{font-weight:660;font-size:var(--fs-ui);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vmeta{font-size:var(--fs-cap);color:var(--ink-3);margin-top:2px;line-height:1.4}
.vacts{display:flex;gap:2px;margin-top:var(--sp-4)}

.mrows{display:flex;flex-direction:column;gap:var(--sp-6)}
.mrow{border:1px solid var(--line);border-radius:var(--radius);background:var(--panel);
  box-shadow:var(--shadow);overflow:hidden}
.mrow.changed{border-left:3px solid var(--amber)}
.mrow.conflict{border-left:3px solid var(--red)}
.mhead{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-4) var(--sp-8);
  border-bottom:1px solid var(--line-2);background:var(--surface-2)}
.mno{font-size:var(--fs-cap);font-weight:700;color:var(--ink-4);font-variant-numeric:tabular-nums}
.mcols{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:1px;
  background:var(--line-2)}
.mcol{background:var(--panel);padding:var(--sp-6) var(--sp-8);display:flex;flex-direction:column;gap:var(--sp-4)}
.mcol.picked{background:var(--surface-sel);box-shadow:inset 0 0 0 2px var(--blue)}
.mwho{font-size:var(--fs-cap);font-weight:700;color:var(--ink-2);text-transform:uppercase;
  letter-spacing:.05em;display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap}
.mtext{font-family:var(--doc-font);font-size:14px;line-height:1.6;flex:1 1 auto}
.mtext.diff ins{background:var(--green-bg);color:var(--green);text-decoration:none}
.mtext.diff del{background:var(--red-bg);color:var(--red)}
.mcmt{font-size:var(--fs-sm);background:var(--amber-bg);border-left:2px solid var(--amber);
  padding:var(--sp-4) var(--sp-5);border-radius:0 var(--radius-sm) var(--radius-sm) 0}
.mcol .btn{align-self:flex-start}

/* The whole-manuscript viewer pane: the rest of the paper always to hand, with
   the section you are editing marked so clicking through the outline never
   loses your place. */
.wp-sec{border-bottom:1px solid var(--line-2);padding-bottom:var(--sp-6)}
.wp-sec:last-child{border-bottom:0}
.wp-sec.here{background:var(--surface-sel);box-shadow:inset 3px 0 0 var(--ac-fill)}
.wp-head{position:sticky;top:0;z-index:1;background:var(--surface-2);
  display:flex;align-items:center;gap:var(--sp-4);
  padding:var(--sp-4) var(--sp-8);font-family:var(--ui-font);
  font-size:var(--fs-cap);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-2);border-bottom:1px solid var(--line-2);margin-bottom:var(--sp-5)}
.wp-sec.here .wp-head{background:var(--surface-sel);color:var(--ac-ink)}
.wp-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wp-wc{margin-left:auto;font-weight:600;letter-spacing:0;color:var(--ink-4);
  font-variant-numeric:tabular-nums;flex:0 0 auto}
/* PADDED ONCE, NOT TWICE. The paragraphs carry their own horizontal padding so
   a hover or a selection highlight runs the full width of the column — which
   means .pv must not pad the same edge again, or the text is inset by both and
   the reading column in a 340px pane loses ~56px to margins it does not need
   (Alex, on desktop: "the right pane padding for the viewer panel is still very
   wide"). Vertical padding on .pv stays; only the doubled sides go. */
/* The equal-contribution and supplement legends, right-set under the byline
   the way Alex's title page prints them. */
.doc .au-notes{text-align:right;font-size:.92em;margin:10pt 0 0;line-height:1.5}
.wp .pv-p,.wp .pv-h2,.wp .pv-h3{padding-left:var(--sp-6);padding-right:var(--sp-6)}
.pv.wp{padding-left:0;padding-right:0}
/* A thin scrollbar rather than a reserved gutter: `scrollbar-gutter: stable`
   permanently spends ~10px of a 340px column to avoid a shift that only happens
   when content changes length, which is the wrong trade in the pane somebody
   just asked to be less padded. */
.pane-body::-webkit-scrollbar{width:8px}
.pane-body::-webkit-scrollbar-thumb{background:var(--line);border-radius:4px}
.pane-body::-webkit-scrollbar-track{background:transparent}
.wp-empty{padding:0 var(--sp-8) var(--sp-4);font-size:var(--fs-cap);color:var(--ink-4);font-style:italic}

/* ============================================================================
   APPEARANCE
   Seeds are data-* attributes on <html>; each block below supplies the role
   tokens the rest of the stylesheet consumes. Three namespaces, never mixed:

     --ac-* / --ui-* / --rail-*   screen furniture
     --srf-*                      the writing surface as seen on screen
     --doc-*                      what the exporter reads — written by nothing
                                  in here, and read by nothing outside .sheet

   No block below sets a --doc-* value. That is the property that stops an
   appearance setting from changing a manuscript you have already submitted.
   ========================================================================= */

/* ---------- Accent, five roles ------------------------------------------
   fill  solid backgrounds        3:1 vs the panel behind it
   on    text ON the fill         4.5:1 vs the fill  (inverts in dark mode)
   ink   the accent AS TEXT       4.5:1 vs the panel
   edge  1px borders/underlines   3:1 vs the panel
   wash  tint behind a hot row    --ink on top of it must still clear 4.5:1  */
:root{
  --ac-fill:#012169; --ac-fill-hover:#0b2f7e; --ac-on:#ffffff;
  --ac-ink:#012169;  --ac-edge:#5c78bd;       --ac-wash:#eef2fc;
}
:root[data-accent="navy"]{--ac-fill:#012169;--ac-fill-hover:#0b2f7e;--ac-on:#fff;--ac-ink:#012169;--ac-edge:#5c78bd;--ac-wash:#eef2fc}
:root[data-accent="blue"]{--ac-fill:#1b5fbf;--ac-fill-hover:#154b99;--ac-on:#fff;--ac-ink:#154b99;--ac-edge:#5b8ad6;--ac-wash:#eaf1fc}
:root[data-accent="teal"]{--ac-fill:#0e6a6b;--ac-fill-hover:#0a5354;--ac-on:#fff;--ac-ink:#0a5354;--ac-edge:#3e9596;--ac-wash:#e8f5f5}
:root[data-accent="bronze"]{--ac-fill:#8a5a1b;--ac-fill-hover:#734a14;--ac-on:#fff;--ac-ink:#734a14;--ac-edge:#b28248;--ac-wash:#faf1e4}
:root[data-accent="plum"]{--ac-fill:#6b3fa0;--ac-fill-hover:#57318a;--ac-on:#fff;--ac-ink:#57318a;--ac-edge:#9470c4;--ac-wash:#f3eefa}
:root[data-accent="ember"]{--ac-fill:#a8431f;--ac-fill-hover:#8f3617;--ac-on:#fff;--ac-ink:#8f3617;--ac-edge:#c06a44;--ac-wash:#fcf1ec}
:root[data-accent="forest"]{--ac-fill:#1f6b3a;--ac-fill-hover:#17542d;--ac-on:#fff;--ac-ink:#17542d;--ac-edge:#4f9468;--ac-wash:#eaf5ee}
:root[data-accent="graphite"]{--ac-fill:#3d4757;--ac-fill-hover:#2f3846;--ac-on:#fff;--ac-ink:#2f3846;--ac-edge:#78849a;--ac-wash:#eef0f4}

/* Dark mode is NOT the light palette dimmed. The fill goes bright so it stays
   findable on a dark panel, which forces the label on it to go near-black. */
:root[data-theme="dark"][data-accent="navy"]{--ac-fill:#7d9df0;--ac-fill-hover:#93aef5;--ac-on:#0a1020;--ac-ink:#a8bdf7;--ac-edge:#3f5390;--ac-wash:#161d2e}
:root[data-theme="dark"][data-accent="blue"]{--ac-fill:#6fa8f5;--ac-fill-hover:#87b8f8;--ac-on:#06101f;--ac-ink:#9cc4fa;--ac-edge:#3a6099;--ac-wash:#121f30}
:root[data-theme="dark"][data-accent="teal"]{--ac-fill:#3fbfbf;--ac-fill-hover:#5bcece;--ac-on:#04201f;--ac-ink:#6fd8d6;--ac-edge:#2a7b7b;--ac-wash:#0f2222}
:root[data-theme="dark"][data-accent="bronze"]{--ac-fill:#d9a05a;--ac-fill-hover:#e3b273;--ac-on:#1e1305;--ac-ink:#e8bb80;--ac-edge:#8f6a34;--ac-wash:#241c0f}
:root[data-theme="dark"][data-accent="plum"]{--ac-fill:#a97fe0;--ac-fill-hover:#bb96e8;--ac-on:#140a22;--ac-ink:#c6a8f2;--ac-edge:#6b4a9c;--ac-wash:#1d1629}
:root[data-theme="dark"][data-accent="ember"]{--ac-fill:#d5642f;--ac-fill-hover:#e07a48;--ac-on:#1a0e07;--ac-ink:#e8875a;--ac-edge:#a85630;--ac-wash:#241612}
:root[data-theme="dark"][data-accent="forest"]{--ac-fill:#5fc384;--ac-fill-hover:#7ad09a;--ac-on:#04190c;--ac-ink:#8bd8a6;--ac-edge:#2f7a4b;--ac-wash:#0f2216}
:root[data-theme="dark"][data-accent="graphite"]{--ac-fill:#9aa7bb;--ac-fill-hover:#aeb9ca;--ac-on:#0d1119;--ac-ink:#b8c3d4;--ac-edge:#5a6577;--ac-wash:#181d26}

/* The existing vocabulary now derives from the accent roles, so every rule in
   the stylesheet above follows the palette without being touched. */
:root{
  --navy:var(--ac-ink); --navy-2:var(--ac-fill-hover);
  --blue:var(--ac-edge); --blue-lt:var(--ac-wash); --blue-line:var(--ac-edge);
  --surface-sel:var(--ac-wash); --on-accent:var(--ac-on);
}

/* ---------- Chrome tone --------------------------------------------------
   Independent of light/dark on purpose: the classic workstation look is a deep
   rail beside a white page IN A LIGHT APP, which a light/dark switch alone
   cannot express. */
:root[data-chrome="ink"]{--nav-fill:#0e1c33;--nav-edge:#0a1526;--nav-ink:#dbe3f5;--nav-ink-dim:#8fa3cf}
:root[data-chrome="slate"]{--nav-fill:#2b3444;--nav-edge:#222a38;--nav-ink:#e2e7f0;--nav-ink-dim:#9aa6ba}
:root[data-chrome="paper"]{--nav-fill:#f2f4f8;--nav-edge:#dde2ea;--nav-ink:#26303f;--nav-ink-dim:#68748a}
:root[data-theme="dark"][data-chrome="paper"]{--nav-fill:#171d28;--nav-edge:#232b38;--nav-ink:#dfe4ec;--nav-ink-dim:#8e99ab}
:root[data-theme="dark"][data-chrome="slate"]{--nav-fill:#111722;--nav-edge:#1b2230;--nav-ink:#dfe4ec;--nav-ink-dim:#8e99ab}
#sidebar{background:var(--nav-fill);border-right-color:var(--nav-edge);color:var(--nav-ink)}
.nav-title{color:var(--nav-ink)}
.nav-sub,.nav-sec-head,.nav-row .val{color:var(--nav-ink-dim)}
.nav-row{color:var(--nav-ink)}
.nav-mark{color:var(--nav-ink)}
:root[data-chrome="paper"] .nav-row:hover{background:rgba(0,0,0,.05)}
:root[data-chrome="paper"] .nav-row.sel{background:var(--ac-wash);color:var(--ac-ink);border-color:var(--ac-edge)}
:root[data-chrome="paper"] .nav-foot{border-top-color:var(--nav-edge)}

/* ---------- Density — CHROME ONLY ---------------------------------------
   Density must never reach the sheet. The moment the writing surface's metrics
   move, the on-screen preview stops matching the exported file and the writer
   has no way to know. */
:root{--ui-scale:1;--ui-row:1;--ui-fs:1}
:root[data-density="compact"]{--ui-scale:.82;--ui-row:.84;--ui-fs:.94}
:root[data-density="roomy"]{--ui-scale:1.22;--ui-row:1.2;--ui-fs:1.06}
:root[data-density="compact"],:root[data-density="roomy"]{
  --sp-3:calc(6px*var(--ui-scale)); --sp-4:calc(8px*var(--ui-scale));
  --sp-5:calc(10px*var(--ui-scale)); --sp-6:calc(12px*var(--ui-scale));
  --sp-8:calc(16px*var(--ui-scale)); --sp-10:calc(20px*var(--ui-scale));
  --sp-12:calc(24px*var(--ui-scale));
  --fs-ui:calc(12.5px*var(--ui-fs)); --fs-sm:calc(12px*var(--ui-fs));
  --fs-base:calc(13px*var(--ui-fs)); --fs-cap:calc(11px*var(--ui-fs));
  --fs-title:calc(14px*var(--ui-fs));
}
:root[data-density="compact"] .nav-row,
:root[data-density="compact"] .out-row,
:root[data-density="compact"] .cite-row{padding-top:2px;padding-bottom:2px}
:root[data-density="roomy"] .nav-row,
:root[data-density="roomy"] .out-row,
:root[data-density="roomy"] .cite-row{padding-top:7px;padding-bottom:7px}

/* ---------- Corners ------------------------------------------------------ */
:root[data-corners="square"]{--radius:3px;--radius-sm:2px}
:root[data-corners="soft"]{--radius:10px;--radius-sm:6px}
:root[data-corners="round"]{--radius:16px;--radius-sm:10px}

/* ---------- Panel style --------------------------------------------------
   Flat is also the performance mode: no blurred shadows repainting behind a
   long scrolling document. Separation moves to a hairline, so nothing ever
   depends on a shadow alone to be distinguishable. */
:root[data-panels="flat"]{
  --shadow:0 0 0 1px var(--line-strong);
  --shadow-lg:0 0 0 1px var(--line-strong);
  --paper-shadow:transparent;
}
:root[data-panels="flat"] .card,
:root[data-panels="flat"] .sheet{box-shadow:0 0 0 1px var(--line)}
:root[data-panels="flat"] .dropmenu,
:root[data-panels="flat"] .modal{box-shadow:0 0 0 1px var(--line-strong),0 8px 24px rgba(0,0,0,.18)}

/* ---------- Paper (SCREEN ONLY) -----------------------------------------
   Exported and printed documents are always white. This changes what you look
   at while writing and nothing else — exports.js writes its own literal CSS. */
:root[data-paper="bright"]{--paper:#ffffff;--paper-ink:#161a22;--paper-line:#e3e6ec;--paper-rule:#eef0f4}
:root[data-paper="warm"]{--paper:#fbf7ef;--paper-ink:#1d1a14;--paper-line:#e6ded0;--paper-rule:#f0e9dc}
:root[data-paper="dim"]{--paper:#141a22;--paper-ink:#e4e7ee;--paper-line:#28303c;--paper-rule:#222a34}
:root[data-theme="dark"][data-paper="bright"]{--paper:#141b27;--paper-ink:#e3e7ee;--paper-line:#2a3242;--paper-rule:#222a38}
:root[data-theme="dark"][data-paper="warm"]{--paper:#1a1712;--paper-ink:#ece5d8;--paper-line:#332c22;--paper-rule:#2a241c}

/* ---------- Faithful vs Comfort -----------------------------------------
   Faithful: the sheet renders the DOCUMENT's own font, size and leading, so
   what is on screen is a preview of the file.
   Comfort: the on-screen reading experience is tuned independently — and the
   app says so, permanently, in the toolbar. A writer drafting at 1.2x on a
   short measure will otherwise misjudge length and paragraph rhythm. */
:root{
  /* REAL values, not zero-as-unset. These were --srf-measure:0 and
     --srf-leading:0, intended as "no value until appearance.js writes one" —
     but 0 IS a value, so every var(--srf-measure, 72ch) fallback below was
     dead code, and any state where the inline pair was absent rendered the
     writing surface at ZERO column width and ZERO line-height: words and
     lines overprinting into an unreadable smear (Alex's phone screenshot,
     2026-08-15, and any condensed desktop window in the same state). The
     defaults ARE the fallbacks the consumers always meant. */
  --srf-measure:72ch;--srf-scale:1;--srf-leading:1.7;
  --doc-face:"Times New Roman",Times,serif;--doc-pt:12pt;--doc-lead:2}
:root[data-sheetview="faithful"] .blk .bd{
  font-family:var(--doc-face);
  font-size:calc(var(--doc-pt)*1.34);   /* 12pt reads ~16px at 100% on screen */
  line-height:var(--doc-lead);
}
/* THE SHEET FILLS THE PANE — always, in both views (Alex, 2026-08-13). The
   writing surface is the most important thing on screen, and it used to stop
   at a cap (820px faithful, the measure in comfort) with the leftover pane
   sitting as dead space to its right; it now stretches and re-stretches as the
   outline, the side panel and the window come and go — the flex row already
   does that, the caps were what refused it.

   The MEASURE survives where it belongs: on the text. In comfort view the
   line length is still the person's measure setting — applied to the block
   bodies and centred inside the full sheet, so the paper spans the pane while
   the prose keeps a readable line. The Appearance slider keeps meaning. */
:root[data-sheetview="faithful"] .sheet{width:100%}
:root[data-sheetview="comfort"] .blk .bd{
  font-family:var(--doc-face);
  font-size:calc(16px*var(--srf-scale));
  line-height:var(--srf-leading, 1.7);
  max-width:var(--srf-measure,72ch);
  margin-left:auto;margin-right:auto;
}
:root[data-sheetview="comfort"] .sheet{width:100%}
.viewbadge{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-micro);
  font-weight:700;text-transform:uppercase;letter-spacing:.07em;
  padding:1px 6px;border-radius:999px;background:var(--amber-bg);
  color:var(--amber);border:1px solid var(--amber-line)}
:root[data-sheetview="faithful"] .viewbadge{display:none}

/* ---------- High contrast ------------------------------------------------
   Not a mood, a floor. Washes collapse to a left bar plus weight, so a selected
   row never depends on a tint that could be stacked below legibility. */
:root[data-contrast="high"]{
  --ink-3:var(--ink-2); --ink-4:var(--ink-2);
  --line:var(--line-strong); --line-2:var(--line-strong);
  --ac-wash:transparent;
}
:root[data-contrast="high"] .out-row.sel,
:root[data-contrast="high"] .cite-row.sel,
:root[data-contrast="high"] .nav-row.sel{
  background:transparent;box-shadow:inset 3px 0 0 var(--ac-fill);font-weight:700
}
:root[data-contrast="high"] :focus-visible{outline-width:3px}

/* ---------- Motion ------------------------------------------------------- */
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before{animation:none !important;transition:none !important}

/* ---------- Appearance settings UI --------------------------------------- */
.apr-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:var(--sp-6)}
.apr-card{border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--sp-6);
  cursor:pointer;background:var(--surface-2);text-align:left}
.apr-card:hover{border-color:var(--ac-edge)}
.apr-card.on{border-color:var(--ac-fill);box-shadow:inset 0 0 0 1px var(--ac-fill);background:var(--ac-wash)}
.apr-name{font-weight:660;font-size:var(--fs-ui)}
.apr-hint{font-size:var(--fs-cap);color:var(--ink-3);margin-top:2px;line-height:1.45}
.apr-mini{display:flex;height:34px;border-radius:4px;overflow:hidden;margin-bottom:var(--sp-5);
  border:1px solid var(--line)}
.apr-mini i{display:block;height:100%}
.apr-mini .m-rail{width:26%}
.apr-mini .m-body{flex:1 1 auto;position:relative}
.apr-mini .m-page{position:absolute;inset:5px 20% 5px 8%;border-radius:2px}
.apr-mini .m-dot{position:absolute;right:6px;top:6px;width:10px;height:5px;border-radius:2px}
.swatches{display:flex;flex-wrap:wrap;gap:var(--sp-4)}
.swatch{width:34px;height:34px;border-radius:999px;border:2px solid transparent;cursor:pointer;
  position:relative;padding:0}
.swatch.on{border-color:var(--ink);box-shadow:0 0 0 2px var(--panel) inset}
.seg{display:inline-flex;gap:4px;flex-wrap:wrap}
.contrastline{display:flex;align-items:center;gap:var(--sp-5);flex-wrap:wrap;
  font-size:var(--fs-ui);padding:var(--sp-5) 0}

/* ============================================================================
   OPUS BENCH branding
   Colours taken from the app icon: a rose-plum → slate gradient with a
   folded-paper mark in pale blue and pale rose. The pastels are used as
   SURFACES and facets only; anything carrying text derives a darker role, which
   is why the accent has five values rather than one.
   ========================================================================= */
:root{
  --opus-rose:#9a5360; --opus-plum:#705c71; --opus-slate:#4e6481; --opus-mid:#625f77;
  --mark-a:#a9bdd3;    /* the blue leaf  */
  --mark-b:#d2a3a8;    /* the rose leaf  */
}

/* Accent — derived from the icon, roles measured not sampled. */
:root[data-accent="opus"]{--ac-fill:#7d4250;--ac-fill-hover:#6d3944;--ac-on:#fff;--ac-ink:#7a3f4c;--ac-edge:#a86b73;--ac-wash:#f7edee}
:root[data-theme="dark"][data-accent="opus"]{--ac-fill:#d2a3a8;--ac-fill-hover:#dcb2b7;--ac-on:#22141a;--ac-ink:#e3bfc3;--ac-edge:#8a5c64;--ac-wash:#251a1e}
:root[data-accent="slate"]{--ac-fill:#42566f;--ac-fill-hover:#3a4c63;--ac-on:#fff;--ac-ink:#3a4c63;--ac-edge:#7b8ea8;--ac-wash:#eef1f6}
:root[data-theme="dark"][data-accent="slate"]{--ac-fill:#a9bdd3;--ac-fill-hover:#bbcbde;--ac-on:#111a24;--ac-ink:#c0cee1;--ac-edge:#5b6e88;--ac-wash:#171e29}

/* ---------- --ob-*: the suite's own hue ----------------------------------
   THE CORNER RULE, IN COLOUR. The icon's gradient runs rose to slate, and the
   two ends now mean something: SLATE is Opus Bench — the landing page, the
   platform controls in the top right, bookmarks, the console — and ROSE is the
   app you happen to be in. Walk from Stylus into Remit and the slate does not
   move; that is the point of it. It is the same reasoning as the corner rule
   itself: what belongs to the suite looks identical everywhere, and what
   belongs to an app is free to differ.

   DELIBERATELY NOT UNDER [data-accent]. --ac-* is the person's choice for the
   app they are writing in, and they may set it to Forest. --ob-* is identity
   and must not follow, for the same reason the four app marks sit outside the
   token system entirely: identity does not adapt to preference.

   DERIVED FROM THE SLATE LEAF, NOT SAMPLED FROM IT — the same rule the rose
   accent follows, and for the same reason. The mark's slate (#4e6481) is a
   mid-tone because it is a shape in a logo, not a colour anything is read
   against; used directly it gives an icon that reads grey at 18px and a fill
   that fails against white. Hue is kept and saturation lifted, so it is
   recognisably the mark's blue and legible at control sizes. Every pair below
   is measured, not judged. */
:root{
  --ob-fill:#2f5686; --ob-fill-hover:#274a75; --ob-on:#ffffff;
  --ob-ink:#2c5180;  --ob-edge:#7f9dc4;       --ob-wash:#eef3fa;
}
:root[data-theme="dark"]{
  --ob-fill:#8fb6e8; --ob-fill-hover:#a4c4ed; --ob-on:#0d1826;
  --ob-ink:#a9c8f0;  --ob-edge:#4d6b96;       --ob-wash:#141d2a;
}
/* Must stay AFTER the dark block: equal specificity, so source order decides.
   Collapses for the same reason --ac-wash does — a tint may never be the only
   thing carrying a state. */
:root[data-contrast="high"]{--ob-wash:transparent}

/* The rail carries the icon's gradient, at the icon's own angle. Nav ink is
   lifted to #f5f0f1 so it clears 4.5:1 at the ROSE corner, which is the
   darkest-to-text point of the ramp — checking only the middle would ship a
   sidebar that goes illegible at one end. */
:root[data-chrome="opus"]{
  --nav-fill:var(--opus-plum); --nav-edge:#3d3145;
  --nav-ink:#f5f0f1; --nav-ink-dim:#d3c2c8;
}
:root[data-chrome="opus"] #sidebar{
  background:linear-gradient(200deg,var(--opus-slate) 0%,var(--opus-mid) 38%,
             var(--opus-plum) 66%,var(--opus-rose) 100%);
}
:root[data-chrome="opus"] .nav-row.sel{
  background:rgba(255,255,255,.20);border-color:rgba(255,255,255,.30);color:#fff
}
:root[data-chrome="opus"] .nav-row:hover{background:rgba(255,255,255,.13);color:#fff}
:root[data-chrome="opus"] .nav-mark{background:none}
:root[data-chrome="opus"] .nav-foot{border-top-color:rgba(255,255,255,.22)}
:root[data-theme="dark"][data-chrome="opus"] #sidebar{
  background:linear-gradient(200deg,#243040 0%,#241f2c 40%,#2e2029 72%,#3a2029 100%);
}
:root[data-theme="dark"][data-chrome="opus"]{--nav-ink:#efe6e8;--nav-ink-dim:#b8a6ad}
.nav-mark svg{display:block}

/* ---------- Viewer panes, echoing the folded-paper mark -------------------
   Each pane header carries a two-tone leading edge — blue leaf, rose leaf —
   so a stack of viewers reads as a set of folded sheets rather than as
   undifferentiated boxes. Purely a top border: no tint sits under any text. */
.pane-bar{position:relative}
.pane-bar::before{
  content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--mark-a) 0 50%,var(--mark-b) 50% 100%);
  opacity:.85;
}
.pane-head{position:relative}
.pane-head::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;
  background:linear-gradient(90deg,var(--mark-a),var(--mark-b));
}
/* The pane the editor's section is showing gets the mark at full strength. */
.wp-sec.here .wp-head{box-shadow:inset 3px 0 0 var(--ac-fill)}

/* The writing sheet gets the same folded edge along its top, so the page and
   the viewers read as the same family of object.

   This used to be `overflow:hidden` purely so the 3px edge would follow the
   sheet's rounded corners. That cost two real things: it made the sheet its own
   scrollport, which silently rendered the sticky section header in the
   whole-document view inert, and it clipped the per-paragraph ⋯/💬 gutter (which
   sits at left:-38px) once the sheet's side padding shrinks on a narrow screen.
   Rounding the pseudo-element itself buys the same look for neither price. */
.sheet{position:relative}
.sheet::before{
  content:"";position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,var(--mark-a) 0 42%,var(--mark-b) 58% 100%);
  border-radius:8px 8px 0 0;
  opacity:.9;
}
:root[data-panels="flat"] .sheet::before{opacity:.7}

/* Review workbench + citation detail get the same treatment, so every
   "window" in the app is recognisably part of one set. */
.cite-detail .cd-head{position:relative}
.cite-detail .cd-head::before{
  content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--mark-a),var(--mark-b));
}
.rv-form .card:first-child{position:relative}
.mrow{position:relative}
.mrow::before{
  content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--mark-a) 0 50%,var(--mark-b) 50% 100%);
  opacity:.55;
}
.mrow.conflict::before{background:var(--red);opacity:.9}

/* Boot screen wears the mark too, so the first thing you see is the app. */
.boot-card{border-top:3px solid transparent;
  border-image:linear-gradient(90deg,var(--mark-a),var(--mark-b)) 1}
.boot-title{color:var(--ac-ink)}

/* A seat count is two or three digits in a table cell; the browser default
   stretches a number input to fill it and the stepper crowds the value out. */
/* Qualified by type on purpose. The base rule is `input[type="number"] …
   {width:100%}` — an element plus an attribute, which outweighs a bare class —
   so `.adm-seats{width:66px}` lost silently and every seat box stretched to
   215px, taking the column with it. Same family as the dead `--r-sm` and the
   `:first-of-type` trap: a rule that reads correctly and never applies. */
input[type="number"].adm-seats{width:66px}

/* The account corner in the app's own top bar. Same controls, same place and
   the same classes as the landing page's — reusing .hub-icbtn / .hub-me is the
   point, because two surfaces of one product drifting apart on where your face
   lives is how a suite starts feeling like stapled-together apps. */
.tb-acct{display:flex;align-items:center;gap:var(--sp-3);margin-left:auto;flex:0 0 auto}
/* The topbar corner is denser than the landing page's, so the same three
   controls step down together — 30px against a 30px avatar, keeping the
   one-size rule that makes them read as peers. */
.tb-acct .hub-icbtn{width:30px;height:30px}
.tb-acct .hub-icbtn svg{width:18px;height:18px}
/* .tb-right already claims margin-left:auto on some screens; the corner has to
   sit outside it, so it gets its own auto and a left gutter when both appear. */
.tb-right + .tb-acct{margin-left:var(--sp-6)}

/* The rail's mark is the app's real icon now, and a button — it is the way back
   up to the suite. */
.nav-mark-btn{background:transparent;border:0;padding:0;cursor:pointer;display:flex;
  border-radius:7px;line-height:0}
.nav-mark-btn:hover{box-shadow:0 0 0 3px var(--ac-wash)}
.nav-mark-btn:focus-visible{outline:2px solid var(--ac-edge);outline-offset:2px}

/* A hairline "or" between two ways of doing the same thing. */
.hu-orbar{display:flex;align-items:center;gap:var(--sp-6);margin:var(--sp-8) 0 var(--sp-6);
  color:var(--ink-3);font-size:var(--fs-cap);letter-spacing:.04em;text-transform:uppercase}
.hu-orbar::before,.hu-orbar::after{content:"";flex:1 1 auto;height:1px;background:var(--line)}

/* App grants in the roster and in the person's card. */
.hu-apps{white-space:nowrap}
.hu-appchip{display:inline-flex;margin-right:3px;vertical-align:middle}
.hu-appsfld{margin-top:var(--sp-8)}
.hu-appopt{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-3) var(--sp-4);
  border-radius:var(--radius-sm);cursor:pointer}
.hu-appopt:hover{background:var(--surface-hover)}
.hu-appopt.locked{opacity:.7;cursor:default}
.hu-appopt .hint{margin-left:auto}

/* The rail's four verb groups (Write / Edit / Cite / Review). A heading above
   the sections, not another row — it names an activity, and nothing about it is
   clickable. */
.nav-group{
  font-size:var(--fs-cap);font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  /* Brighter than the section headings beneath it, not dimmer. The first
     version inherited --ink-4 at 75% and came out fainter than the labels it
     was meant to group, which reads as decoration rather than structure. The
     rail has its own ink (#8fa3cf for a section head); a group sits above that. */
  color:#c3d0ea;padding:var(--sp-7) var(--sp-5) var(--sp-2);
  border-top:1px solid rgba(255,255,255,.09);margin-top:var(--sp-4)
}
.nav-scroll > .nav-group:first-child,
.nav-sec:first-child + .nav-group{border-top:0;margin-top:0}
.nav-sec + .nav-group{margin-top:var(--sp-4)}
/* A paper inside a folder, and the folder itself. Keyed to `in-folder`, which
   means only the indent — `nav-sub` is the tagline style and dragged a filed
   paper's title into micro uppercase along with it. */
.nav-row.in-folder .lbl{padding-left:var(--sp-8)}
.nav-row.nav-folder .mk{font-size:var(--fs-sm)}
.nav-row.soon{opacity:.55}
.nav-row.soon .val{font-size:var(--fs-micro);letter-spacing:.06em;text-transform:uppercase}

/* Name and post-nominals share a row at roughly 4:1 — "Alex Hall, MD" is one
   fact with a short suffix, not two facts of equal weight. */
.prof-name .fld:first-child{flex:4 1 0}
.prof-name .fld:last-child{flex:1 1 0;min-width:90px}

/* The co-author directory and its picker. */
.orcid-mark{vertical-align:-2px}
.ca-pick{max-height:46vh;overflow:auto;border:1px solid var(--line);border-radius:var(--radius)}
.ca-pick-row{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:var(--sp-8);
  padding:var(--sp-6) var(--sp-8);border-bottom:1px solid var(--line-2);cursor:pointer}
.ca-pick-row:last-child{border-bottom:0}
.ca-pick-row:hover{background:var(--surface-hover)}
.ca-pick-row.on-paper{opacity:.55;cursor:default}
.ca-pick-name{min-width:0}

/* Live presence, above the writing columns. Patched in place every couple of
   seconds, so it must never be inside the editor — rebuilding the writing
   surface on that cadence would destroy the caret twice a second. */
.ed-presence{
  display:flex;align-items:center;gap:var(--sp-8);flex-wrap:wrap;
  padding:var(--sp-4) var(--sp-10);background:var(--ac-wash);
  border-bottom:1px solid var(--ac-edge);font-size:var(--fs-sm);color:var(--ink-2)
}
/* NOBODY HERE, NOTHING DRAWN. Working alone is the common case, and the strip
   was painting its rose wash and border across the top of the editor to say so
   — a band of colour whose entire meaning was "no news". It is emptied rather
   than removed when the last collaborator leaves (see .ed-presence above: it
   must not be inside the editor, so it is patched in place), so :empty is what
   "alone" looks like in the DOM. */
.ed-presence:empty{display:none}
/* Overlapping discs: one line however many people are here, where a sentence
   each wrapped at five and pushed the writing surface down every two seconds.
   The ring is the strip's own background, so the overlap reads as a stack. */
.pres-bub{position:relative;flex:0 0 auto;width:24px;height:24px;padding:0;border:0;
  border-radius:999px;cursor:pointer;overflow:hidden;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--fs-micro);font-weight:700;letter-spacing:.02em;
  box-shadow:0 0 0 2px var(--ac-wash);transition:transform .12s ease}
.pres-bub + .pres-bub{margin-left:-6px}
.pres-bub img{width:100%;height:100%;object-fit:cover;display:block}
.pres-bub:hover,.pres-bub:focus-visible{z-index:2;transform:translateY(-1px)}
/* Typing right now, rather than just reading, gets the accent ring. */
.pres-bub.editing{box-shadow:0 0 0 2px var(--ac-wash),0 0 0 3px var(--ac-edge)}
.pres-more{color:var(--ink-3);font-weight:600;font-size:var(--fs-cap);margin-left:var(--sp-4)}

/* ---------- The landing page ---------------------------------------------
   A full surface over the app, not a screen inside it: the suite is a level
   above any one app, and drawing it inside the writing app's chrome would say
   the opposite. z-index sits ABOVE the app and its sidebar (60) and BELOW the
   sign-in gate (400) — an expired session must cover the landing page, not
   appear under it — and far below the modal layer, because every dialog it
   opens is an ordinary MS.dialog.

   Type: the two display sizes are DERIVED from --fs-lead rather than written as
   pixels, so Compact and Roomy still move them. A raw px here would silently
   opt the landing page out of the density setting. */
.hub{
  position:fixed;inset:0;z-index:300;background:var(--bg);color:var(--ink);
  /* Same reserved gutter as #content — see the note there. The landing page
     centres its tiles too, so it shifts for the same reason. */
  overflow:auto;scrollbar-gutter:stable;display:flex;flex-direction:column;
  --hub-h:calc(var(--fs-lead) + 5px);
  --hub-tile:calc(var(--fs-lead) + 1px);
}
.hub-bar{
  position:sticky;top:0;z-index:2;flex:0 0 auto;display:flex;align-items:center;
  gap:var(--sp-8);padding:var(--sp-6) var(--sp-12);background:var(--panel);
  border-bottom:1px solid var(--line)
}
.hub-brand{display:flex;align-items:center;gap:var(--sp-5)}
.hub-brand-name{font-size:var(--fs-lead);font-weight:680;letter-spacing:-.01em}
/* .hub-bar-right / .hub-icbtn / .hub-bell / .hub-bell-n / .hub-me / .hub-av
   now live in css/corner.css, which this page links FIRST — one definition
   worn by the landing page, Stylus, the console and Portfolio alike. They
   were duplicated here, and because no page ever loaded both files the two
   copies never fought, they just drifted: 12 computed properties apart by
   the time it was measured. What stays in this file is what is genuinely
   this page's — .tb-acct's denser sizing, .hub-pop-id, and the phone
   override, which beats the base only by source order. */

/* What is waiting. Wider than the account popover because every row is a
   sentence, and capped so that a long list scrolls inside the panel rather than
   running off the bottom of the window. */
/* .hub-pop.hub-inbox, NOT .hub-inbox. `.hub-pop` sets width:250px and is
   written 200 lines BELOW this, so at equal specificity it wins on source order
   and the panel came out too narrow for its own sentences — every manuscript
   title wrapped to four lines. Two same-specificity regressions have shipped
   from this file for exactly this reason; the fix is to out-specify rather than
   to rely on where the rule happens to sit. */
.hub-pop.hub-inbox{width:340px;max-width:calc(100vw - 16px)}
.hub-inbox-h{
  padding:var(--sp-8) var(--sp-10) var(--sp-5);font-weight:680;
  border-bottom:1px solid var(--line-2)
}
.hub-inbox-empty{padding:var(--sp-12) var(--sp-10);color:var(--ink-3);line-height:1.5}
.hub-inbox-list{max-height:min(60vh,420px);overflow:auto;padding:var(--sp-3)}
.hub-inbox-row{
  display:flex;align-items:flex-start;gap:var(--sp-6);width:100%;text-align:left;
  background:none;border:0;padding:var(--sp-6) var(--sp-6);border-radius:var(--radius-sm);
  cursor:pointer;font:inherit;color:inherit
}
.hub-inbox-row:hover{background:var(--surface-hover)}
.hub-inbox-row:focus-visible{outline:2px solid var(--ob-edge);outline-offset:-2px}
.hub-inbox-ic{display:flex;color:var(--ob-ink);flex:0 0 auto;margin-top:1px}
.hub-inbox-txt{flex:1 1 auto;min-width:0}
.hub-inbox-l{display:block;font-weight:600;line-height:1.35}
.hub-inbox-s{display:block;font-size:var(--fs-sm);color:var(--ink-3);margin-top:1px}
.hub-inbox-at{flex:0 0 auto;font-size:var(--fs-cap);color:var(--ink-4);margin-top:2px}

.hub-main{flex:1 1 auto}
.hub-wrap{max-width:1120px;margin:0 auto;padding:var(--sp-16) var(--sp-12) 64px}
.hub-err{margin-bottom:var(--sp-12)}

.hub-sec{margin-bottom:var(--sp-16)}
/* min-height is the height of the tallest thing a heading may CARRY (the 24px
   .hub-h-act button), stated on every heading rather than left to whichever one
   happens to hold a control. .hub-cols is two independent columns, so a heading
   4px taller than the one beside it walks that whole column's rows out of step
   with its neighbour — which is exactly what adding the switcher did. */
.hub-h{
  display:flex;align-items:center;gap:var(--sp-5);margin:0 0 var(--sp-10);
  min-height:24px;
  font-size:var(--hub-h);font-weight:700;letter-spacing:-.015em
}
.hub-h svg{color:var(--ob-ink);flex:0 0 auto}

/* The app marks. A rounded square with its own gradient — product identity,
   deliberately outside the accent-token system, because these are four logos
   that must look the same in both themes rather than five roles that adapt. */
.app-ic{display:inline-flex;flex:0 0 auto;line-height:0}
.app-ic img{display:block;width:100%;height:100%;object-fit:contain}

/* Two up, not three. minmax(330px) gave three columns at 1280 and left the
   fourth app alone on a second row looking like an afterthought; 420px holds a
   2×2 grid at every desktop width and collapses to one on a narrow window. */
/* align-items:start, or grid stretches every card in a row to the tallest —
   so expanding one tile inflates the one beside it into a tall empty box that
   looks broken. Only visible once the tiles could differ in height. */
/* auto-FILL, not auto-fit. auto-fit COLLAPSES the tracks nothing landed in, so
   with one app that tile stretched across the whole row and the suite looked
   like a different product depending on how many apps you happened to hold. The
   tracks stay whether or not they are filled, so a tile is the same size at one
   app as at four and they fill 1=top-left, 2=top-right, 3=bottom-left,
   4=bottom-right, wrapping the same way as more are added. */
.hub-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(420px,1fr));
  gap:var(--sp-12);align-items:start}
.hub-tile{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--sp-12);display:flex;flex-direction:column;gap:var(--sp-8);box-shadow:var(--shadow)
}
/* A tile for something that does not exist yet reads as recessed, not broken:
   the card steps back a surface and the mark loses its shadow. Dimming the
   whole card would take the description with it, and the description is the
   only reason the tile is worth drawing at all. */
.hub-tile.soon{background:var(--surface-2);box-shadow:none}
.hub-tile.soon .app-ic{opacity:.55;filter:saturate(.55)}

/* CONDENSED BY DEFAULT. The tile is a row — mark, name, and Launch hard against
   the right edge opposite the mark — and the description is one click down.
   Padding tightens because a one-line row in card padding reads as a card
   waiting for content that never arrives. */
/* Bottom padding is smaller than the top on purpose: the chevron block sits in
   it, so the two have to be read together. Trimmed until the air above the
   header row and the air below it measure the same. */
.hub-tile{padding:var(--sp-8) var(--sp-10) var(--sp-3);gap:0}
.hub-tile-head{
  display:flex;align-items:center;gap:var(--sp-8);width:100%;
  background:none;border:0;padding:0;font:inherit;color:inherit;text-align:left;
  cursor:pointer
}
.hub-tile-head:focus-visible{outline:2px solid var(--ob-edge);outline-offset:3px;border-radius:var(--radius-sm)}
.hub-tile-id{min-width:0;flex:1 1 auto}
.hub-tile-name{font-size:var(--hub-tile);font-weight:680;letter-spacing:-.01em}
.hub-tile-tag{font-size:var(--fs-cap);color:var(--ink-3);letter-spacing:.05em;
  text-transform:uppercase;margin-top:1px}

/* Launch: narrow, fixed right, and the SUITE's blue rather than the app accent —
   opening an app is an Opus Bench act and looks the same on every tile. */
.hub-btn-go{
  flex:0 0 auto;margin-left:auto;padding:7px 18px;font-weight:600;
  background:var(--ob-fill);border-color:var(--ob-fill);color:var(--ob-on)
}
.hub-btn-go:hover:not([disabled]){background:var(--ob-fill-hover);border-color:var(--ob-fill-hover)}
.hub-btn-go[disabled]{opacity:.45;cursor:default}

/* The only chevron on the card: centred, and tucked toward the bottom edge
   without reaching it. The glyph stays small and the button around it does not —
   padding is the hit target, or this is a 14px thing to hit — so the padding
   above the glyph is what holds it off the header and the negative bottom
   margin is what pulls it toward the edge, leaving a couple of px of air.

   The card's own bottom padding is cut to --sp-4 (above) so that, with this
   block sitting in it, the space above the header row and the space below it
   read as equal. aria-hidden + tabindex -1 because the header already exposes
   the toggle to the keyboard and a screen reader does not need it twice. */
.hub-tile-more{
  display:flex;align-items:center;justify-content:center;
  margin:0 auto -4px;padding:0 18px 2px;
  background:none;border:0;cursor:pointer;color:var(--ink-4);line-height:0
}
.hub-tile-more:hover{color:var(--ob-ink)}
.hub-tile-more svg{width:14px;height:14px;transition:transform .16s ease}
.hub-tile.open .hub-tile-more svg{transform:rotate(180deg)}

/* Collapsed is the DEFAULT STATE IN CSS, not a class that has to be applied —
   a tile that paints expanded and then snaps shut on the next frame is what you
   get from doing this the other way round. */
.hub-tile-body{display:none;padding-top:var(--sp-6)}
.hub-tile.open .hub-tile-body{display:block}
.hub-tile-blurb{margin:0 0 var(--sp-8);color:var(--ink-2);line-height:1.6}
.hub-btn-more{color:var(--ob-ink);font-weight:600;padding:6px 14px}
.hub-chip{
  display:inline-flex;align-items:center;font-size:var(--fs-tag);font-weight:650;
  letter-spacing:.03em;padding:1px 7px;border-radius:999px;margin-top:2px;
  background:var(--ac-wash);color:var(--ac-ink);border:1px solid var(--ac-edge)
}

.hub-cols{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-16)}
.hub-rows{display:flex;flex-direction:column;gap:var(--sp-6)}
.hub-row{
  display:flex;align-items:center;gap:var(--sp-8);width:100%;text-align:left;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--sp-8) var(--sp-10);cursor:pointer;font:inherit;color:var(--ink)
}
.hub-row:hover{background:var(--surface-hover);border-color:var(--line-strong)}
.hub-row-ic{display:flex;color:var(--ob-ink);flex:0 0 auto}
.hub-row-lbl{font-weight:600}
.hub-row-meta{margin-left:auto;color:var(--ink-3);font-size:var(--fs-sm);white-space:nowrap}
.hub-note{margin-top:var(--sp-6);color:var(--ink-3);font-size:var(--fs-sm)}

/* An action at the far end of a section heading: the same icon-button language
   as the platform controls in the top right corner, at heading scale. Kept
   SHORTER than the heading's own line box (a ~21px face lands around 26px) so
   that adding it does not push this column's rows a couple of pixels out of
   step with the column beside it. The icon colour is stated through .hub-h
   because `.hub-h svg` above matches this button's icon at equal specificity,
   and the winner would otherwise be whichever rule was written last. */
.hub-h-act{
  margin-left:auto;display:flex;align-items:center;justify-content:center;
  width:24px;height:24px;padding:0;border-radius:var(--radius-sm);
  border:1px solid transparent;background:none;color:var(--ink-3);cursor:pointer
}
.hub-h .hub-h-act svg{width:18px;height:18px;display:block;color:inherit}
.hub-h-act:hover{background:var(--ob-wash);color:var(--ob-fill);border-color:var(--ob-edge)}
.hub-h-act:focus-visible{outline:2px solid var(--ob-edge);outline-offset:2px}

/* The team, in the account popover, under the plan chip. A line of fact in the
   identity block — not a row in the actions below it, which is where switching
   lives. */
.hub-pop-team{margin-top:var(--sp-4);font-size:var(--fs-sm);color:var(--ink-3);
  word-break:break-word}

/* A value the person may read but not set. Deliberately NOT a disabled input:
   a greyed box still looks like a box, so it invites a click and then refuses
   it. This reads as what it is — a fact about the account. */
.prof-ro{
  padding:9px 0;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}

/* The initials picker. Real discs, not a dropdown of labels: "AJH" against
   "AH" is a difference you judge by looking at it. */
.mono-row{display:flex;gap:var(--sp-6);flex-wrap:wrap}
.mono-opt{
  display:flex;flex-direction:column;align-items:center;gap:4px;
  padding:var(--sp-5) var(--sp-6);background:none;cursor:pointer;font:inherit;
  border:1px solid var(--line);border-radius:var(--radius-sm);color:var(--ink-3)
}
.mono-opt:hover{border-color:var(--line-strong);background:var(--surface-hover)}
.mono-opt.on{border-color:var(--ob-edge);background:var(--ob-wash);color:var(--ob-ink)}
.mono-opt:focus-visible{outline:2px solid var(--ob-edge);outline-offset:2px}
.mono-lbl{font-size:var(--fs-cap);white-space:nowrap}

/* First / MI / Last. The middle initial is one character, so it gets one
   character's worth of box — a full-width third column would say it is as
   important as the other two. */
.row.ui-name{display:flex;gap:var(--sp-6);align-items:flex-end}
.row.ui-name .fld:nth-child(1),.row.ui-name .fld:nth-child(3){flex:1 1 0;min-width:0}
.row.ui-name .fld:nth-child(2){flex:0 0 64px}

/* Avatars. Solid disc in the person's own colour with the PAIRED tint as ink —
   --au-N and --au-N-bg are guaranteed 4.5:1 against each other in both themes,
   which white is not: the dark palette brightens --au-1 to #7fb0f5, and white
   on that is about 2:1. (The 20px .avatar chip in the rail still hardcodes
   #fff and has exactly this problem; it is not this surface's to fix.) */

/* The account popover. Its own thing rather than a dropmenu: it shows a face
   and three lines of identity before it shows any action, and a list of rows
   cannot say who you are. */
.hub-pop{
  position:fixed;z-index:7450;width:250px;background:var(--tb-menu-bg);
  border:1px solid var(--line-strong);border-radius:var(--radius);
  box-shadow:var(--shadow-lg);overflow:hidden
}
.hub-pop-id{padding:var(--sp-12) var(--sp-10);text-align:center;
  border-bottom:1px solid var(--line-2)}
.hub-pop-id .hub-av{margin-bottom:var(--sp-6)}
.hub-pop-name{font-weight:680}
.hub-pop-mail,.hub-pop-inst{font-size:var(--fs-sm);color:var(--ink-3);word-break:break-word}
.hub-pop-plan{margin-top:var(--sp-5)}
.hub-pop-acts{padding:var(--sp-3)}
.hub-pop-act{
  display:flex;align-items:center;gap:var(--sp-8);width:100%;text-align:left;
  background:transparent;border:0;border-radius:var(--radius-sm);cursor:pointer;
  padding:var(--sp-5) var(--sp-6);font:inherit;color:var(--ink)
}
.hub-pop-act:hover{background:var(--surface-hover)}
.hub-pop-act svg{color:var(--ink-3);flex:0 0 auto}

.hub-learn-head{display:flex;align-items:center;gap:var(--sp-8);margin-bottom:var(--sp-8)}
.hub-learn-name{font-size:var(--fs-lead);font-weight:680}
.hub-learn-tag{font-size:var(--fs-cap);color:var(--ink-3);letter-spacing:.05em;text-transform:uppercase}
.hub-learn p{line-height:1.6;color:var(--ink-2)}

.hub-prof{display:flex;gap:var(--sp-16);align-items:flex-start}
.hub-prof-pic{flex:0 0 auto;text-align:center}
.hub-prof-picacts{display:flex;flex-direction:column;gap:var(--sp-3);margin-top:var(--sp-6)}
.hub-prof-fields{flex:1 1 auto;min-width:0}

/* ---------- The Users screen (inside the landing page) -------------------- */

.hu-head{display:flex;align-items:center;gap:var(--sp-8);margin-bottom:var(--sp-10)}
.hu-headtxt{min-width:0}
.hu-sub{font-size:var(--fs-sm);color:var(--ink-3);margin-top:1px}
.hu-invite{padding:8px 14px;font-weight:600}
.hu-scopebar{margin-bottom:var(--sp-8)}
.hu-scope{font-size:var(--fs-sm);color:var(--ink-3);display:inline-flex;align-items:center;gap:var(--sp-5)}
/* The scope reads as part of the sentence it sits in — "Showing <name>" — so
   the name takes the page's ink and weight while the word before it stays
   secondary. The chevron is the only thing saying "there are others", which is
   why the control still needs a border on hover: without one it is a heading
   that happens to open a menu. */
.hu-scopebtn{
  display:inline-flex;align-items:center;gap:var(--sp-3);
  font:inherit;font-size:var(--fs-base);font-weight:600;color:var(--ink);
  background:none;border:1px solid transparent;border-radius:var(--radius-sm);
  padding:3px var(--sp-4);margin:-3px 0;cursor:pointer
}
.hu-scopebtn svg{color:var(--ink-3);flex:0 0 auto}
.hu-scopebtn:hover{background:var(--ob-wash);border-color:var(--ob-edge);color:var(--ob-fill)}
.hu-scopebtn:hover svg{color:var(--ob-fill)}
.hu-scopebtn:focus-visible{outline:2px solid var(--ob-edge);outline-offset:2px}
.hu-back{
  width:34px;height:34px;border-radius:999px;border:1px solid var(--line);
  background:var(--panel);color:var(--ink-2);cursor:pointer;font-size:var(--fs-lead);
  display:grid;place-items:center;font-family:inherit;line-height:1
}
.hu-back:hover{background:var(--surface-hover);color:var(--ink)}
.hu-title{margin:0;font-size:var(--hub-h);font-weight:700;letter-spacing:-.015em}
.hu-head-right{margin-left:auto;display:flex;align-items:center;gap:var(--sp-8)}
.hu-seats{font-size:var(--fs-sm);color:var(--ink-3)}
.hu-plusic{font-weight:700}

.hu-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;box-shadow:var(--shadow)}
.hu-bar{display:flex;gap:var(--sp-8);padding:var(--sp-8) var(--sp-10);background:var(--surface-2);
  border-bottom:1px solid var(--line)}
.hu-search{flex:1 1 auto;display:flex;align-items:center;gap:var(--sp-5);
  background:var(--input-bg);border:1px solid var(--input-line);
  border-radius:var(--radius-sm);padding:0 var(--sp-8);color:var(--ink-4)}
.hu-search input{flex:1 1 auto;border:0;background:transparent;padding:9px 0;
  font:inherit;color:var(--ink);outline:none;min-width:0}
.hu-filter{flex:0 0 auto}
.hu-filter.on{border-color:var(--ac-edge);color:var(--ac-ink)}
.hu-fcount{display:inline-grid;place-items:center;min-width:16px;height:16px;padding:0 4px;
  border-radius:999px;background:var(--ac-fill);color:var(--ac-on);font-size:var(--fs-micro);
  font-weight:700}

/* A roster is read at a glance and clicked once, so it is deliberately roomier
   than the app's dense working grids: a 40px face, a tall row, and real space
   either side. This is the one table in the product that is not trying to fit
   as much as possible on screen. */
.hu-table{width:100%;border-collapse:collapse;font-size:var(--fs-md)}
.hu-table th{
  text-align:left;font-size:var(--fs-cap);font-weight:700;color:var(--ink-3);
  letter-spacing:.04em;text-transform:uppercase;padding:var(--sp-8) var(--sp-12);
  border-bottom:1px solid var(--line)
}
.hu-table td{padding:var(--sp-8) var(--sp-12);border-bottom:1px solid var(--line-2);height:64px}
.hu-role{color:var(--ink-2)}
.hu-row{cursor:pointer}
.hu-row:hover td{background:var(--surface-hover)}
/* The row you last opened stays marked, so closing the card does not lose your
   place in a list of thirty people. */
.hu-row.sel td{background:var(--ac-wash)}
.hu-row.sel td:first-child{box-shadow:inset 3px 0 0 var(--ac-fill)}
.hu-row.off td{opacity:.62}
/* The real control in the row: a button, so it can be tabbed to and pressed.
   The <tr> is a mouse convenience on top of it, not the only way in. */
.hu-person{display:flex;align-items:center;gap:var(--sp-8);width:100%;text-align:left;
  background:transparent;border:0;padding:0;margin:0;font:inherit;color:inherit;cursor:pointer;
  border-radius:var(--radius-sm)}
.hu-person:focus-visible{outline:2px solid var(--ac-edge);outline-offset:2px}
.hu-name{font-weight:600}
.hu-mail{color:var(--ac-ink)}
.hu-empty{padding:var(--sp-16);text-align:center;color:var(--ink-3)}

.hu-pill{
  display:inline-flex;align-items:center;font-size:var(--fs-cap);font-weight:650;
  padding:2px 11px;border-radius:999px;border:1px solid
}
.hu-pill.active{color:var(--green);background:var(--green-bg);border-color:var(--green-line)}
.hu-pill.pending{color:var(--amber);background:var(--amber-bg);border-color:var(--amber-line)}
.hu-pill.deactivated,.hu-pill.suspended{color:var(--ink-3);background:var(--surface-2);border-color:var(--line-strong)}
/* The staff mark in a customer's roster. Accent-toned, not a status colour —
   it qualifies the role beside it rather than reporting a state, and it must
   read in both themes, so it uses role tokens like everything else. */
.hu-pill.staff{color:var(--ac-ink);background:var(--ac-wash);border-color:var(--ac-edge)}
.hu-staffnote{margin:0 0 12px}

.hu-foot{display:flex;align-items:center;justify-content:flex-end;gap:var(--sp-8);
  padding:var(--sp-8) var(--sp-12);font-size:var(--fs-sm);color:var(--ink-3)}
.hu-per{display:flex;align-items:center;gap:var(--sp-5);white-space:nowrap}
.hu-pg{
  width:26px;height:26px;border-radius:var(--radius-sm);border:1px solid var(--line);
  background:var(--panel);color:var(--ink-2);cursor:pointer;font-family:inherit;line-height:1
}
.hu-pg:hover:not([disabled]){background:var(--surface-hover);color:var(--ink)}
.hu-pg[disabled]{opacity:.4;cursor:default}

/* The filter popover is checkboxes, not actions: several can be on at once and
   picking one must not close it, which is exactly what U.menu does. */
.hu-fpop{
  position:fixed;z-index:7450;width:210px;background:var(--tb-menu-bg);
  border:1px solid var(--line-strong);border-radius:var(--radius);
  box-shadow:var(--shadow-lg);padding:var(--sp-6)
}
.hu-fgrp + .hu-fgrp{margin-top:var(--sp-6);padding-top:var(--sp-6);border-top:1px solid var(--line-2)}
.hu-fh{font-size:var(--fs-cap);font-weight:700;color:var(--ink-3);letter-spacing:.04em;
  text-transform:uppercase;padding:0 var(--sp-4) var(--sp-3)}
.hu-fopt{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-3) var(--sp-4);
  border-radius:var(--radius-sm);cursor:pointer}
.hu-fopt:hover{background:var(--surface-hover)}
.hu-fclear{margin-top:var(--sp-4);text-align:right}

.hu-info{display:flex;gap:var(--sp-16);align-items:flex-start}
.hu-info-pic{flex:0 0 auto}
.hu-info-fields{flex:1 1 auto;min-width:0}
/* The place suggestions. On <body> so it escapes the card's overflow, and
   fixed so it tracks the field it was opened under. */
.place-pop{
  position:fixed;z-index:7600;max-height:280px;overflow:auto;
  background:var(--tb-menu-bg);border:1px solid var(--line-strong);
  border-radius:var(--radius-sm);box-shadow:var(--shadow-lg);padding:var(--sp-2)
}
.place-opt{
  display:block;width:100%;text-align:left;background:none;border:0;
  padding:5px var(--sp-6);border-radius:var(--radius-sm);cursor:pointer;
  font:inherit;color:inherit;white-space:nowrap
}
.place-opt:hover,.place-opt.on{background:var(--surface-hover)}

/* Page one's folding blocks. The head is the whole bar so the target is big,
   and the twisty rotates rather than swapping glyph — same device as the
   viewer panes and the app tiles. */
.p1-head{cursor:pointer;user-select:none}
.p1-head:hover{background:var(--surface-hover)}
.p1-tw{display:inline-flex;align-items:center;color:var(--ink-4);line-height:0;
  transition:transform .16s ease;flex:0 0 auto;margin-right:var(--sp-3)}
.p1-tw svg{width:15px;height:15px}
.p1-tw.open{transform:rotate(90deg)}
.p1-card.shut .card-head{border-bottom:0}

/* Metrics: a value you may hide but never type. The tick is what prints, so it
   reads as a printing decision rather than as a setting. */
.p1-metrics{display:flex;flex-direction:column;gap:2px}
.p1-metric{display:flex;align-items:baseline;gap:var(--sp-6);padding:4px 6px;
  border-radius:var(--radius-sm);cursor:pointer}
.p1-metric:hover{background:var(--surface-hover)}
.p1-metric-l{font-weight:600;min-width:170px}
.p1-metric-v{color:var(--ink-2)}
.p1-metric.off .p1-metric-l,.p1-metric.off .p1-metric-v{color:var(--ink-4);
  text-decoration:line-through}
.p1-extra{align-items:flex-end}

/* The line-number gutter. Absolutely positioned inside the preview and
   aria-hidden: it is a reading aid, so it must never reach a copy, an export,
   or a screen reader working through the prose. Numbers every fifth line, the
   way a manuscript prints them — one on every line is a wall of digits. */
.pane .pv{position:relative}
.pane.lines-on .pv{padding-left:34px}
.pv-lines{position:absolute;inset:0 auto 0 0;width:28px;pointer-events:none}
.pv-line-n{
  position:absolute;right:0;font-size:10px;line-height:1;color:var(--ink-4);
  font-variant-numeric:tabular-nums;transform:translateY(2px)
}
.pane-mk{
  flex:0 0 auto;max-width:112px;font-size:var(--fs-cap);height:24px;padding:0 4px
}
.pane-ln{flex:0 0 auto;font-variant-numeric:tabular-nums;letter-spacing:-.03em}
.pane-ln.on{background:var(--ob-wash);color:var(--ob-ink);border-color:var(--ob-edge)}

/* Page one in the viewer pane. Centred like a printed title page rather than
   styled like the editor's cards — this pane is for reading what the journal
   will receive, and the whole reason it exists is that the editor's version is
   a form. */
.pv-title{padding:var(--sp-10) var(--sp-8)}
.pvt-title{font-size:var(--fs-lead);font-weight:700;line-height:1.35;text-align:center;
  margin-bottom:var(--sp-6)}
.pvt-run{text-align:center;font-size:var(--fs-sm);color:var(--ink-3);margin-bottom:var(--sp-8)}
.pvt-authors{text-align:center;line-height:1.7;margin-bottom:var(--sp-8)}
.pvt-affs{font-size:var(--fs-sm);color:var(--ink-2);line-height:1.6;
  margin-bottom:var(--sp-8)}
.pvt-affs sup{color:var(--ink-3)}
.pvt-foot{font-size:var(--fs-sm);color:var(--ink-2);line-height:1.6;
  border-top:1px solid var(--line-2);padding-top:var(--sp-6);margin-bottom:var(--sp-6)}
.pvt-kw{font-size:var(--fs-sm);color:var(--ink-2);margin-bottom:var(--sp-8);line-height:1.6}
.pvt-metrics{font-size:var(--fs-cap);color:var(--ink-4);border-top:1px solid var(--line-2);
  padding-top:var(--sp-5)}

.hu-info-status{margin-bottom:var(--sp-6)}
/* The suspension note. Set against the surface rather than left as loose text,
   because it is somebody's typed sentence sitting among generated labels and it
   has to read as quoted rather than as the interface talking. The left rule is
   the same device the notices use, at the weight of a fact rather than a
   warning — the pill above it is already carrying the alarm. */
.hu-info-why{
  margin-bottom:var(--sp-10);padding:var(--sp-5) var(--sp-8);
  border-left:2px solid var(--line-strong);background:var(--surface-2);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  color:var(--ink-2);line-height:1.5;word-break:break-word
}
.hu-pair{margin-bottom:var(--sp-10)}
.hu-pk{font-weight:700;font-size:var(--fs-sm)}
.hu-pv{color:var(--ink-2);word-break:break-word}
.hu-pv.mono{font-family:var(--mono);font-size:var(--fs-sm)}
.hu-pv.mail{color:var(--ac-ink)}
/* Destructive action to the left of the confirm pair, so "Deactivate" is never
   where a hurried click expects "Cancel". It is an outlined red button, not a
   filled one: it is not the action of the dialog, and .ghost on its own wins
   over .danger (later in the sheet, same specificity) and rendered it grey —
   a destructive control that looks like a disabled one. */
.hu-foot-left{margin-right:auto}
.btn.danger.ghost{background:transparent;color:var(--red);border-color:var(--red-line)}
.btn.danger.ghost:hover{background:var(--red-bg);color:var(--red)}

.hu-add-lead{margin:0 0 var(--sp-10);color:var(--ink-2)}
.hu-add-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius)}
.hu-add{width:100%;border-collapse:collapse;min-width:560px}
.hu-add th{text-align:left;font-size:var(--fs-cap);font-weight:700;color:var(--ink-3);
  letter-spacing:.04em;text-transform:uppercase;padding:var(--sp-5) var(--sp-6);
  border-bottom:1px solid var(--line);background:var(--surface-2)}
.hu-add td{padding:var(--sp-5) var(--sp-6);border-bottom:1px solid var(--line-2)}
.hu-add tr:last-child td{border-bottom:0}
.hu-add input,.hu-add select{width:100%}
.hu-add-del{width:38px}
.hu-trash{background:transparent;border:0;cursor:pointer;color:var(--ink-4);font-size:var(--fs-md);
  padding:var(--sp-3);border-radius:var(--radius-sm);line-height:1}
.hu-trash:hover:not([disabled]){background:var(--red-bg);color:var(--red)}
.hu-trash[disabled]{opacity:.3;cursor:default}
.hu-add-foot{display:flex;align-items:center;gap:var(--sp-8);margin-top:var(--sp-8)}
.hu-add-foot .hint{margin-left:auto}

/* ---------- Narrow windows and phones ------------------------------------
   Last in the sheet on purpose: these are overrides, and at equal specificity
   the later rule wins. Sitting them next to the sidebar rules meant
   `.tb-facts{display:none}` lost to the plain `.tb-facts` declared below it. */

/* The landing page is two columns of cards on a desktop and one everywhere
   else. The tile grid handles itself (auto-fit/minmax); Support and Team
   Settings do not, and side by side below 1000px they were 380px each. */
@media (max-width:980px){
  .hub-cols{grid-template-columns:1fr;gap:var(--sp-12)}
  .hub-prof,.hu-info{flex-direction:column;align-items:center}
  .hub-prof-fields,.hu-info-fields{width:100%}
}

/* The band between the phone breakpoint and a comfortable desktop had no
   treatment at all: the bar kept the full word/ref/table/figure counts AND the
   full action group, so once it was allowed to wrap it grew to three rows.
   Drop the counts first — they are ambient information, and the same numbers
   are on the section outline and in Details. */
@media (max-width:1000px){
  .tb-facts{display:none}
  .tb-sec{display:none}
}
@media (max-width:760px){
  /* The landing page on a phone: one tile per row, the two buttons stacked so
     neither is a 90px target, and the bar's seat count dropped — it is ambient,
     and the Add New User button is what has to survive. */
  .hub-wrap{padding:var(--sp-10) var(--sp-6) 48px}
  .hub-grid{grid-template-columns:1fr}
  .hub-tile-foot{flex-direction:column}
  .hub-btn-more,.hub-btn-go{flex:1 1 auto}
  .hu-seats{display:none}
  .hu-bar{flex-wrap:wrap}
  .hu-search{flex:1 1 100%}
  /* The roster keeps Name and Status on a phone. Email is the widest column and
     it is on the person's card one tap away; Role is a word the pill implies. */
  .hu-table td:nth-child(2),.hu-table th:nth-child(2),
  .hu-table td:nth-child(3),.hu-table th:nth-child(3){display:none}
  .hu-foot{flex-wrap:wrap;justify-content:space-between}
}

@media (max-width:760px){
  .tb{flex-wrap:wrap;row-gap:var(--sp-4)}
  .tb-nav{order:0;margin-right:var(--sp-4)}
  .tb-crumb{min-width:0;flex:1 1 0;order:1}
  .tb-sec{display:none}
  .tb-right{flex:1 1 100%;order:2;flex-wrap:wrap;justify-content:flex-start;gap:var(--sp-4)}
  .tb-facts{display:none}
  /* On a phone the bar has to stay one row. The view toggles are the ones to
     lose: Track and Marks are settings you set once, not controls you reach
     for mid-sentence, and both are reachable from Settings. What is left —
     Check, More, Export — is what you actually press. */
  .tb-right .tb-view{display:none}
  /* The carets cost a whole extra button row once touch targets are 40px
     tall. Tapping a button that opens a menu is self-evident anyway. */
  .tb-car{display:none}
  /* Smaller on a phone, but never wrapping: `white-space:normal` was written
     for the old two-line header, and inside the new baseline flex row a
     wrapping title in a squeezed item rendered ONE CHARACTER PER LINE — a
     370px-tall header spelling the title downwards (Alex's screenshot,
     2026-08-15). The title takes the slack and ellipsizes; min-width:0 is
     what lets a flex item actually shrink under its content. */
  .tb-name{font-size:var(--fs-md)}
  /* The crumb takes the WHOLE first row on a phone — otherwise the flex row
     satisfied itself by shrinking the title to zero width and the header
     showed DRAFT with no name at all. Two compact rows: the title (grown,
     truncating) with its stage beside it, then the actions row sitting
     right. */
  /* Basis leaves room for the 42px opener so ☰ and the title SHARE the first
     row; 100% pushed the opener onto a lonely row of its own. */
  .tb-crumb.tb-onerow{flex:1 1 calc(100% - 84px)}
  /* TWO ROWS ON A PHONE (Alex, 2026-08-16):

       ☰  Title
       ▤ DRAFT ..................... the actions

     Moving the whole-document button beside the title was right on a desktop
     and wrong here — that row already carries the opener and a title needing
     every pixel, so a button and a status word beside it cut the title to an
     ellipsis after four words.

     display:contents on the crumb is what makes this possible without a
     phone-only branch in the renderer: the crumb stops being a box and its
     children become items of the bar itself, so the title can take a full row
     while the button and the stage sit on the next one WITH the actions —
     which are the crumb's siblings and could never share a line with its
     insides otherwise. One markup, two layouts. */
  .tb-crumb.tb-onerow{display:contents}
  .tb-onerow .tb-name{order:1;flex:1 1 calc(100% - 84px);min-width:0;align-self:center}
  .tb-onerow .tb-wholebtn{order:2;margin-left:0}
  .tb-onerow .tb-mini{order:2}
  .tb-onerow .tb-stagelink{order:3}
  /* margin-left:auto rather than a spacer: the actions end the second row on
     the right, which is where an actions cluster belongs and where it already
     was before this header was restacked. */
  .tb-right{order:4;flex:0 0 auto;margin-left:auto;justify-content:flex-end}
  .save-ind span:nth-child(2){display:none}
  .sheet{padding:var(--sp-10) var(--sp-8)}
  .sheetwrap{padding:4px 4px 30vh}
  .citefoot{padding:0 var(--sp-6) var(--sp-2)}
  .abs-main{padding:var(--sp-6) var(--sp-6) 50px}
  .page{padding:var(--sp-8) var(--sp-6) 40px}
  .row{flex-direction:column;gap:0}
  .fld{flex:1 1 auto !important}

  /* The peer-review workbench is a 55/45 split. Both panes carry min-width:0,
     so the percentages hold all the way down and a phone got a 215px PDF beside
     a 176px form — neither usable. On a phone you are reading the paper OR
     writing the review, never both at once, so stack them and let the form own
     the screen; the PDF is still reachable by scrolling up to it. */
  .rvwrap{flex-direction:column}
  .rv-pdf{flex:0 0 auto;max-height:45vh}
  .rv-form{flex:1 1 auto;min-height:0}

  /* The search box was sharing a row with a 130px sort select and collapsed to
     about 44px — not enough to see what you typed. Give it its own row. */
  .cite-bar{flex-wrap:wrap}
  .cite-bar input[type=search]{flex:1 1 100%;order:-1}

  /* The 30vh runway below the sheet is there so the last paragraph of a long
     manuscript can sit mid-screen while you type. An abstract is one screen
     long, so the same runway just buries the Authors card under blank space. */
  .abs-main .sheetwrap{padding-bottom:0}
}
/* Touch only — gated on BOTH conditions so a desktop pointer is never
   inflated. Anything revealed by :hover has no equivalent under a finger. */
@media (hover:none) and (pointer:coarse){
  .nav-row,.btn,.btn.sm,.tab,.tb-nav,.nav-collapse{min-height:40px}
  .nav-row{padding-top:var(--sp-5);padding-bottom:var(--sp-5)}
  .blk-gut,.cf-row .btn,.pane-bar .btn{opacity:1}
}

/* ---------- Sign-in providers + admin -----------------------------------
   The "or" divider between the emailed link and the OAuth buttons, and the
   operator panel opened from Settings. */
.or-sep{display:flex;align-items:center;gap:var(--sp-5);margin:var(--sp-6) 0;color:var(--ink-4);
  font-size:var(--fs-cap)}
.or-sep::before,.or-sep::after{content:"";flex:1 1 auto;height:1px;background:var(--line)}
/* ---------- Opus Bench surfaces ------------------------------------------
   BLUE IS THE SUITE'S BUTTON. `.btn.primary` otherwise takes --ac-fill, which
   is the accent somebody picked for the app they WRITE in — so Administration
   and the Users page wore a different colour depending on a preference that has
   nothing to do with them. `.modal.ob` is the marker a platform dialog sets on
   itself; #hub is the landing page. Danger keeps its own red: "this destroys
   something" outranks "this belongs to the suite". */
.modal.ob .btn.primary,#hub .btn.primary,.appshell .btn.primary{
  background:var(--ob-fill);border-color:var(--ob-fill);color:var(--ob-on)
}
.modal.ob .btn.primary:hover:not([disabled]),#hub .btn.primary:hover:not([disabled]),
.appshell .btn.primary:hover:not([disabled]){
  background:var(--ob-fill-hover);border-color:var(--ob-fill-hover)
}
.modal.ob .btn:focus-visible,#hub .btn:focus-visible,
.appshell .btn:focus-visible{outline:2px solid var(--ob-edge);outline-offset:2px}
.modal.ob a,#hub a,.appshell a{color:var(--ob-ink)}
/* An app's front door is a SUITE surface, so its status notice takes the suite
   slate too — `.notice.info` is --blue, which in this theme is the app accent
   rose and reads as a warning here. */
.appshell .notice.info{border-left-color:var(--ob-fill);background:var(--ob-wash)}

/* THE TABS HAD NO CSS AT ALL — `.tab` and `.tab.on` were undefined, so four
   plain bordered buttons sat in a row with nothing to say which one you were
   looking at. A segmented control: one recessed track, the active tab raised
   out of it. */
.tabs{
  display:inline-flex;gap:2px;padding:3px;margin-bottom:var(--sp-10);
  background:var(--surface-2);border:1px solid var(--line);border-radius:9px
}
.tab{
  appearance:none;border:0;background:none;font:inherit;cursor:pointer;
  padding:6px 14px;border-radius:var(--radius-sm);color:var(--ink-2);
  font-weight:600;font-size:var(--fs-sm);white-space:nowrap
}
.tab:hover{background:var(--surface-hover);color:var(--ink)}
.tab.on{background:var(--panel);color:var(--ob-ink);box-shadow:var(--shadow)}
.tab:focus-visible{outline:2px solid var(--ob-edge);outline-offset:1px}

/* The operator search. It was a bare full-width box with no label and no icon,
   floating between the stat tiles and the table. */
.adm-search{
  display:flex;align-items:center;gap:var(--sp-5);margin:var(--sp-10) 0;
  border:1px solid var(--line-strong);border-radius:var(--radius-sm);
  padding:0 var(--sp-8);background:var(--panel)
}
.adm-search svg{width:15px;height:15px;flex:0 0 auto;color:var(--ink-4)}
.adm-search input{flex:1 1 auto;border:0;background:transparent;padding:9px 0;font:inherit;color:var(--ink)}
.adm-search input:focus{outline:none}
.adm-search:focus-within{border-color:var(--ob-edge);box-shadow:0 0 0 3px var(--ob-wash)}

/* An empty state that says what to do next, not just that there is nothing. */
.adm-empty{
  padding:var(--sp-16) var(--sp-12);text-align:center;border:1px dashed var(--line-strong);
  border-radius:var(--radius-sm);background:var(--surface-2)
}
.adm-empty b{display:block;color:var(--ink);margin-bottom:2px}
.adm-empty span{color:var(--ink-3);font-size:var(--fs-sm)}

/* ---------- The operator console ----------------------------------------
   Its own host, its own whole window. Deliberately plainer than the product —
   an operator surface that looks like the app is one somebody mistakes for the
   app, and the top of this screen should never be ambiguous about which of the
   two you are typing into. */
/* z-index 350: ABOVE the app and the landing page (300), BELOW the sign-in gate
   (400). It was 400 — the SAME as the gate — and .cons is appended to <body>
   after it, so at equal z-index the later element wins and the console painted
   straight over the sign-in screen. The gate was present and working the whole
   time and there was simply no way to reach it, which from the outside is
   indistinguishable from "the console cannot be signed into". */
.cons{position:fixed;inset:0;z-index:350;background:var(--bg);overflow:auto;
  display:flex;flex-direction:column}
.cons-bar{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:var(--sp-8);
  padding:var(--sp-6) var(--sp-12);background:var(--panel);border-bottom:2px solid var(--ob-fill)}
.cons-brand{display:flex;align-items:center;gap:var(--sp-5)}
.cons-name{font-weight:680;letter-spacing:-.01em;color:var(--ob-ink)}
.cons-who{margin-left:auto;display:flex;align-items:center;gap:var(--sp-6);
  font-size:var(--fs-sm);color:var(--ink-3)}
.cons-main{flex:1 1 auto;max-width:900px;width:100%;margin:0 auto;padding:var(--sp-16) var(--sp-12) 64px}

/* ---- the release record ------------------------------------------------
   Entries are a READING surface, not a control surface, so they get a wider
   measure than the operator forms above them and a rule between them rather
   than a card each — a page of nested cards reads as a list of settings, and
   this is a list of events. Every colour is a token: the console is the one
   place somebody is looking at 2am, and both themes have to hold. */
/* The console's .row puts a label left and stretches its control to the right
   edge, which suits a text field and makes a seven-item picker look like a
   search box. Sized to its content instead, with a floor so the longest
   option does not clip. */
/* The header IS the control. Reset the UA button so it reads as a heading
   rather than a form control, but keep it a <button> so it is focusable and
   announces aria-expanded. */
.cons-rel-toggle{display:flex;align-items:center;gap:var(--sp-5);width:100%;
  background:none;border:0;padding:0;margin:0;font:inherit;color:inherit;
  cursor:pointer;text-align:left}
.cons-rel-toggle h2{margin:0}
.cons-rel-toggle:hover .cons-rel-chev{color:var(--ob-ink)}
.cons-rel-toggle:focus-visible{outline:2px solid var(--ob-edge);outline-offset:3px;border-radius:6px}
.cons-rel-chev{color:var(--ink-4);font-size:var(--fs-sm);width:1em;flex:0 0 auto}
.cons-rel-count{margin-left:auto;color:var(--ink-3);font-size:var(--fs-sm);
  font-variant-numeric:tabular-nums}
/* Collapsed, the card is just its header — no residual padding pretending
   there is content under it. */
.cons-rel.is-shut{padding-top:var(--sp-8);padding-bottom:var(--sp-8);margin-bottom:var(--sp-8)}
.cons-rel select{width:auto;min-width:15rem;flex:0 0 auto}
.cons-rel-site{margin-top:calc(var(--sp-4) * -1)}
.cons-rel-site code{font-family:var(--mono);font-size:var(--fs-micro);
  background:var(--line-2);border-radius:5px;padding:1px 5px}
.cons-rel-item{border-top:1px solid var(--line);padding-top:var(--sp-8);margin-top:var(--sp-8)}
.cons-rel-item:first-of-type{border-top:0;margin-top:var(--sp-4)}
.cons-rel-item h3{margin:0 0 2px;font-size:var(--fs-lg);display:flex;align-items:center;gap:var(--sp-4);flex-wrap:wrap}
.cons-rel-meta{margin:0 0 var(--sp-5);color:var(--ink-3);font-size:var(--fs-sm)}
/* The section heads carry the meaning, so they are the one thing allowed to
   shout — uppercase and tracked, small enough not to compete with the title. */
.cons-rel-h{margin:var(--sp-6) 0 var(--sp-2);font-size:var(--fs-micro);
  text-transform:uppercase;letter-spacing:.06em;color:var(--ink-3)}
/* Retired is the section people skim for: it is the only one that tells you
   something you relied on is gone. Amber, not red — removal is not a fault. */
.cons-rel-item h4.cons-rel-h:nth-of-type(3){color:var(--amber)}
.cons-rel-list{margin:0;padding-left:var(--sp-9)}
.cons-rel-list li{margin:2px 0;line-height:1.5}
.cons-mid{text-align:center;padding:var(--sp-16)}
.cons-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--sp-12);box-shadow:var(--shadow);margin-bottom:var(--sp-12)}
.cons-search{display:flex;align-items:center;gap:var(--sp-6);margin-bottom:var(--sp-6);
  background:var(--panel);border:1px solid var(--line-strong);border-radius:var(--radius);
  padding:var(--sp-4) var(--sp-6)}
.cons-search svg{width:16px;height:16px;color:var(--ink-4);flex:0 0 auto}
.cons-search input{flex:1 1 auto;border:0;background:transparent;padding:9px 0;font:inherit}
.cons-search input:focus{outline:none}
.cons-search:focus-within{border-color:var(--ob-edge);box-shadow:0 0 0 3px var(--ob-wash)}
.cons-hint{margin:0 0 var(--sp-12)}
.cons-head{display:flex;align-items:center;gap:var(--sp-8);margin-bottom:var(--sp-10)}
.cons-head-right{margin-left:auto}
.cons-h1{font-size:var(--fs-lead);font-weight:680}
.cons-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--sp-6);margin-bottom:var(--sp-10)}
.cons-fact{border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--sp-5) var(--sp-6)}
.cons-k{font-size:var(--fs-cap);color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}
.cons-v{font-weight:600;overflow:hidden;text-overflow:ellipsis}
.cons-v.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--fs-sm);font-weight:500}
.cons-sec{margin-top:var(--sp-12);padding-top:var(--sp-10);border-top:1px solid var(--line-2)}
/* The roster sections are <details>, so the open/close state lives in the DOM
   and survives a re-render without this file tracking which headings are open.
   The summary keeps the .adm-h heading look and gains the affordances a native
   marker does not carry on its own. */
details.cons-sec > summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:var(--sp-4)}
details.cons-sec > summary::-webkit-details-marker{display:none}
/* 11px was a chevron you had to look for. These are the control for the whole
   section, so they are sized like one: a 16px glyph in a 20px box, which is
   also a touch target rather than a hairline. */
details.cons-sec > summary::before{content:'\25B8';color:var(--ink-3);font-size:16px;
  width:20px;text-align:center;transition:transform .12s ease;display:inline-block}
details.cons-sec[open] > summary::before{transform:rotate(90deg)}
details.cons-sec > summary:hover{color:var(--ink)}
details.cons-sec > summary:hover::before{color:var(--ink)}

/* A TEAM INSIDE THE TEAMS SECTION. Indented and lighter than a top-level
   heading, so the nesting is visible at a glance: Teams is the category, each
   team is a row that opens on its own without opening its neighbours. */
details.cons-sub{margin:0 0 var(--sp-4) 0;padding-left:var(--sp-6);
  border-left:2px solid var(--line-2)}
details.cons-sub > summary{cursor:pointer;list-style:none;display:flex;align-items:center;
  gap:var(--sp-4);padding:var(--sp-4) 0;
  font-size:var(--fs-sm);font-weight:650;color:var(--ink)}
details.cons-sub > summary::-webkit-details-marker{display:none}
details.cons-sub > summary::before{content:'\25B8';color:var(--ink-3);font-size:14px;
  width:18px;text-align:center;transition:transform .12s ease;display:inline-block}
details.cons-sub[open] > summary::before{transform:rotate(90deg)}
/* A roster row is a way INTO the per-account card, so it reads as clickable. */
.cons-person{cursor:pointer}
.cons-person:hover{background:var(--surface-hover)}
.cons-row{display:flex;align-items:center;gap:var(--sp-8);padding:var(--sp-6) 0}
.cons-row > div:first-child{flex:1 1 auto;min-width:0}
.cons .btn.primary{background:var(--ob-fill);border-color:var(--ob-fill);color:var(--ob-on)}
.cons .btn.primary:hover:not([disabled]){background:var(--ob-fill-hover);border-color:var(--ob-fill-hover)}

/* Bookmarks. The add row is the first thing on the screen because adding is
   what somebody opened this to do; editing what is already there is the rarer
   visit. */
.bm-add{display:flex;gap:var(--sp-6);align-items:flex-end;flex-wrap:wrap}
.bm-add .fld{flex:1 1 160px;min-width:0}
.bm-addgo{flex:0 0 auto;padding-bottom:12px}
.bm-folders{display:flex;flex-direction:column;gap:var(--sp-5)}
.bm-folder{display:flex;gap:var(--sp-6);align-items:center}
.bm-folder input{flex:1 1 auto}

.adm-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:var(--sp-5)}
.adm-stat{border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--sp-5) var(--sp-6);
  background:var(--surface-2)}
.adm-n{font-size:var(--fs-lead);font-weight:700;font-variant-numeric:tabular-nums;color:var(--ink)}
.adm-l{font-size:var(--fs-cap);color:var(--ink-3);text-transform:uppercase;letter-spacing:.06em}
.adm-list{max-height:52vh;overflow:auto;border:1px solid var(--line);border-radius:var(--radius-sm)}
.adm-list table{width:100%}
.adm-list td{vertical-align:top}
tr.adm-susp{opacity:.6}

/* ---------- The sign-in screen -------------------------------------------
   A front door for the web build. It sits above everything (including the
   modal layer, which is why the z-index is higher than the scrim's) and it is
   deliberately not dismissable by Escape: leaving it should be a choice you
   made, not a key you pressed. The desktop build never constructs it. */
/* Two rows, not one: the card is centred in whatever is left over and the
   consent line sits on the floor of the screen. Done with the grid rather than
   by positioning the line absolutely, because .gate scrolls — an absolutely
   placed foot rides up over the card the moment the window is short. With no
   foot the second track is 0 and the card is centred exactly as before. */
.gate{position:fixed;inset:0;z-index:400;display:grid;place-items:center;
  grid-template-rows:1fr auto;
  padding:var(--sp-10);overflow:auto;background:var(--bg)}
/* Generous, EXPLICIT padding (px, not a token) so the content column is inset
   like the reference — buttons sit narrow and centred, not edge-to-edge. The
   earlier `var(--sp-14)` did not exist in the scale, which invalidated the whole
   padding shorthand and collapsed it to 0. */
.gate-card{width:100%;max-width:420px;background:var(--panel);
  border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:0 18px 60px rgba(16,24,40,.20);padding:48px 40px 36px}

/* The consent line: on the floor of the screen, off the card, and quiet. It is
   --ink-4 (the faintest ink that still passes) because it is a statement of
   fact rather than a step in signing in — but the two document names inside it
   are ordinary ink and underlined, or the only clickable thing on the line
   reads as the least clickable thing on the screen. */
.gate-foot{
  align-self:end;justify-self:center;max-width:460px;text-align:center;
  padding-top:var(--sp-12);font-size:var(--fs-sm);color:var(--ink-4);line-height:1.7
}
.gate-foot-a{
  font:inherit;color:var(--ink-3);background:none;border:0;padding:0;
  text-decoration:underline;text-underline-offset:2px;cursor:pointer
}
.gate-foot-a:hover{color:var(--ob-ink)}
.gate-foot-a:focus-visible{outline:2px solid var(--ob-edge);outline-offset:2px;border-radius:2px}
.gate-foot-dt{display:block;margin-top:2px;font-size:var(--fs-cap)}

/* The documents themselves, in a dialog until they have a page of their own. */
.legal-intro{margin:0 0 var(--sp-10);color:var(--ink-2)}
.legal-h{margin:var(--sp-12) 0 var(--sp-3);font-size:var(--fs-md);font-weight:680}
.legal-p{margin:0;color:var(--ink-2);line-height:1.65}
/* Brand: the app icon (rounded square) centred, tagline beneath. */
.gate-brand{display:flex;flex-direction:column;align-items:center;gap:var(--sp-5);margin-bottom:var(--sp-8)}
.gate-app-icon{width:76px;height:76px;border-radius:18px;display:block;
  box-shadow:0 4px 16px rgba(16,24,40,.20)}
.gate-logo{width:56px;height:56px;display:grid;place-items:center}
.gate-logo svg{width:56px;height:56px}
.gate-tag{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.14em;
  color:var(--ink-4);font-weight:700}
.gate-h{font-size:var(--fs-title);font-weight:680;text-align:center;margin:0 0 var(--sp-4)}
.gate-sub{font-size:var(--fs-sm);color:var(--ink-3);text-align:center;line-height:1.5;margin:0 0 var(--sp-8)}
.gate-card .fld{margin-bottom:var(--sp-6)}
.gate-card .fld + .fld{margin-top:0}

/* The two buttons take their colour from the logo: a deep slate-blue Continue
   and a muted-rose CILogon, both with white text. Defined here so they match the
   mark regardless of the app's accent theme. */
.gate-primary{width:100%;justify-content:center;min-height:44px;
  background:var(--gate-blue);border-color:var(--gate-blue);color:#fff;font-weight:640}
.gate-primary:hover:not(:disabled){background:var(--gate-blue-h);border-color:var(--gate-blue-h);color:#fff}
.gate-primary:disabled{opacity:.45;cursor:default}
.gate-note{font-size:var(--fs-cap);color:var(--ink-3);line-height:1.5;margin-top:var(--sp-5)}
.gate-oauth,.gate-local{width:100%;justify-content:center;min-height:44px;margin-top:var(--sp-5);
  display:flex;align-items:center;gap:var(--sp-5)}
/* THE PRIMARY BLUE, because CILogon IS the primary action now. It wore the rose
   while the blue Continue button sat under it and two primaries would have
   competed; with the email step behind the service-entrance link there is only
   one door, and it should look like the one. */
.gate-cilogon{background:var(--gate-blue);border-color:var(--gate-blue);color:#fff;font-weight:600}
.gate-cilogon:hover{background:var(--gate-blue-h);border-color:var(--gate-blue-h);color:#fff}
.gate-oauth-ic{flex:0 0 auto}

/* Password field + reveal eye share the row, equal-height columns. */
.gate-pw{display:flex;align-items:stretch;gap:var(--sp-4)}
.gate-pw input{flex:1 1 auto;min-width:0}
.gate-eye{flex:0 0 auto;width:40px;border:1px solid var(--line);border-radius:var(--r-input,8px);
  background:var(--surface-2);cursor:pointer;font-size:15px;line-height:1;opacity:.6}
.gate-eye:hover,.gate-eye.on{opacity:1;border-color:var(--gate-blue)}

/* The signed-in email on the password step, with its Edit link. */
.gate-idrow{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-5);
  border:1px solid var(--line);border-radius:var(--r-input,8px);
  padding:var(--sp-5) var(--sp-6);margin-bottom:var(--sp-6);background:var(--surface-2)}
.gate-id{font-size:var(--fs-sm);color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gate-edit{flex:0 0 auto;color:var(--blue);font-weight:600}

.gate-rule{display:flex;align-items:center;gap:var(--sp-6);margin:var(--sp-8) 0;
  color:var(--ink-4);font-size:var(--fs-cap)}
.gate-rule::before,.gate-rule::after{content:"";flex:1 1 auto;height:1px;background:var(--line)}
.nav-signin .mk{font-weight:700}
.gate-links{margin-top:var(--sp-6);font-size:var(--fs-cap);text-align:center;color:var(--ink-3)}
.gate-links-left{text-align:left;margin-top:0;margin-bottom:var(--sp-6)}
.gate-links a{color:var(--blue);text-decoration:none;font-weight:600}
.gate-links a:hover{text-decoration:underline}
@media (max-width:760px){
  .gate{padding:var(--sp-6);place-items:start center}
  .gate-card{padding:var(--sp-10);max-width:none}
}

/* Admin section subheading (Access tab). */
.adm-h{font-size:var(--fs-cap);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  color:var(--ink-3);margin:0 0 var(--sp-5)}

/* The mail diagnosis. Green or red, because the answer is binary and the whole
   point is not having to read carefully to find out which. */
.cons-mail{margin-top:var(--sp-8);padding:var(--sp-8);border-radius:var(--radius-sm);
  border:1px solid var(--line)}
.cons-mail.good{background:var(--green-bg);border-color:var(--green-line)}
.cons-mail.good b{color:var(--green)}
.cons-mail.bad{background:var(--amber-bg);border-color:var(--amber-line)}
.cons-mail.bad b{color:var(--amber)}
/* The temporary password, shown once. Monospaced and large because it will be
   read off a screen and typed by somebody on a phone. */
.cons-pw{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--fs-lead);
  font-weight:600;letter-spacing:.02em;margin:var(--sp-5) 0;user-select:all}

/* ---------- Rail metrics (Stylus sidebar) --------------------------------
   Taken from the reference sheet: item height 36, icon 18, icon-to-text gap 8,
   section gap 20, radius 8, section label 12, nav item 14, tracking -0.03em.

   The COLOURS are deliberately NOT taken. That sheet is a near-black rail with
   an orange accent; ours carries the app icon's own rose-to-slate gradient, and
   swapping the palette in would make Stylus stop matching the suite it sits in.
   Metrics travel between designs. A palette does not.

   Last in the file on purpose — see the note above about a later plain rule
   beating an earlier one at equal specificity. */
:root{
  --nv-item-h:36px; --nv-icon:18px; --nv-gap:8px;
  --nv-section-gap:20px; --nv-radius:8px;
  /* The reference sheet says section label 12 against nav item 14. That makes
     the label for a group SMALLER than the rows inside it, which is exactly
     what read as sloppy on both rails (Alex, 2026-08-16). Metrics travel
     between designs; a heading that loses to its own contents does not. The
     label now matches the item and wins on weight, case and colour instead. */
  --nv-label:14px; --nv-item:14px; --nv-track:-0.03em;
}
.nav-row{min-height:var(--nv-item-h);gap:var(--nv-gap);border-radius:var(--nv-radius);
  font-size:var(--nv-item);letter-spacing:var(--nv-track)}
.nav-row .mk{width:var(--nv-icon);height:var(--nv-icon);flex:0 0 auto;
  display:grid;place-items:center;opacity:.92}
.nav-row .mk svg{width:var(--nv-icon);height:var(--nv-icon);display:block}
.nav-sec{margin-top:var(--nv-section-gap)}
.nav-sec-head{font-size:var(--nv-label);letter-spacing:.05em;font-weight:800}
/* One left edge on this rail too: a row whose label comes first is inset by
   the width the icon would have taken. Declared here so it beats the earlier
   plain rule at equal specificity, like everything else in this block. */
.nav-row > .lbl:first-child{margin-left:calc(var(--nv-icon) + var(--nv-gap))}
.nav-sec-head .cnt{font-size:var(--fs-cap);min-width:2.2em;text-align:right;
  font-variant-numeric:tabular-nums;font-weight:700;opacity:.85}
.nav-row .val{font-size:var(--fs-cap);min-width:2.2em;text-align:right;
  font-variant-numeric:tabular-nums}

/* A GROUP (Write / Edit / Cite / Review) is a control now, not a caption —
   and it reads a clear step LOUDER than the section heads under it: larger,
   brighter, wider-tracked. The two used to share one size and read as a
   single run-on list. */
.nav-group{
  display:flex;align-items:center;gap:6px;width:100%;
  margin:var(--nv-section-gap) 0 2px;padding:var(--sp-3) var(--sp-5);
  background:none;border:0;font-family:inherit;cursor:pointer;text-align:left;
  /* A STEP ABOVE THE SECTION HEADS, which are now 14px — raising those to
     stop them losing to their own rows left this one smaller than the things
     under IT, which is the same inversion one level up. The rail reads top
     down: group, then section, then row. */
  font-size:15px;font-weight:800;text-transform:uppercase;
  letter-spacing:.12em;color:var(--nav-ink, #e8edf7);border-radius:var(--nv-radius)
}
.nav-group:hover{background:#ffffff10}
.nav-group:focus-visible{outline:2px solid #ffffff5c;outline-offset:-2px}
.nav-group .tw{font-size:8px;opacity:.7;transition:transform .14s ease;transform:rotate(90deg)}
.nav-group.is-collapsed .tw{transform:rotate(0deg)}
.nav-groupbody[hidden]{display:none}
/* A group head wears the SAME bubble as Home when its own home screen is
   open, and the quieter on-path mark when the selection lives somewhere
   beneath it — the breadcrumb you can follow down the rail. */
.nav-group.sel{background:#ffffff1f;color:#fff;border-radius:var(--nv-radius)}
.nav-group.on-path{color:#fff}
.nav-sec-head.on-path{color:#e8edf7}
/* The guide line ITSELF carries the accent when its branch is on-path — one
   continuous bar running from the group down to wherever the selection is,
   rather than a mark beside a single row. */
.nav-group.on-path + .nav-groupbody::before{background:var(--ac-edge, #c9a0a8);width:2px;opacity:1}
.nav-sec.on-path-branch .nav-children::before{background:var(--ac-edge, #c9a0a8);width:2px;opacity:1}
.nav-group .gtw{display:grid;place-items:center;border-radius:4px;margin:-2px 0 -2px -2px;
  padding:2px}
.nav-group .gtw:hover{background:#ffffff22}

/* The full title, small and unbold, under the nickname it explains. */
.ms-full{display:block;font-weight:400;font-size:var(--fs-cap);color:var(--ink-3);
  line-height:1.35;margin-top:1px}
.recent-row .ms-full,.nav-row .ms-full{color:inherit;opacity:.65}

/* Everything under a verb sits visibly INSIDE it: indented, with a drop line
   tracing the group the way the manuscript list already traces its folder. */
.nav-groupbody{position:relative;padding-left:var(--sp-7)}
/* Accent, like .nav-children's line: every open group wears the red guide
   line, dimmed until its branch is the one on-path. */
.nav-groupbody::before{content:"";position:absolute;left:9px;top:2px;bottom:6px;
  width:2px;background:var(--ac-edge, #c9a0a8);opacity:.45;border-radius:1px}
/* THE SECTION HEADS STEP DOWN FROM THE GROUP BY WEIGHT AND COLOUR, NOT SIZE.
   This rule is the one that actually decides — two classes, so it beat both
   .nav-sec-head and --nv-label and pinned every heading at 12.5px against
   13.5px rows. That is the whole defect: the label for a group was smaller
   than the things inside it, on the rail as on the citation pane (Alex,
   2026-08-16). It matches the rows now and stays a clear step below the group
   above it through weight, tracking and ink. */
.nav-groupbody .nav-sec-head{font-size:var(--nv-item);letter-spacing:.05em;
  font-weight:800;color:#a8bbe4}
.nav-groupbody .nav-sec-head:hover{color:#dbe5f8}
.nav-groupbody .nav-sec{margin-top:var(--sp-4)}
/* Home sits right under the head — the old stack of paddings and section
   gaps opened a gulf between the blue block and the first row. */
.nav-scroll > .nav-sec:first-child{margin-top:0}
.nav-scroll > .nav-sec:first-child + .nav-group{margin-top:var(--sp-6)}

/* "All manuscripts" owns the list under it: a twisty that is its OWN control,
   so opening the list and going to the screen are different clicks on one row.
   The row was previously the link and the papers were its siblings. */
.nav-parent{position:relative;padding-left:2px}
.nav-parent .nav-tw{
  width:16px;height:22px;flex:0 0 auto;display:grid;place-items:center;
  background:none;border:0;color:inherit;cursor:pointer;opacity:.7;padding:0
}
.nav-parent .nav-tw:hover{opacity:1}
.nav-parent .tw{font-size:8px;display:block;transition:transform .14s ease;transform:rotate(90deg)}
.nav-parent.is-collapsed .tw{transform:rotate(0deg)}
.nav-parent-hit{display:flex;align-items:center;gap:var(--nv-gap);flex:1 1 auto;min-width:0}
.nav-sub-children{padding-left:var(--sp-6)}

/* First / MI / Last on the sign-up card. The middle initial is one character,
   so it gets one character's worth of box — a third equal column would claim it
   matters as much as the other two. */
.gate-name{display:flex;gap:10px;align-items:flex-end}
.gate-name .fld{flex:1 1 0;min-width:0}
.gate-name .fld.gate-mi{flex:0 0 62px}

/* Team + team role in one cell of the allowed-addresses table. The role is
   narrow because it is meaningless without the team beside it. */
.adm-teamcell{display:flex;gap:6px;align-items:center}
.adm-teamcell select:first-child{flex:1 1 auto;min-width:0}
.adm-teamcell select:last-child{flex:0 0 92px}

/* The collapse twisty, drawn and sized WITH the row icons rather than guessed
   at: 15px against the 18px row icons reads as the same family. It was the
   character "▸" at 8px, which next to an 18px icon is a speck. */
.nav-sec-head .tw,.nav-group .tw,.nav-parent .tw{
  width:15px;height:15px;flex:0 0 auto;display:grid;place-items:center;
  transition:transform .14s ease;transform:rotate(90deg);opacity:.8
}
.nav-sec-head .tw svg,.nav-group .tw svg,.nav-parent .tw svg{width:15px;height:15px;display:block}
.nav-sec.is-collapsed .nav-sec-head .tw,
.nav-group.is-collapsed .tw,
.nav-parent.is-collapsed .tw{transform:rotate(0deg)}
.nav-parent .nav-tw{width:22px;height:24px}
/* The folder rows use the same marker slot as a row icon, so their glyphs get
   the row-icon size too rather than staying at whatever the font chose. */
.nav-row.nav-folder .mk{font-size:13px}

/* ---------- A rail you can widen, and file into by dragging ---------------
   --rail-w overrides --sidebar-w when U.applyRailWidth has read a stored one.
   Last in the file so it beats the base rule at equal specificity. */
/* :not(.narrow) because the drawer's width is a property of the PHONE, not a
   preference — a rail dragged to 460px on a desktop would otherwise open as a
   460px drawer over a 375px screen. */
/* :not(.nav-collapsed) or this rule's equal specificity to the collapse
   rule above lets SOURCE ORDER decide, and this one sits later — a
   collapsed rail kept reading its remembered width instead of going to 0. */
#app:not(.narrow):not(.nav-collapsed) #sidebar{width:var(--rail-w, var(--sidebar-w))}
/* The transition is SUSPENDED while dragging. Left on, every frame animates and
   the edge trails the cursor by 160ms, which reads as the drag being broken. */
body.rail-resizing #sidebar{transition:none}
body.rail-resizing{cursor:col-resize;user-select:none}

#navGrip{
  flex:0 0 auto;width:6px;margin-left:-6px;z-index:6;cursor:col-resize;
  background:transparent;transition:background .12s ease
}
#navGrip:hover,body.rail-resizing #navGrip{background:var(--ob-edge)}
/* Nothing to grip when the rail is shut, and nothing to drag on a phone where
   it is an overlay rather than a column. */
#app.nav-collapsed #navGrip,#app.narrow #navGrip{display:none}

/* Dragging a document into a folder. Pointer events, not HTML5 drag-and-drop —
   the Tauri shell eats the OS drag before the page sees it. */
body.rail-dragging{cursor:grabbing;user-select:none}
.nav-row.is-dragging{opacity:.45}
.nav-row.nav-folder.drop-on{background:#ffffff2e;color:#fff;
  box-shadow:inset 0 0 0 1px #ffffff45}
.nav-row[data-drag]{cursor:grab}
.nav-row[data-drag]:active{cursor:grabbing}
/* The folder's own twisty: same 15px family as every other twisty in the
   rail, pointing right shut and down open. */
.nav-folder .fold-tw{width:15px;height:15px;flex:0 0 auto;display:grid;
  place-items:center;transition:transform .14s ease;opacity:.8}
.nav-folder .fold-tw svg{width:15px;height:15px;display:block}
.nav-folder .fold-tw.open{transform:rotate(90deg)}
/* Reordering folders: an insertion LINE above or below the target, not a
   fill — filling is the drop-INTO signal and means something else here. */
.nav-row.nav-folder.fold-before{box-shadow:inset 0 2px 0 0 var(--ob-edge)}
.nav-row.nav-folder.fold-after{box-shadow:inset 0 -2px 0 0 var(--ob-edge)}

/* ---------- Authors & affiliations ----------------------------------------
   The masthead is a PREVIEW — set like a paper, not like a form, so nobody
   tries to click into it. */
.mast-card .card-body{padding:18px 22px}
.mast-tag{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.09em;
  color:var(--ink-4);font-weight:700;margin-bottom:10px}
.mast-title{font-family:var(--doc-font);font-size:19px;font-weight:700;
  line-height:1.3;margin-bottom:8px}
.mast-authors{font-family:var(--doc-font);font-size:14px;line-height:1.6;
  margin-bottom:8px}
.mast-authors sup,.mast-affs sup,.au-chip sup,.au-aff-n{color:var(--ob-ink);font-weight:700}
.mast-affs{font-size:var(--fs-sm);color:var(--ink-2);line-height:1.55}
.mast-foot{margin-top:8px;padding-top:8px;border-top:1px dashed var(--line);
  font-size:var(--fs-sm);color:var(--ink-3)}

.cons-hint{font-size:var(--fs-micro);color:var(--ink-4);margin-top:2px}

/* Ownership transfer: one bubble at the head of the Role column. Small because
   it is rare, and outlined rather than filled because it is not the thing you
   came to this dialog to do. */
.xfer-bubble{width:26px;height:26px;padding:0;border:1px solid var(--line-strong);
  border-radius:999px;background:var(--panel);color:var(--ink-3);cursor:pointer;
  font-size:13px;line-height:1;display:inline-flex;align-items:center;justify-content:center}
.xfer-bubble:hover{border-color:var(--amber);color:var(--amber);background:var(--amber-bg)}
.xfer-bubble:focus-visible{outline:2px solid var(--amber);outline-offset:1px}

/* The cloud-storage figure. One number, large, with what it is made of under
   it — never summed with anything measured on this machine. */
.cf-total{margin-bottom:var(--sp-8);padding:var(--sp-8) var(--sp-10);
  border:1px solid var(--line);border-radius:var(--radius);background:var(--surface-2)}
.cf-total-n{font-size:var(--fs-lead);font-weight:800;line-height:1.1}
.cf-total-k{font-size:var(--fs-cap);color:var(--ink-3);margin-bottom:var(--sp-4)}

/* Filing, at the top of the record where it can be found. */
.cd-coll{display:flex;align-items:baseline;gap:var(--sp-5);margin:var(--sp-6) 0 var(--sp-8)}
.cd-coll-k{flex:0 0 auto;font-size:var(--fs-micro);font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-4)}
.cd-coll .cd-chips{flex:1 1 auto;display:flex;flex-wrap:wrap;gap:var(--sp-4);margin:0}
/* The row's own menu — IN FLOW, leading the right-hand group, wearing a
   BUBBLE. It was pinned absolutely at the row's top-right corner, which the
   paperclip later moved into: two marks on the same pixels, the menu
   invisible under the clip. In flow nothing can overlap it again, and the
   ring is what makes three dots read as a button rather than stray ink —
   faint at rest, full on the row's hover, always faintly there on touch
   screens where there is no hover to reveal it. */
.cite-item{position:relative}
.ci-more{flex:0 0 auto;width:22px;height:22px;padding:0;display:inline-flex;
  align-items:center;justify-content:center;
  border:1px solid var(--line-strong);border-radius:999px;background:var(--surface-2);
  color:var(--ink-3);cursor:pointer;line-height:1;
  opacity:.35;transition:opacity .12s ease}
.cite-item:hover .ci-more,.ci-more:focus-visible{opacity:1}
.ci-more:hover{background:var(--surface-hover);border-color:var(--ink-4);color:var(--ink-2)}
@media (hover:none) and (pointer:coarse){ .ci-more{opacity:.8} }

/* The roster, shown as it will print — a supplement is the one document nobody
   reads until it is published, so the preview is the printed form. */
.ro-title{width:100%}
.ro-prev{margin-top:12px;padding:12px 14px;border:1px solid var(--line);border-radius:var(--radius);
  background:var(--surface-2);max-height:340px;overflow:auto;font-size:var(--fs-sm)}
.ro-h1{font-weight:800;text-align:center;margin-bottom:8px}
.ro-h2{font-weight:700;margin-top:10px}
.ro-h3{font-style:italic;color:var(--ink-2);margin-top:6px}
.ro-note{font-style:italic;color:var(--ink-3)}
.ro-p{color:var(--ink-2);line-height:1.5}

.nav-shared{flex:0 0 auto;display:inline-flex;color:#cdd8ee;opacity:.95}
.nav-shared svg{width:15px;height:15px;display:block}
.nav-row.sel .nav-shared{color:var(--ac-ink)}

/* The topbar face stack, and the read-only "who can see this" list behind it. */
.shr-stack{display:inline-flex;align-items:center;gap:0;padding:2px 6px}
.shr-stack .avatar{box-shadow:0 0 0 2px var(--panel)}
.shr-stack .avatar + .avatar{margin-left:-6px}
.shr-n{margin-left:var(--sp-4);font-size:var(--fs-micro);color:var(--ink-3);font-weight:700}
.shr-row{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-5) var(--sp-4);
  border-bottom:1px solid var(--line-2)}
.shr-row:last-child{border-bottom:0}
.shr-who{flex:1 1 auto;min-width:0}
.shr-who .hint{font-size:var(--fs-micro)}
.shr-role{flex:0 0 auto;font-size:var(--fs-cap);color:var(--ink-3)}
/* The role picker on a review-round row. Left to grow it eats the whole row,
   and the person's name — the thing you are actually reading down the list —
   ends up squeezed against a control. */
.rnd-role{flex:0 0 auto;width:auto;max-width:140px}
/* Inviting somebody who is not on the paper: two fields and a button, wrapping
   to their own lines on a phone rather than shrinking to unusable slivers. */
.rnd-adhoc{display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:center;
  padding:var(--sp-5) 0 var(--sp-6);border-bottom:1px solid var(--line-2);
  margin-bottom:var(--sp-5)}
.rnd-adhoc input{flex:1 1 200px;min-width:0}
.rnd-adhoc .btn{flex:0 0 auto}
@media (max-width:640px){
  .rnd-adhoc input{flex:1 1 100%}
  .rnd-adhoc .btn{flex:1 1 100%;justify-content:center}
}
.shr-head{margin-top:var(--sp-8);padding:var(--sp-4);font-size:var(--fs-micro);font-weight:700;
  text-transform:uppercase;letter-spacing:.06em;color:var(--ink-4)}

/* One author, one folding card. */
.au-card{border:1px solid var(--line);border-radius:var(--radius);margin-bottom:8px;
  background:var(--panel)}
.au-head{display:flex;align-items:center;gap:8px;padding:8px 10px;cursor:pointer;
  border-radius:var(--radius)}
.au-head:hover{background:var(--ob-wash)}
.au-card.open .au-head{border-bottom:1px solid var(--line);border-radius:var(--radius) var(--radius) 0 0}
.au-n{flex:0 0 22px;text-align:center;font-weight:800;color:var(--ink-4);font-size:var(--fs-sm)}
/* A name never breaks in the middle — the hint beside it gives way instead. */
.au-chip{font-weight:650;white-space:nowrap;flex:0 0 auto}
.au-chip sup{margin-left:2px}
/* A group row is easy to mistake for a person with an unusual name, and the
   difference decides whether the card offers ORCID and affiliations. Says so. */
.au-tag{margin-left:6px;padding:1px 5px;border:1px solid var(--line);border-radius:999px;
  background:var(--ob-wash);color:var(--ink-4);font-size:var(--fs-micro);font-weight:600;
  letter-spacing:.04em;text-transform:uppercase;vertical-align:1px}
.au-affhint{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--ink-4);font-size:var(--fs-sm)}
/* Drawn, chevron-sized, and it rotates — the 11px text triangle it replaces
   was the smallest thing on the row. */
.au-tw{flex:0 0 auto;color:var(--ink-4);width:18px;height:18px;display:grid;place-items:center}
.au-tw svg{width:15px;height:15px;display:block;transition:transform .14s ease}
.au-tw.open svg{transform:rotate(90deg)}
/* The outline's reorder grip. Hidden until the row is hovered or the button
   itself has focus — a column of handles down a narrow rail reads as clutter,
   and the rail is mostly used for navigating rather than arranging. Focus is
   part of the test, or the keyboard route would be invisible to the person
   using it. */
.out-grab{
  flex:0 0 auto;width:14px;margin-left:-4px;padding:0;border:0;background:none;
  cursor:grab;color:var(--ink-4);font-size:12px;line-height:1;opacity:0
}
.out-row:hover .out-grab,.out-grab:focus-visible{opacity:1}
.out-grab:active{cursor:grabbing}
.out-grab:focus-visible{outline:2px solid var(--ob-edge);outline-offset:1px;border-radius:2px}

.au-grab{flex:0 0 auto;cursor:grab;color:var(--ink-4);font-size:14px;padding:0 2px;
  touch-action:none;user-select:none}
.au-grab:active{cursor:grabbing}
.au-body{padding:12px}
.au-foot{display:flex;align-items:center;gap:8px;margin-top:10px}
.au-drop-marker{height:0;border-top:2px solid var(--ob-ink);border-radius:1px;margin:2px 0}

/* An author's own affiliation lines — full addresses, so they can be checked
   where they are used. */
.au-aff{display:flex;align-items:center;gap:6px;padding:5px 8px;border:1px solid var(--line);
  border-radius:var(--radius-sm);margin-bottom:5px;background:var(--ob-wash)}
.au-aff-n{flex:0 0 auto}
.au-aff-t{flex:1 1 auto;min-width:0;font-size:var(--fs-sm);line-height:1.4}
.au-aff-shared{color:var(--ink-4);font-size:var(--fs-micro);white-space:nowrap}
.aff-flash{outline:2px solid var(--ob-edge);outline-offset:3px;border-radius:var(--radius-sm);
  transition:outline-color .3s ease}

/* The affiliation picker dialog. */
.af-grp{font-size:var(--fs-micro);text-transform:uppercase;letter-spacing:.08em;
  color:var(--ink-4);font-weight:700;margin:12px 0 4px}
.af-row{display:block;width:100%;text-align:left;padding:7px 10px;margin-bottom:4px;
  border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel);
  font:inherit;font-size:var(--fs-sm);cursor:pointer;color:var(--ink)}
.af-row:hover{background:var(--ob-wash);border-color:var(--ob-edge)}
.af-row sup{color:var(--ob-ink);font-weight:700;margin-right:2px}
.af-manual{border-style:dashed;color:var(--ink-3)}
.af-row.on{border-color:var(--ob-ink);background:var(--ob-wash)}

/* One author of a looked-up paper: the facts on the left, one verb on the
   right. */
.fp-au{display:flex;align-items:flex-start;gap:10px;padding:8px 10px;margin-bottom:6px;
  border:1px solid var(--line);border-radius:var(--radius-sm)}
.fp-au-t{flex:1 1 auto;min-width:0}
/* Top-aligned with the NAME line — centring against a three-line affiliation
   left every button floating at a different height down the list. */
.fp-au .btn{flex:0 0 auto;margin-top:1px;white-space:nowrap}

/* The Format tool: options on the left, the page as it will paste on the
   right. */
.fmt-grid{display:flex;gap:16px;align-items:flex-start}
.fmt-side{flex:0 0 230px;min-width:0}
.fmt-main{flex:1 1 auto;min-width:0}
/* A DIV around each radio group, never a label — a caption label forwards
   caption clicks into the group's first radio. */
.fmt-group{display:block;margin-bottom:var(--sp-6)}
.fmt-cap{display:block;font-size:var(--fs-cap);color:var(--ink-3);margin-bottom:2px}
.fmt-opts{display:flex;flex-direction:column;gap:2px}
.fmt-opt{display:flex;gap:6px;align-items:center;font-size:var(--fs-ui);cursor:pointer;
  padding:2px 0}
.fmt-opt input{width:auto;margin:0}
.fmt-preview{border:1px solid var(--line);border-radius:var(--radius-sm);padding:14px 16px;
  font-family:var(--doc-font);font-size:13.5px;line-height:1.7;background:var(--panel);
  max-height:340px;overflow:auto}
.fmt-preview sup,.fmt-preview sub{color:var(--ob-ink);font-weight:700}
.fmt-emails{border:1px dashed var(--line);border-radius:var(--radius-sm);padding:8px 10px;
  font-size:var(--fs-sm);color:var(--ink-2);word-break:break-all}
@media (max-width:760px){.fmt-grid{flex-direction:column}.fmt-side{flex:1 1 auto}}

/* The collapse chevron in the rail head — drawn, and the same size as every
   other chevron on the rail. It was a 14px text ‹ beside 15px drawn twisties. */
.nav-collapse svg{width:16px;height:16px;display:block}

/* The Search row under the app head — Flywheel's slot: identity, then
   search, then the work. */
.nav-searchrow{display:flex;align-items:center;gap:8px;width:calc(100% - var(--sp-10));
  margin:2px var(--sp-5) 0;padding:7px 9px;background:#ffffff12;border:1px solid #ffffff1f;
  border-radius:var(--nv-radius,6px);font-family:inherit;font-size:var(--nv-item,13px);
  color:var(--nav-ink);cursor:pointer;text-align:left}
.nav-searchrow:hover{background:#ffffff1e}
.nav-searchrow svg{width:15px;height:15px;flex:0 0 auto;opacity:.85}
.nav-searchrow .lbl{flex:1 1 auto}
.nav-searchrow .kbd{flex:0 0 auto;font-size:10.5px;padding:1px 5px;border:1px solid #ffffff2e;
  border-radius:4px;color:var(--nav-ink-dim);letter-spacing:.04em}

/* HOME — a destination, not a section: as loud as the verb groups. */
.nav-row.nav-home{font-size:13.5px;font-weight:800;letter-spacing:.1em}
.nav-row.nav-home .mk svg{width:16px;height:16px}

/* The Home page's Recent rows. */
.recent-row{display:flex;align-items:center;gap:10px;padding:7px 4px;cursor:pointer;
  border-radius:var(--radius-sm)}
.recent-row:hover{background:var(--ob-wash)}
.recent-row .lbl{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-weight:600}
.recent-row .tag{flex:0 0 74px;text-align:center}

/* ==== THE FOUR SECTION HOMES (Write · Edit · Cite · Review) ==============
   A section home is read top to bottom once: what needs me, where I left off,
   what I can start. The styling has to hold that order — the attention strip
   is loud and unboxed, the cards below are quiet and uniform, and a row's
   signal sits between its name and its date where the eye already travels. */
.gh-head{margin:0 0 var(--sp-8)}
.gh-head h2{font-size:var(--fs-title, 21px);margin:0 0 2px;letter-spacing:-.01em}

/* Not a card. Giving it card chrome would make it one more box to read past,
   and the whole point is that it is the thing you deal with first. */
.gh-att{display:flex;flex-direction:column;gap:var(--sp-3);margin-bottom:var(--sp-9)}
.gh-att-row{display:flex;align-items:center;gap:var(--sp-6);width:100%;text-align:left;
  padding:var(--sp-5) var(--sp-7);border:1px solid var(--line);border-left:3px solid var(--ink-4);
  border-radius:var(--radius-sm);background:var(--panel);color:var(--ink);
  font:inherit;font-size:var(--fs-ui);cursor:pointer;transition:background .12s,border-color .12s}
.gh-att-row:hover{background:var(--surface-hover)}
.gh-att-row.bad{border-left-color:var(--red)}
.gh-att-row.warn{border-left-color:var(--amber)}
.gh-att-t{flex:1 1 auto;min-width:0}
.gh-att-go{flex:0 0 auto;font-size:var(--fs-micro);font-weight:700;color:var(--ac-ink);
  text-transform:uppercase;letter-spacing:.05em}

.gh-row{display:flex;align-items:center;gap:var(--sp-6);padding:var(--sp-5) var(--sp-4);
  cursor:pointer;border-radius:var(--radius-sm);border-bottom:1px solid var(--line-2)}
.gh-row:last-child{border-bottom:0}
.gh-row:hover{background:var(--surface-hover)}
.gh-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-weight:620;font-size:var(--fs-ui)}
.gh-name .ms-full{display:block;font-weight:400;font-size:var(--fs-micro);color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis}
/* The signals wrap rather than squeeze the name: on a narrow pane the name is
   still the thing you are reading down the column for. */
.gh-tags{flex:0 1 auto;display:flex;gap:var(--sp-3);flex-wrap:wrap;justify-content:flex-end}
.gh-when{flex:0 0 auto;font-size:var(--fs-micro);color:var(--ink-4);
  font-variant-numeric:tabular-nums;white-space:nowrap}

.gh-stats{display:flex;flex-wrap:wrap;gap:var(--sp-9)}
.gh-stat{display:flex;flex-direction:column;gap:1px}
.gh-stat b{font-size:var(--fs-lead, 19px);font-weight:700;line-height:1.1;
  font-variant-numeric:tabular-nums}
.gh-stat span{font-size:var(--fs-micro);color:var(--ink-3)}

.gh-chips{display:flex;flex-wrap:wrap;gap:var(--sp-4)}
.gh-chip{display:inline-flex;align-items:baseline;gap:6px;padding:5px 11px;cursor:pointer;
  border:1px solid var(--line);border-radius:999px;background:var(--surface-2);
  color:var(--ink);font:inherit;font-size:var(--fs-ui);font-weight:600}
.gh-chip:hover{border-color:var(--ac-fill);color:var(--ac-ink);background:var(--ac-wash)}
.gh-chip .n{font-size:var(--fs-micro);color:var(--ink-4);font-weight:700}
.gh-chip .sub{font-size:var(--fs-micro);color:var(--ink-4);font-weight:400}

@media (max-width:640px){
  /* The date is the first thing to go: on a phone the name and its signal are
     what the row is for, and a relative timestamp is the least of the three. */
  .gh-when{display:none}
  .gh-row{flex-wrap:wrap;gap:var(--sp-3)}
  .gh-tags{width:100%;justify-content:flex-start}
  .gh-stats{gap:var(--sp-7)}
}

/* ⌘K — the jump palette. Above everything, dismissed by Esc or the backdrop. */
.cmdk{position:fixed;inset:0;background:rgba(16,24,40,.4);z-index:520;
  display:flex;align-items:flex-start;justify-content:center;padding-top:12vh}
.cmdk-card{width:min(560px,92vw);background:var(--panel);border-radius:var(--radius);
  border:1px solid var(--line);box-shadow:0 18px 60px rgba(16,24,40,.35);overflow:hidden}
.cmdk-in{width:100%;border:0;border-bottom:1px solid var(--line-2);border-radius:0;
  padding:13px 16px;font-size:var(--fs-md);background:var(--panel);color:var(--ink)}
.cmdk-in:focus{outline:none;box-shadow:none}
.cmdk-list{max-height:46vh;overflow:auto;padding:6px}
.cmdk-row{display:flex;align-items:center;gap:10px;padding:8px 10px;cursor:pointer;
  border-radius:var(--radius-sm)}
.cmdk-row .lbl{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmdk-row.sel,.cmdk-row:hover{background:var(--ob-wash)}

/* A boilerplate row: title and freshness left, the two verbs right. The row
   itself opens the editor. */
.bp-row{display:flex;align-items:center;gap:8px;padding:7px 8px;margin-bottom:4px;
  border:1px solid var(--line);border-radius:var(--radius-sm);cursor:pointer}
.bp-row:hover{background:var(--ob-wash)}
.bp-row .lbl{flex:1 1 auto;min-width:0}
.bp-row .btn{flex:0 0 auto}

/* Pending manuscript invitations, each with its two verbs. */
.pend-row{display:flex;align-items:center;gap:6px;padding:3px 0;font-size:var(--fs-sm)}

/* The console's per-app seats sub-table sits inside its team's row. */
.cons-appseats > td{background:var(--ob-wash);padding:6px 10px 10px}
.cons-appgrid{margin:0}
.cons-appgrid td,.cons-appgrid th{padding:4px 8px}

/* "Review its references" — a long checklist that scrolls inside the dialog. */
.rr-list{max-height:380px;overflow:auto;border:1px solid var(--line);
  border-radius:var(--radius-sm);padding:4px}
.rr-row{display:flex;gap:8px;align-items:flex-start;padding:6px 8px;cursor:pointer;
  border-radius:var(--radius-sm);font-size:var(--fs-sm);line-height:1.45}
.rr-row:hover{background:var(--ob-wash)}
.rr-row input{width:auto;margin-top:2px;flex:0 0 auto}
.rr-row .rr-t{min-width:0}
.rr-off{opacity:.55;cursor:default}

/* The person form's affiliation section — visibly its own thing, because the
   links are to SHARED book entries, not fields of this person. */
.ca-affsec{margin-top:14px;padding-top:12px;border-top:1px solid var(--line-2)}
.ca-affsec-h{font-weight:700;margin-bottom:8px}
.cpa-scopes{display:flex;gap:6px;margin-bottom:4px}

/* An ORCID candidate: the whole identity on two lines, because rows that read
   "Alex Hall (0000-…)" eight times over are unpickable. */
.orc-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.orc-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--fs-sm);
  color:var(--ink-3)}
.orc-insts{margin-top:2px}

/* One affiliation of the pool. Collapsed it is the PRINTED line — doc face,
   superscript first, nothing editable — so the shut list reads exactly as it
   will under the masthead. Open, the head keeps the number and the field grid
   drops below: the grid wraps WHOLE fields (department and institution wide,
   the address trio narrow) — a plain flex row used to snap mid-list and
   orphan State and Country on their own line. */
.aff-entry{border:1px solid var(--line);border-radius:var(--radius-sm);margin-bottom:8px}
.aff-head{display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;
  border-radius:var(--radius-sm)}
.aff-head:hover{background:var(--ob-wash)}
.aff-entry.open .aff-head{border-bottom:1px solid var(--line);
  border-radius:var(--radius-sm) var(--radius-sm) 0 0}
.aff-hn{font-weight:800;color:var(--ink-3)}
.aff-line{font-family:var(--doc-font);font-size:13.5px;line-height:1.5;
  color:var(--ink-2);min-width:0}
.aff-line sup{color:var(--ob-ink);font-weight:700}
.aff-body{display:flex;gap:10px;align-items:flex-start;padding:8px 12px 4px}
/* auto-fit with a floor, NOT fixed spans: the centre column's width depends on
   which viewer panes are open, and a media query only knows the window. Every
   field keeps a typable width and whole fields wrap together at any pane
   size. */
.aff-grid{flex:1 1 auto;min-width:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:0 10px}
.aff-grid .fld{min-width:0}
.aff-w,.aff-nw{min-width:0}
.aff-ops{flex:0 0 auto;display:flex;gap:4px;align-items:center;padding-top:20px}

/* The folder's ⋯. PERMANENT, like .nav-add above — the hidden-until-hover
   rail control was unlearnable and is gone by Alex's call (2026-08-14). */
.nav-more{
  flex:0 0 auto;margin-left:var(--sp-3);width:22px;height:22px;padding:0;
  border:0;border-radius:var(--radius-sm);background:none;color:inherit;
  font:inherit;line-height:1;cursor:pointer;opacity:.9;
  /* Centred rather than baseline-dropped: the glyph is a drawn SVG now, and a
     22px box sized for a text character leaves it sitting low. */
  display:inline-flex;align-items:center;justify-content:center
}
.nav-more .kebab{width:14px;height:14px}
.ci-more .kebab,.ci-add .kebab{width:14px;height:14px}
.nav-more:focus-visible{opacity:1}
.nav-more:hover{background:#ffffff1f;opacity:1}
.nav-more:focus-visible{outline:2px solid #ffffff5c;outline-offset:-2px}
/* The count slides out of the way rather than the ⋯ overlapping it. */
.nav-row.nav-folder:hover .val{opacity:.6}

/* ==== appshell — the front door for a live suite app that is not this bundle
   (js/appshell.js). Wears the suite's slate, not the app accent: until the
   app's own web build mounts, this page belongs to Opus Bench. */
.appshell{position:fixed;inset:0;z-index:40;overflow:auto;background:var(--bg);
  display:flex;align-items:flex-start;justify-content:center;
  padding:9vh var(--sp-6) var(--sp-10)}
.appshell-card{max-width:560px;width:100%;background:var(--panel);
  border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--sp-9) var(--sp-10);box-shadow:0 10px 40px #0000001f}
.appshell-head{display:flex;align-items:center;gap:var(--sp-6);
  margin-bottom:var(--sp-6)}
.appshell-name{font-size:1.35rem;font-weight:700}
/* --fs-sm. There is no `--fs-small` in the scale, so this declaration was
   invalid and the tagline took whatever size it inherited — the same silent
   failure as the recorded `--r-sm` / `--radius-sm` pair, and just as hard to
   see, because a bad custom property drops that one declaration and nothing
   else complains. */
.appshell-tag{color:var(--ink-3);font-size:var(--fs-sm)}
.appshell-lead{font-size:var(--fs-lead);margin:0 0 var(--sp-5)}
.appshell-sec{font-size:var(--fs-micro);font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--ob-ink);margin:var(--sp-7) 0 var(--sp-3)}
.appshell-p{margin:0 0 var(--sp-3);color:var(--ink)}
.appshell-ul{margin:0;padding-left:1.2em}
.appshell-ul li{margin-bottom:var(--sp-2)}
.appshell-foot{display:flex;justify-content:space-between;gap:var(--sp-4);
  margin-top:var(--sp-8)}
.appshell-status{margin:0 0 var(--sp-5)}
.appshell-foot{justify-content:flex-start}
/* "Web edition soon" sits beside a WORKING Launch, so it must not wear the
   same accent as "Coming soon" — that chip means the button is dead. */
.hub-chip.soft{
  background:var(--surface-2);color:var(--ink-3);border-color:var(--line);
  font-weight:600;margin-top:3px;text-transform:none;letter-spacing:.01em}

/* The little (i) beside a role picker. A circle, not a glyph in a font that may
   not have it, and sized as something you can actually hit — the whole reason
   it exists is that "Editing author" does not explain itself. */
.role-i{display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;border-radius:50%;border:1px solid var(--line);
  background:var(--panel);color:var(--ink-3);
  font:600 11px/1 -apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;
  font-style:italic;cursor:help;vertical-align:middle;margin-left:4px;text-transform:none}
.role-i:hover{border-color:var(--ob-edge);color:var(--ink)}

/* The CILogon explainer on the gate. A note, not a warning: the person has done
   nothing wrong, they are simply about to land on a page that asks them to find
   their university in a list of thousands, and "my institution isn't there" is
   the commonest reason somebody gives up before they start. */
.gate-note{display:flex;gap:8px;align-items:flex-start;margin:10px 0 2px;
  padding:10px 12px;border:1px solid var(--line);border-radius:8px;
  background:var(--surface-2);color:var(--ink-2);
  font:400 12.5px/1.5 -apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif}
.gate-note-i{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;margin-top:1px;border-radius:50%;border:1px solid var(--line);
  background:var(--panel);color:var(--ink-3);font:italic 600 11px/1 Georgia,serif}
/* THE SSO ROW. CILogon takes whatever width is left and the shortcuts are
   square, so the hierarchy is legible before a single word is read: one door,
   two handles. flex-wrap so a narrow phone stacks them rather than crushing the
   primary button to a stub. */
.gate-sso{display:flex;flex-wrap:wrap;align-items:stretch;gap:8px;margin-top:var(--sp-5)}
/* flex-basis 0, not auto: .gate-oauth carries width:100% for the stacked case,
   and an `auto` basis would honour it, claim the whole row and wrap the two
   shortcuts onto a line of their own. */
.gate-sso .gate-oauth{flex:1 1 0;width:auto;min-width:0;margin-top:0}
/* Square, and the SAME height as the button beside it — matched off gate-oauth's
   min-height rather than a second number that would drift from it. */
/* A BARE MARK WITH A FULL-SIZE HIT AREA. No border, no fill, no box — just the
   glyph — but still 44px square to press, which is the touch minimum and the
   reason the padding is on the button rather than the icon. */
.gate-bare{flex:0 0 auto;width:44px;height:44px;min-height:44px;padding:0;border:0;
  background:none;border-radius:var(--radius);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center}
.gate-bare:hover{background:var(--ob-wash)}
.gate-bare:focus-visible{outline:2px solid var(--gate-blue);outline-offset:1px}
.gate-sso .gate-bare{flex:0 0 44px}
.gate-sq .gate-note-i{margin-top:0}
/* The bare button has no box to tint; the disc inside it carries the state. */
/* ORCID's own green — the REAL one. #a6ce39 is the brand green and it is a pale
   yellow-green: at 18px on white it read as a smudge. The mark is half again as
   large now and drawn in the darker tone ORCID itself uses on light backgrounds,
   which is legible without ceasing to be their colour. */
.gate-orcid{color:#a6ce39}
.gate-orcid:hover{color:#8fb52c}
.gate-orcid .gate-oauth-ic{width:27px;height:27px}

/* THE (i) IS THE ORCID MARK'S TWIN. Same 27px disc, same 44px hit area, one at
   each end — so the row is symmetrical about the button in the middle, which is
   the only thing anybody is meant to press. Sized off the same number rather
   than eyeballed: if one changes the other has to, and this is where you would
   look for it.

   Drawn as an outline where ORCID is filled, because it is an explainer and not
   a way in — the shape matches, the weight does not. */
.gate-sso .gate-note-i{width:27px;height:27px;margin-top:0;
  border:1.5px solid var(--line-strong);color:var(--ink-3);
  font:italic 700 15px/1 Georgia,serif;background:transparent}
.gate-sso .gate-info:hover .gate-note-i{border-color:var(--ink-3);color:var(--ink-2)}
.gate-sso .gate-info[aria-expanded="true"] .gate-note-i{
  border-color:var(--gate-blue);color:var(--gate-blue);background:var(--ob-wash)}

/* The service entrance stands alone in the small print now. */
.gate-staff{display:flex;align-items:center;justify-content:center}
/* The explainer is a block of prose once opened, not a row with a glyph in it —
   the glyph is now the button that opened it. */
.gate-help{display:block}
.gate-help[hidden]{display:none}
.gate-signup{margin-top:14px;text-align:center}
.gate-signup .hint{margin-top:4px}

/* The co-author search: an input with a hit list anchored beneath it. Absolute
   inside a relative wrapper, so the dialog does not reflow as results come and
   go — a form that jumps while you type reads as broken. */
.collab-find{position:relative}
.collab-hits{position:absolute;left:0;right:0;top:100%;z-index:30;margin-top:4px;
  background:var(--panel);border:1px solid var(--line);border-radius:8px;
  box-shadow:var(--shadow);max-height:240px;overflow-y:auto;padding:4px}
.collab-hit{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  border:0;background:none;padding:8px 10px;border-radius:6px;cursor:pointer;
  font:inherit;color:var(--ink)}
.collab-hit:hover{background:var(--surface-hover)}
.collab-hit .tag{margin-left:auto;flex:0 0 auto}
.collab-hit.is-empty{cursor:default;color:var(--ink-3)}
.collab-hit.is-empty:hover{background:none}

/* The presubmit report. A screening report is read as a list of verdicts, so
   each row is one fact with a coloured dot: red blocks a submission, amber is
   worth fixing, grey is a note, green passed. Passes are shown deliberately —
   "all figures are cited" is only reassuring because somebody checked. */
.ps-row{display:flex;align-items:flex-start;gap:var(--sp-8);
  padding:var(--sp-8) var(--sp-12);border-top:1px solid var(--line-2)}
.ps-row:first-child{border-top:0}
.ps-row.is-ok .ps-label{color:var(--ink-2);font-weight:500}
.ps-txt{flex:1 1 auto;min-width:0}
.ps-label{font-weight:650;color:var(--ink)}
.ps-dot{flex:0 0 auto;width:9px;height:9px;border-radius:50%;margin-top:6px;
  background:var(--ink-4)}
.ps-dot.high{background:var(--red,#c0392b)}
.ps-dot.med{background:var(--amber,#e08e0b)}
.ps-dot.low{background:var(--ink-4)}
.ps-dot.ok{background:var(--green,#2e9e5b)}

/* ==== the review-link page (js/shareview.js) — /read/{token} ==============
   A public reader with no app behind it. Paper-first: the manuscript is the
   page, everything else stays small and stays out of the margins. The paper
   itself is styled by the export's own docCss, injected beside it — this
   block styles only the chrome around it. */
.shv{position:fixed;inset:0;z-index:300;overflow:auto;background:var(--surface-2)}
.shv-bar{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:10px;
  padding:10px 18px;background:var(--panel);border-bottom:1px solid var(--line);
  box-shadow:0 2px 14px #00000014}
.shv-who{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
.shv-who b{font-size:var(--fs-ui);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.shv-ncount{flex:0 0 auto;font-size:var(--fs-cap);color:var(--ac-ink);
  background:var(--ac-wash);border:1px solid var(--ac-edge);border-radius:999px;padding:2px 10px}
.shv-main{max-width:8.2in;margin:0 auto;padding:26px 16px 80px}
/* ROOM FOR A MARGIN, on screens that have it. The page widens only enough to
   carry the rail; everything that is not the paper stays at reading width, so
   the form does not stretch to fill a column it does not need. */
/* 1180px excluded a great many laptops and any window that is not maximised —
   and below it the comments were only in the list under the paper, which is
   where nobody scrolls. The paper gives up a little width instead so the margin
   starts earlier; below 1000px there is genuinely nowhere to put it and the
   lists take over. */
@media (min-width:1000px){
  .shv-main{max-width:calc(8.2in + 300px)}
  .shv-main > *:not(.shv-paperwrap){max-width:8.2in}
  .shv-paperwrap{display:grid;grid-template-columns:minmax(0,8.2in) minmax(240px,280px);
    gap:16px;align-items:start}
}
.shv-paper{background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:.9in .8in;box-shadow:0 10px 40px #0000001a}
/* The paper is black-on-white in BOTH themes, like every export — what you
   are reading is what would be submitted, and submissions have no dark mode. */
.shv-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:18px 20px;margin-top:18px}
.shv-card h2,.shv-card h3{margin:0 0 6px}
/* THE FORM GRID. `auto-fit,minmax(180px,1fr)` gave every field the same width,
   so MI and Country came out as wide as a name and the rows broke wherever the
   viewport happened to fall. Alex specified the rows and the proportions
   instead, so the grid is 24 columns and each field says how many it takes —
   which is the only way "First, MI (small), Last, degrees (small), email,
   orcid, all on one row" can survive a resize.

   DESKTOP / iPAD: name row · department+institution · city/state/country.
   The spans are declared per field below rather than per row, because the row
   IS the sum reaching 24. */
.shv-form{display:grid;grid-template-columns:repeat(24,1fr);gap:var(--sp-5) var(--sp-4)}
.shv-form .fld{min-width:0}
/* The row adds to 24 exactly, so email finishes flush with the card's edge
   rather than stopping short of it — and a surname gets more room than a set of
   initials, which is the wrong way round when they are the same width. */
.shv-f-first{grid-column:span 5}
.shv-f-mi{grid-column:span 2}
.shv-f-last{grid-column:span 6}
.shv-f-deg{grid-column:span 3}
.shv-f-email{grid-column:span 8}
.shv-f-orcid{grid-column:1 / span 12}
.shv-f-dept{grid-column:span 12}
.shv-f-inst{grid-column:span 12}
.shv-f-city{grid-column:span 9}
.shv-f-state{grid-column:span 6}
.shv-f-country{grid-column:span 9}
/* Kept for the older two-up rows elsewhere on the page. */
.shv-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:8px 12px;margin:10px 0 14px}
.shv-actions{display:flex;gap:10px;flex-wrap:wrap}
.shv-chip{position:absolute;z-index:400;padding:5px 12px;font-size:var(--fs-cap);
  font-weight:650;color:var(--ac-on);background:var(--ac-fill);border:0;
  border-radius:999px;cursor:pointer;box-shadow:0 4px 16px #00000033}
.shv-notes{margin-top:18px}
.shv-notes h3{margin:0 0 8px}
.shv-note{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:10px 12px;margin-bottom:8px}
.shv-quote{font-style:italic;color:var(--ink-3);font-size:var(--fs-sm);margin-bottom:4px}
.shv-ntext{margin-bottom:6px}
.shv-rnotes{margin-top:6px}

/* ---- the reader page: status, folding, note markers, line numbers ---- */

/* THE HEADER GETS A SECOND ROW. Row one is what this is; row two is what is
   wanted from you, by when, and whether you have done it. */
.shv-bar{flex-direction:column;align-items:stretch;gap:6px}
.shv-barmain{display:flex;align-items:center;gap:10px;min-width:0}
.shv-status{display:flex;flex-wrap:wrap;gap:6px}
.shv-pill{display:inline-flex;align-items:center;gap:5px;padding:2px 10px;
  border-radius:999px;font-size:var(--fs-cap);font-weight:600;white-space:nowrap;
  border:1px solid transparent}
.shv-pill.bad{background:var(--red-bg);color:var(--red);border-color:var(--red-line)}
.shv-pill.good{background:var(--green-bg);color:var(--green);border-color:var(--green-line)}
.shv-pill.warn{background:var(--amber-bg);color:var(--amber);border-color:var(--amber-line)}
.shv-pill.flat{background:var(--surface-2);color:var(--ink-3);border-color:var(--line)}

/* FOLDED TO THE FIRST ROW. Not shut — the name row shows through, so the card
   reads as a form with blanks in it rather than as a closed drawer somebody
   has to guess the contents of. */
.shv-foldhead{display:flex;align-items:center;gap:var(--sp-4);width:100%;
  background:none;border:0;padding:0 0 8px;cursor:pointer;text-align:left;color:inherit}
.shv-foldtitle{font-size:var(--fs-ui);font-weight:700;flex:1 1 auto;min-width:0}
.shv-dot{color:var(--ink-4);margin:0 2px}
.shv-send.folded .shv-foldhide{display:none}
.shv-send.folded .shv-form{opacity:.75}
.shv-send.done{opacity:.9}
.shv-decline{margin-left:auto;color:var(--ink-3);font-size:var(--fs-cap)}
.shv-decline:hover{color:var(--red)}
.shv-actions{align-items:center}

/* HOW TO LEAVE A NOTE, said where somebody will read it. */
.shv-howto{background:var(--surface-2);border:1px dashed var(--line);
  border-radius:var(--radius-sm);padding:8px 12px;margin:0 0 12px;
  font-size:var(--fs-sm);color:var(--ink-2)}

/* WHERE THE NOTE IS. The mark carries its number in the margin so the list and
   the paper agree without anybody counting. */
.shv-paperwrap{position:relative}
.shv-mk{background:var(--amber-bg);color:inherit;border-bottom:2px solid var(--amber-line);
  padding:0 1px;border-radius:2px;cursor:pointer}
.shv-mk::after{content:attr(data-n);font-size:9px;vertical-align:super;font-weight:700;
  color:var(--amber);margin-left:2px}
.shv-mk.flash{animation:shvflash 1.2s ease}
@keyframes shvflash{0%,100%{background:var(--amber-bg)}35%{background:var(--amber)}}
/* A NOTE ALREADY SENT reads in the rail's blue rather than the amber of one
   still being written — the same two colours the cards beside them use, so a
   passage and its card are obviously the same thing. It carries no number:
   the numbers count what is about to be submitted. */
.shv-mk-c{background:var(--surface-sel);border-bottom-color:var(--blue)}
.shv-mk-c.flash{animation:shvflashc 1.2s ease}
@keyframes shvflashc{0%,100%{background:var(--surface-sel)}35%{background:var(--rail)}}
.shv-railnote.flash{animation:shvcardflash 1.2s ease}
@keyframes shvcardflash{0%,100%{background:var(--panel)}35%{background:var(--surface-sel)}}
.shv-nhead{display:flex;align-items:center;gap:8px;margin-bottom:4px}
.shv-nnum{display:inline-flex;align-items:center;justify-content:center;min-width:20px;
  height:20px;border-radius:999px;background:var(--amber-bg);color:var(--amber);
  font-size:var(--fs-cap);font-weight:700}
.shv-note[data-svact="gotonote"]{cursor:pointer}
.shv-note[data-svact="gotonote"]:hover{border-color:var(--blue-line)}
.shv-nacts{display:flex;gap:6px}

/* The two switches over the paper — what is being shown, and where. */
.shv-showbar{display:flex;align-items:center;gap:var(--sp-6);flex-wrap:wrap;
  margin:0 0 8px;font-size:var(--fs-sm);color:var(--ink-2)}
.shv-showbar-k{font-size:var(--fs-cap);text-transform:uppercase;letter-spacing:.05em;
  color:var(--ink-3);font-weight:700}
/* SHOWN ONCE. With a margin in use the cards are beside their sentences; the
   lists below would then be the same comments a second time, which reads as
   twice as many comments as there are. */
.shv-main.has-margin #shvTalk,
.shv-main.has-margin #shvNotes{display:none}
.shv-showbar label{display:inline-flex;align-items:center;gap:6px;cursor:pointer}
.shv-showbar input{width:auto;margin:0}

/* A comment already on the paper reads differently from a note being written:
   quieter, and blue rather than the amber of an unsent note. */
.shv-railtalk{border-left-color:var(--blue)}
.shv-railtalk.done{opacity:.6}

/* ---- the margin rail ---- */
/* Declared AFTER the wide-screen block above, so the reveal has to live here
   too: two rules of equal specificity are settled by order, and the earlier
   `display:block` lost to this `display:none` every time. */
.shv-rail{display:none;position:relative;min-height:100%}
@media (min-width:1000px){ .shv-rail{display:block} }
.shv-railnote{position:absolute;left:0;width:100%;background:var(--panel);
  border:1px solid var(--line);border-left:3px solid var(--amber);
  border-radius:var(--radius-sm);padding:10px 12px;cursor:pointer;
  transition:border-color .12s,box-shadow .12s}
.shv-railnote:hover{border-color:var(--amber);box-shadow:0 2px 10px rgba(0,0,0,.10)}
.shv-railnote .shv-quote{font-size:var(--fs-cap);margin-bottom:4px}
.shv-railnote .shv-ntext{font-size:var(--fs-sm);margin-bottom:6px}

/* ---- the state block: Alex's plate, badge and round control ---- */
/* IN THE HEAD, TOP RIGHT: state, an explainer, and the fold mark, on one line
   with the card's title. Out of the form grid entirely, so the name row is only
   fields and each of them is as wide as it should be. */
.shv-state{margin-left:auto;display:inline-flex;align-items:center;gap:10px;
  flex:0 0 auto}
.shv-state-chip{position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:auto;min-height:0;
  padding:4px 12px;border-radius:999px;text-align:center;white-space:nowrap;
  font-weight:700;font-size:var(--fs-cap);line-height:1.2;
  border:2px dotted var(--red);color:var(--red);background:var(--red-bg)}
.shv-state-info{width:20px;height:20px;flex:0 0 auto;border-radius:50%;cursor:help;
  border:1px solid var(--line);background:var(--surface-2);color:var(--ink-3);
  font-style:italic;font-weight:700;font-size:11px;line-height:18px;text-align:center;
  font-family:Georgia,serif;display:inline-block}
.shv-state-info:hover{border-color:var(--blue);color:var(--ac-ink)}
.shv-state.good .shv-state-chip{border-style:solid;border-color:var(--green);
  color:var(--green);background:var(--green-bg)}
.shv-state.flat .shv-state-chip{border-style:solid;border-color:var(--line);
  color:var(--ink-3);background:var(--surface-2)}
/* IN THE PILL, NOT OVER IT. Absolutely positioned on the corner it sat on top
   of the last letter of the label — fine when the plate was a wide block in the
   form grid, wrong the moment it became a pill sized to its text. Part of the
   flex row, it can never overlap whatever the label happens to say. */
.shv-state-badge{flex:0 0 auto;margin-left:8px;
  width:18px;height:18px;border-radius:50%;display:inline-grid;place-items:center;
  background:var(--red);color:#fff;font-size:11px;font-weight:800;line-height:1}
.shv-state.good .shv-state-badge{background:var(--green)}
.shv-state.flat .shv-state-badge{background:var(--ink-4)}

.shv-state-go{width:34px;height:34px;flex:0 0 auto;border-radius:50%;
  background:#2f5686;color:#fff;display:inline-grid;place-items:center;
  box-shadow:0 2px 8px rgba(47,86,134,.30);transition:transform .15s ease}
.shv-foldhead:hover .shv-state-go{background:#24456d}
.shv-send:not(.folded) .shv-state-go{transform:rotate(180deg)}
/* The conversation already on the paper, shown to the person being asked. */
.shv-said{opacity:1}
.shv-said.done{opacity:.6}
.shv-extmark{font-size:var(--fs-cap);font-weight:600;padding:1px 7px;border-radius:999px;
  background:var(--amber-bg);color:var(--amber);border:1px solid var(--amber-line)}
.shv-said-reply{margin-top:6px;padding-left:10px;border-left:2px solid var(--line);
  font-size:var(--fs-sm);color:var(--ink-2)}

/* Line numbers on this page come from js/linenums.js — the same module the
   PDF uses — so there is no gutter of our own to style here. */

@media (max-width:760px){
  /* ALEX'S MOBILE ROWS: name row, email, department+institution, city/state/
     country, orcid. Same DOM, different spans — the page does not need a second
     form to be a different shape. */
  .shv-f-first{grid-column:span 8}
  .shv-f-mi{grid-column:span 4}
  .shv-f-last{grid-column:span 8}
  .shv-f-deg{grid-column:span 4}
  .shv-f-email{grid-column:span 24}
  .shv-f-orcid{grid-column:1 / span 24}
  /* No margin to put it in, so the plate and its control lie flat across the
     top of the form instead of standing in a column beside it. */
  /* On a phone the head wraps; the state keeps its own line under the title
     rather than squeezing it. */
  .shv-foldhead{flex-wrap:wrap;row-gap:8px}
  .shv-state{margin-left:0;width:100%;justify-content:space-between}
  .shv-f-dept{grid-column:span 12}
  .shv-f-inst{grid-column:span 12}
  .shv-f-city{grid-column:span 10}
  .shv-f-state{grid-column:span 6}
  .shv-f-country{grid-column:span 8}
  .shv-actions .btn{width:100%}
  .shv-actions .btn.xs,.shv-decline{width:auto}
}
@media (max-width:640px){
  .shv-paper{padding:22px 16px}
  .shv-main{padding:12px 8px 60px}
}


/* ==== The suite on a PHONE (Alex's screenshot, 2026-08-15) =================
   The landing page was desktop chrome shrunk: the brand wrapped to two lines,
   each tile crammed icon, name, tagline and a floating Launch pill into one
   row so the pills landed wherever the names pushed them, the expand chevron
   sat as a stray smudge, and the Users roster CLIPPED off the right edge with
   the far columns simply unreachable. On a phone the tile is two rows —
   identity, then a full-width 44px Launch, the iOS minimum tap target — the
   chevron docks to the card's corner, and anything wider than the screen
   scrolls INSIDE its own card, the house rule everywhere else. */
@media (max-width:520px){
  .hub-bar{padding:10px 12px;gap:8px}
  .hub-brand-name{white-space:nowrap;font-size:var(--fs-ui)}
  .hub-bar-right{gap:2px}
  .hub-icbtn{width:38px;height:38px}
  .hub-wrap{padding:var(--sp-8) var(--sp-5) 56px}
  .hub-tile{position:relative}
  /* Launch sits on the RIGHT, centred against the logo — the same spot on
     every card because it is margin-positioned, not pushed around by however
     long the app's name runs (Alex: "equally positioned up and down with
     logo to left"). The name and tagline truncate instead of shoving it. */
  .hub-tile-head{flex-wrap:nowrap;align-items:center}
  .hub-tile-head > div{min-width:0}
  .hub-tile-name,.hub-tile-tag{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .hub-btn-go{flex:0 0 auto;margin-left:auto;height:40px;min-width:88px;
    padding:0 14px;font-size:var(--fs-ui)}
  /* CENTRED under the card, as on desktop — the corner was my invention and
     read as a stray control up there (Alex, 2026-08-15). Condensed: a wide,
     short press strip rather than a floating dot, so it costs the card
     almost no height but the whole strip is tappable. */
  .hub-tile-more{position:static;width:100%;margin:2px 0 -2px;padding:2px 0 4px}
  /* The roster is WIDER than a phone by nature — names, emails, roles. It
     scrolls inside its card; clipping it lost the Status column entirely. */
  .hu-listwrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .hu-table{min-width:560px}
  .hu-head{flex-wrap:wrap;row-gap:8px}
  .hu-invite{flex:1 1 100%;justify-content:center;height:44px}
  .hu-bar{flex-wrap:wrap;row-gap:8px}
}
/* Toasts clear the iPhone home indicator and Safari's floating bar — they sat
   exactly where the browser chrome is, layered over the last list rows. */
#toasts{bottom:calc(var(--sp-12) + env(safe-area-inset-bottom, 0px));
  max-width:calc(100vw - 24px)}


/* ==== Stylus bars on a PHONE (Alex, 2026-08-15) ============================
   Under 640px the topbar's words fold away and the icons carry the buttons —
   every control keeps its title for the long-press/tooltip, and the caret
   still says "menu". The sidebar-opener grows to a real thumb target: it is
   the only way back to the rail, which holds the whole manuscript's
   navigation. The formatting bar stops wrapping into a three-row wall and
   becomes ONE row that scrolls sideways inside itself — the house rule for
   anything wider than the screen — with 38px targets. */
@media (max-width:640px){
  /* THE DIALOG TAKES THE SCREEN on a phone, and its header stops eating it. A
     three-line manuscript title in the head left the body a slot to peer
     through; clamped to two lines it is still identifiable and the form below
     is usable. */
  /* .modal.lg and .modal.xl carry two classes and so beat a bare .modal
     however late it appears — the round dialog is `lg`, kept its
     min(980px,100%), and hung 20px off the right of a 375px screen with the
     primary button under the edge. All three named, and the scrim's 32px
     inset cut back so a phone dialog is not framed like a desktop one. */
  .scrim{padding:var(--sp-5)}
  .modal,.modal.lg,.modal.xl{width:100%;max-width:100%;
    max-height:92vh;max-height:92dvh}
  .modal-head{padding:var(--sp-6) var(--sp-7)}
  .modal-head h3{font-size:var(--fs-md);line-height:1.35;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .modal-body{padding:var(--sp-7)}
  .modal-foot{padding:var(--sp-6) var(--sp-7)}
  /* The buttons that finish a dialog get the full width between them rather
     than huddling at the right on a 375px screen. */
  .modal-foot .btn{flex:1 1 0;justify-content:center}

  /* THE LIBRARY'S TOOLBAR IS ONE ROW that scrolls sideways inside itself —
     the house rule here for any control row wider than the screen. It wrapped
     into three ragged rows with the ⋯ stranded alone on the last one (Alex's
     screenshot, 2026-08-16). Uniform heights too: the sort select and the
     buttons were setting their own. */
  .cite-bar{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;
    scrollbar-width:none;align-items:center;gap:var(--sp-3)}
  .cite-bar::-webkit-scrollbar{display:none}
  /* `flex:1 1 100%; order:-1` survived from when search had its own row: inside
     a nowrap scroller it made search the full width of the bar AND put it
     first, so the sort, Add and ⋯ were pushed off the right-hand edge and had
     to be scrolled to. Sort leads, search takes what is left, and all four are
     on screen at 375px. */
  .cite-search{flex:1 1 70px}
  .cite-bar select{max-width:124px}
  .cite-bar > .btn,.cite-bar > select{flex:0 0 auto;height:38px;min-height:38px;
    padding-top:0;padding-bottom:0;white-space:nowrap}
  .tb{padding:var(--sp-4) var(--sp-4)}
  .tb-nav{width:42px;height:42px}
  .tb-nav svg{width:24px;height:24px}
  .tb .tb-lbl,.fmtbar .tb-lbl{display:none}
  .tb-right{gap:var(--sp-3)}
  .tb-right .btn{padding-left:10px;padding-right:10px;min-height:38px}
  .fmtbar{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;
    scrollbar-width:none}
  .fmtbar::-webkit-scrollbar{display:none}
  .fmtbar .tbb{flex:0 0 auto;min-width:38px;height:38px}
  .tbstate{display:none}
  .tb-quiet{gap:var(--sp-3)}
  /* The actions share the second row with the whole-document button and the
     stage, ending it on the right — see the ≤760px block, which sets the
     order and the auto margin that place them there. */
  .tb-right{flex:0 0 auto;margin-left:auto;justify-content:flex-end}
  .tb-wholebtn{display:inline-flex}   /* unchanged on phones: it was already here */
  /* …except the dashboard's creation row: five "＋ Thing" buttons stay one
     line and scroll sideways inside themselves. Start-aligned on purpose —
     a right-justified overflow row clips its FIRST buttons unreachably. */
  .tb-news{flex-wrap:nowrap;overflow-x:auto;justify-content:flex-start;
    -webkit-overflow-scrolling:touch;scrollbar-width:none}
  .tb-news::-webkit-scrollbar{display:none}
  /* Sized so all five fit a 375px screen WITHOUT the scroll being needed —
     the scroll stays as the safety net for narrower phones, but "slightly
     too big" meant everyone got a scrollbar for the sake of ~20px (Alex,
     2026-08-15). */
  /* One ＋ New on the heading row instead of five squeezed buttons — the
     menu behind it holds the same five verbs (Alex, 2026-08-15). */
  .tb-news{display:none}
  .tb-addwrap{display:flex;flex:0 0 auto;margin-left:auto}
}

/* The look-it-up bar at the top of Edit reference, and the collapsed shelf
   picker under it. The bar is a row that collapses on a phone rather than
   squeezing a DOI into sixty pixels. */
.cd-lookup{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:0 0 14px;
  padding:10px;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2)}
.cd-lookup input{flex:1 1 220px;min-width:0}
.cd-lookup .hint{flex:1 1 100%;margin:0}
.cd-shelf{margin-top:14px;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:8px 10px;background:var(--surface-2)}
.cd-shelf>summary{cursor:pointer;font-weight:660;font-size:var(--fs-sm)}

/* ===================================================== EDITABLE TABLES ==
   Column widths only bind under table-layout:fixed — without it the browser
   treats a width as a hint and a long cell simply overrides the one you just
   dragged, so the grip appears to do nothing on exactly the tables that need
   it most. Scoped to a table that HAS widths, so an untouched table keeps
   sizing itself to its content. */
.mstable{border-collapse:collapse}
.mstable:has(colgroup){table-layout:fixed}
.mstable.editing th,.mstable.editing td{position:relative}
.mstable.editing .tcell{display:block;min-height:1.2em;outline:none;word-wrap:break-word}
.mstable.editing .tcell:focus{box-shadow:inset 0 0 0 2px var(--ac-fill);border-radius:2px}

/* The grip straddles the boundary rather than sitting inside one cell, so the
   thing under the pointer is the line you are moving. It only shows on hover
   over the table: a row of permanent handles reads as chrome. */
.tcol-grip{position:absolute;top:0;right:-3px;width:7px;height:100%;cursor:col-resize;
  z-index:2;opacity:0;background:var(--ac-fill);transition:opacity .12s ease}
.mstable.editing:hover .tcol-grip{opacity:.22}
.tcol-grip:hover{opacity:.85 !important}
body.col-resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}
body.col-resizing .tcell{pointer-events:none}

/* The four formatting commands, over the cell being edited. Same floating
   pattern as the accept/reject bar, and it dies on the same scroll. */
.tcell-bar{position:fixed;z-index:6000;display:flex;gap:2px;padding:3px;
  border:1px solid var(--line-strong);border-radius:var(--radius-sm);
  background:var(--panel);box-shadow:0 6px 20px rgba(16,24,40,.16)}
.tcell-bar button{width:26px;height:24px;border:0;background:none;cursor:pointer;
  color:var(--ink-2);border-radius:3px;font-size:12px;line-height:1;padding:0}
.tcell-bar button:hover{background:var(--surface-hover);color:var(--ink)}

/* ---- tables and figures fold, the same way the authors block does ---- */
.asset-head{cursor:pointer;user-select:none}
.asset-head:hover{background:var(--surface-hover)}
.asset-head .btn,.asset-head .iconbtn{cursor:pointer}
.asset-card.shut .card-body{display:none}
/* Shut, the head is the whole card, so it says what is inside it. */
.asset-say{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:var(--fs-cap);color:var(--ink-3)}
.asset-dim{flex:0 0 auto;font-size:var(--fs-micro);font-weight:700;color:var(--ink-3);
  background:var(--surface-2);border:1px solid var(--line);border-radius:999px;padding:0 7px}

/* A selected block of cells. A wash rather than an outline: an outline on each
   cell draws the internal borders twice and the block stops reading as one
   thing. */
.mstable.editing th.tcell-sel,.mstable.editing td.tcell-sel{background:var(--surface-sel)}
.tcell-bar-sep{width:1px;align-self:stretch;background:var(--line);margin:0 2px}
.tcell-bar button[data-cellpick]{width:auto;padding:0 6px;font-size:var(--fs-micro);font-weight:700}
/* Alignment is a STATE, not an action — a cell is always aligned some way — so
   the current one stays lit rather than only responding to hover, the way the
   B/I/U buttons beside it do. A mixed selection lights none of the three, which
   is the honest answer for a range that disagrees with itself. */
.tcell-bar button[data-cellalign]{font-size:13px;line-height:1}
.tcell-bar button[data-cellalign].on{background:var(--ac-wash);color:var(--ac-ink)}
.tcell-bar-n{align-self:center;padding:0 6px;font-size:var(--fs-micro);color:var(--ink-3);
  white-space:nowrap}

/* Where a reference is cited: a tag you can press, not a label. Kept visually
   quieter than the amber "uncited" flag beside it — these are the normal case,
   and a row of loud chips on every reference would bury the one that is
   actually wrong. */
.tag.cite-at{cursor:pointer;border-style:dashed;font-weight:600}
.tag.cite-at:hover{background:var(--surface-sel);border-style:solid;color:var(--ink)}
/* A citation marker is a link under Ctrl/Cmd, and says so on hover. */
.blk [data-ref]{cursor:default}
.blk [data-ref]:hover{background:var(--surface-sel);border-radius:2px}
@keyframes flashrow{0%,100%{background:transparent}35%{background:var(--surface-sel)}}
.flash-row{animation:flashrow 1.4s ease}

/* The emailed message, shown as it arrived so what you copy is what they get.
   Scrolls rather than growing: some rounds carry a long covering note. */
.mailprev{max-height:320px;overflow:auto;padding:12px;border:1px solid var(--line);
  border-radius:var(--radius-sm);background:var(--panel);font-size:var(--fs-sm)}
.mailprev img{max-width:100%}
.mailprev a{word-break:break-all}

/* Reply, on a comment in the reader's margin. Quiet until wanted — the rail is
   for reading, and a row of buttons down it competes with the paper. */
.shv-replybtn{margin-top:6px;border:1px solid var(--line);background:var(--panel);
  color:var(--ink-3);font-size:var(--fs-micro);font-weight:700;cursor:pointer;
  padding:2px 8px;border-radius:999px}
.shv-replybtn:hover{border-color:var(--blue);color:var(--blue)}

/* A row in dialog.choose. Column flex, and the children must be allowed to be
   narrower than their text — without min-width:0 a long title cannot shrink,
   so the row overflows the dialog and takes a horizontal scrollbar with it. */
.btn.pickrow{display:flex;flex-direction:column;align-items:stretch;gap:2px;
  width:100%;text-align:left;margin-bottom:8px;padding:10px 12px;height:auto;
  white-space:normal}
.btn.pickrow>b,.btn.pickrow>.hint{min-width:0;max-width:100%;
  overflow-wrap:anywhere;white-space:normal;line-height:1.35}
.btn.pickrow>.hint{margin:0}

/* Picking several references off the shelf at once. A row is a label so the
   whole line is a hit target, not just the 13px box. */
.lr-row{display:flex;gap:10px;align-items:flex-start;padding:8px 10px;cursor:pointer;
  border-bottom:1px solid var(--line-2)}
.lr-row:hover{background:var(--surface-hover)}
.lr-row input{flex:0 0 auto;margin-top:2px}
/* min-width:0 or a long citation refuses to wrap and the dialog scrolls
   sideways — the same fault the chooser rows had. */
.lr-txt{flex:1 1 auto;min-width:0;overflow-wrap:anywhere;font-size:var(--fs-sm);line-height:1.4}
.lr-row.had{opacity:.55;cursor:default}
.lr-row.had:hover{background:transparent}
.lr-had{flex:0 0 auto;font-size:var(--fs-micro);color:var(--ink-3);white-space:nowrap}

/* A citation marker in a superscript style (AMA, NEJM, Nature). line-height:0
   so raising it cannot open up the line it sits on — a paragraph full of
   citations would otherwise lead differently from one without. */
[data-ref].cite-sup{vertical-align:super;font-size:.78em;line-height:0}

/* A citation row being held for a combined marker. */
.pc-held{outline:2px solid var(--ac-fill);outline-offset:-2px;background:var(--surface-sel)}

/* ---- editing one inline citation ---- */
/* The preview leads, because it is the answer to the only question being
   asked: what will this look like in the sentence. */
.cite-prev{padding:10px 12px;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2);font-size:var(--fs-sm);margin-bottom:12px}
.cite-prev-m{font-family:var(--doc-font);font-size:1.05em}
.cite-prev-m.sup{vertical-align:super;font-size:.8em;line-height:0}
.cite-list{border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden}
.cite-row{display:flex;gap:8px;align-items:center;padding:7px 10px;
  border-bottom:1px solid var(--line-2)}
.cite-row:last-child{border-bottom:0}
.cite-n{flex:0 0 auto;min-width:22px;text-align:right;font-weight:700;color:var(--ink-3);
  font-size:var(--fs-cap)}
/* min-width:0 or a long citation refuses to shrink and pushes the buttons out
   of the dialog — the same flex trap as the chooser and library rows. */
.cite-txt{flex:1 1 auto;min-width:0;overflow-wrap:anywhere;font-size:var(--fs-sm);line-height:1.4}
.cite-row .iconbtn{flex:0 0 auto}
.cite-row .iconbtn[disabled]{opacity:.3;cursor:default}

/* The per-reference extras, under the row they belong to. Indented to the
   citation text rather than the row edge, so it reads as belonging to that
   reference and not to the list. */
.cite-extra{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end;
  padding:8px 10px 10px 34px;border-bottom:1px solid var(--line-2);background:var(--surface-2)}
.cite-extra label{display:flex;flex-direction:column;gap:2px;flex:1 1 120px;min-width:0;
  font-size:var(--fs-micro);font-weight:700;color:var(--ink-3)}
.cite-extra input[type=text]{width:100%;min-width:0}
.cite-extra label.cite-noau{flex:1 1 100%;flex-direction:row;align-items:center;gap:6px;
  font-weight:600;color:var(--ink-2)}
.cite-extra label.cite-noau input{flex:0 0 auto}
.cite-row.open{background:var(--surface-2);border-bottom-color:transparent}

/* ---- picking several references for one citation ---- */
/* .pc-row became a div (it holds a checkbox, and a control inside a button is
   invalid and unclickable in Safari), so it needs the pointer and the layout
   the button gave it. */
.pc-row{cursor:pointer}
.pc-tick{flex:0 0 auto;margin:2px 0 0}
.pc-tick-gap{flex:0 0 auto;width:13px}
.pc-row.held{background:var(--surface-sel)}
/* The tray sits under the list and never scrolls with it: search, tick, search
   again, and what you are holding is still in view. */
.pc-tray{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:10px;
  padding:8px 10px;border:1px solid var(--line);border-radius:var(--radius-sm);
  background:var(--surface-2)}
.pc-tray-n{font-size:var(--fs-micro);font-weight:700;color:var(--ink-3);white-space:nowrap}
.pc-chip{display:inline-flex;align-items:center;gap:4px;max-width:220px;
  padding:2px 4px 2px 8px;border:1px solid var(--line-strong);border-radius:999px;
  background:var(--panel);font-size:var(--fs-micro);white-space:nowrap;overflow:hidden}
.pc-chip button{border:0;background:none;cursor:pointer;color:var(--ink-3);padding:0 2px;
  font-size:11px;line-height:1}
.pc-chip button:hover{color:var(--red)}

/* A letterhead or signature image being chosen. Boxed so an empty one still
   shows where the image will go. */
.lh-prev{display:inline-flex;align-items:center;justify-content:center;min-width:120px;
  min-height:44px;padding:4px 8px;border:1px dashed var(--dash-line);border-radius:var(--radius-sm);
  background:var(--surface-2)}
.lh-prev img{max-width:220px;max-height:70px;display:block}

/* The letter preview. Tall, because the point is to see a page as a page —
   and the sheet inside brings its own white, so the frame is only a window. */
.lt-preview{display:block;width:100%;height:min(70vh,760px);border:0;
  background:var(--surface-2);border-radius:0 0 var(--radius-sm) var(--radius-sm)}

/* ---- the between-apps curtain ----
   Launching crosses an ORIGIN, and the hub is an overlay on top of a live
   Stylus document — so for the length of the mint the person had been looking
   at another app flashing underneath the tile they just pressed. This covers
   that gap, and is styled to match what the island shows while IT boots, so
   the handoff reads as one motion rather than two apps blinking. */
.hub-curtain{
  position:fixed;inset:0;z-index:9700;display:flex;align-items:center;justify-content:center;
  background:var(--bg);color:var(--ink);
  animation:hubCurtainIn .12s ease-out both;
}
@keyframes hubCurtainIn{from{opacity:0}to{opacity:1}}
.hub-curtain-box{
  display:grid;justify-items:center;gap:10px;text-align:center;padding:28px 26px;
}
.hub-curtain-box img,.hub-curtain-box svg{border-radius:12px}
.hub-curtain-name{font-size:var(--fs-lead);font-weight:660;letter-spacing:-.01em}
.hub-curtain-sub{font-size:var(--fs-cap);color:var(--ink-3)}
@media (prefers-reduced-motion:reduce){
  .hub-curtain{animation:none}
}
