/* Modernist — the design system this app is built on.
 *
 * Paper-white ground, near-black ink, one red accent, no rounded corners, and
 * heavy 2px rules doing the structural work that shadows and radii do
 * elsewhere. Micro-labels are uppercase monospace; everything else is Archivo.
 *
 * The tokens below are the source of truth: retune here rather than in the
 * component rules.
 *
 * Archivo — Omnibus-Type, SIL Open Font License 1.1 (fonts/Archivo-OFL.txt).
 * Bundled rather than loaded from a CDN: the archive should keep working on a
 * machine with no internet, and a font request is a request that leaks which
 * documents someone is reading. It is variable across the weight axis, so one
 * file per unicode subset covers 400/600/800 rather than three files each. */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/static/fonts/archivo-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/static/fonts/archivo-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/static/fonts/archivo-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1,
    U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329,
    U+1EA0-1EF9, U+20AB;
}

:root {
  --color-bg: #f3f2f2;
  --color-surface: #eae9e9;
  --color-paper: #fff;
  --color-text: #201e1d;
  --color-accent: #ec3013;
  --color-divider: color-mix(in srgb, #201e1d 40%, transparent);

  /* Tonal ramps — generated in OKLCH on one shared lightness scale, so the
     same step of any role matches the others in visual value. */
  --color-neutral-100: #f8f4f4;
  --color-neutral-200: #eae7e7;
  --color-neutral-300: #d7d3d3;
  --color-neutral-400: #bab6b6;
  --color-neutral-500: #9b9797;
  --color-neutral-600: #7d7979;
  --color-neutral-700: #605d5d;
  --color-neutral-800: #444141;
  --color-neutral-900: #2d2b2b;

  --color-accent-100: #fff2ef;
  --color-accent-200: #ffe0d9;
  --color-accent-300: #ffc4b8;
  --color-accent-400: #ff9783;
  --color-accent-500: #ff563c;
  --color-accent-600: #dd2b0f;
  --color-accent-700: #ae1800;
  --color-accent-800: #7c1405;
  --color-accent-900: #4d170e;

  --font-heading: "Archivo", system-ui, sans-serif;
  --font-heading-weight: 800;
  --font-body: "Archivo", system-ui, sans-serif;
  --font-mono: ui-monospace, Menlo, "SF Mono", "Liberation Mono", monospace;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;

  --radius-sm: 0px;
  --radius-md: 0px;
  --radius-lg: 0px;

  --shadow-sm: 0 1px 2px color-mix(in srgb, #2d2b2b 14%, transparent);
  --shadow-md: 0 3px 10px color-mix(in srgb, #2d2b2b 16%, transparent);
  --shadow-lg: 0 12px 32px color-mix(in srgb, #2d2b2b 22%, transparent);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Base
   ═══════════════════════════════════════════════════════════════════════ */

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

html,
body {
  height: 100%;
}

body {
  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 var(--space-2);
}
h1 { font-size: 42px; }
h2 { font-size: 32px; }
h3 { font-size: 25px; }
h4 { font-size: 20px; }
h5 { font-size: 16px; }
h6 {
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}

p { margin: 0 0 var(--space-3); }
a { color: var(--color-accent); text-underline-offset: 3px; }
a:hover { color: var(--color-accent-700); }
img { display: block; max-width: 100%; }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

mark {
  background: var(--color-accent-200);
  color: var(--color-accent-900);
  padding: 0 2px;
}

main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.text-muted { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
.quiet { color: var(--color-neutral-600); }
.hidden { display: none !important; }

/* The hidden attribute has to outrank whatever display a component sets, or
   it silently does nothing: the browser's own [hidden] rule comes from the UA
   stylesheet, and any author `display:` beats it regardless of specificity.
   That is what stopped the tag search from filtering anything. */
[hidden] { display: none !important; }

/* The uppercase monospace micro-label the whole system leans on. */
.micro {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}

.hr {
  height: 2px;
  border: 0;
  margin: var(--space-4) 0;
  background: var(--color-divider);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Buttons
   ═══════════════════════════════════════════════════════════════════════ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  /* The system's base is 14px, to pair with an .input beside it in a form.
     No button in this app sits in such a pair — they are all chrome, which
     the design draws a point smaller. */
  font-size: 13px;
  line-height: 1.2;
  color: var(--color-text);
  background: transparent;
  border: 1px solid transparent;
  padding: var(--space-2) calc(var(--space-3) * 1.2);
  border-radius: var(--radius-md);
}
.btn svg { display: block; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { background: var(--color-accent); color: var(--color-bg); }
.btn-primary:hover { background: var(--color-accent-600); color: var(--color-bg); }
.btn-primary:active { background: var(--color-accent-700); }
.btn-secondary { border-color: var(--color-divider); }
.btn-secondary:active { background: color-mix(in srgb, var(--color-text) 14%, transparent); }
.btn-ghost { color: var(--color-accent); padding-inline: var(--space-1); }
.btn-ghost:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
.btn-sm { font-size: 12px; padding: 6px 10px; }

/* ═══════════════════════════════════════════════════════════════════════════
   Forms
   ═══════════════════════════════════════════════════════════════════════ */

.field > label {
  display: block;
  font-size: 12px;
  margin-bottom: 5px;
  color: color-mix(in srgb, var(--color-text) 70%, transparent);
}
.input {
  width: 100%;
  min-height: 36px;
  padding: 6px 10px;
  font: inherit;
  font-size: 14px;
  color: var(--color-text);
  caret-color: var(--color-accent);
  background: var(--color-surface);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-md);
}
.input:hover { border-color: color-mix(in srgb, var(--color-text) 45%, transparent); }
.input:focus-visible { border-color: var(--color-accent); outline-offset: 0; }

/* ═══════════════════════════════════════════════════════════════════════════
   Site chrome
   ═══════════════════════════════════════════════════════════════════════ */

.topbar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: 14px var(--space-6);
  border-bottom: 2px solid var(--color-divider);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 16px;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--color-text);
  text-decoration: none;
}
.brand::before {
  content: "";
  width: 14px;
  height: 14px;
  background: var(--color-accent);
}
.brand:hover { color: var(--color-text); }

/* The search field is the one place a 2px ink border is used for emphasis
   rather than for structure — it is the primary action on the page, and per
   the mock it takes every pixel between the brand and the buttons, at any
   width. (It was briefly capped at 700px; the design moved on.) */
.searchbox {
  flex: 1;
  display: flex;
  min-width: 0;
  border: 2px solid var(--color-text);
  background: var(--color-paper);
}
.searchbox .glyph {
  display: flex;
  align-items: center;
  padding: 0 12px;
  color: var(--color-neutral-600);
}
.searchbox input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 12px 4px;
  font: 16px var(--font-body);
  color: var(--color-text);
  outline: none;
}
.searchbox input::-webkit-search-cancel-button { display: none; }
.searchbox .clear {
  display: flex;
  align-items: center;
  padding: 0 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--color-neutral-600);
  border-left: 1px solid var(--color-divider);
  text-decoration: none;
}
.searchbox .clear:hover { color: var(--color-accent-700); }
/* Enter submits; the button is for pointer users and for the no-JS path, so
   it stays but keeps out of the way. */
.searchbox button {
  flex: none;
  border: 0;
  border-left: 1px solid var(--color-divider);
  background: transparent;
  padding: 0 14px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-700);
}
.searchbox button:hover { color: var(--color-accent-700); }

.topbar nav {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
}

/* Icon-square button in the topbar, sized to the mock: 38px, 34 on mobile.
   Serves both links and buttons, so the button's own chrome is zeroed. */
.iconbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  flex: none;
  padding: 0;
  border: 1px solid var(--color-divider);
  background: transparent;
  color: var(--color-neutral-700);
  text-decoration: none;
  cursor: pointer;
}

/* The identity: name visible, email as its tooltip. */
.who {
  font: 11px ui-monospace, Menlo, monospace;
  letter-spacing: 0.04em;
  color: var(--color-neutral-700);
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* No login configured. Dashed on purpose — provisional, not decoration. */
.access-chip {
  font: 10px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 7px 8px;
  border: 1px dashed var(--color-neutral-400);
  color: var(--color-neutral-700);
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Index — filters
   ═══════════════════════════════════════════════════════════════════════ */

.filters {
  display: flex;
  align-items: flex-start;
  gap: var(--space-6);
  padding: var(--space-4) var(--space-6);
  border-bottom: 2px solid var(--color-divider);
}

.filter-tags {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.filter-tags > .micro { margin-right: 4px; }

/* TAGS, DATE and SORT head their groups: a point smaller than the general
   micro-label and tracked wider, so they read as labels rather than as one
   more control in the row. */
.filter-tags > .micro,
.filter-date-row > .micro,
.results-head .sort > .micro {
  font-size: 10px;
  letter-spacing: 0.1em;
}

/* The pills are replaced as a group when the results change, so they need an
   element around them — and display:contents leaves them flex items of the row
   they were laid out in before that element existed, wrapping with the label
   and against the same edge. */
.tag-pills { display: contents; }

/* One pill shape, three states: idle, selected, and the dashed affordances
   that are actions rather than filters. */
.pill-tag {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 7px 9px;
  cursor: pointer;
  text-decoration: none;
  border: 1px solid var(--color-divider);
  color: var(--color-neutral-800);
  background: transparent;
}
.pill-tag.on {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-bg);
}
.pill-tag .n { margin-left: 6px; color: var(--color-neutral-600); }
.pill-tag.on .n { color: color-mix(in srgb, var(--color-bg) 75%, transparent); }
.pill-dashed {
  border: 1px dashed var(--color-accent);
  color: var(--color-accent-700);
}
.pill-plain {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  padding: 7px 4px;
  text-decoration: none;
}
/* The reserved three wear the tag pill because they are tags — they filter the
   same way, so they should look the way filtering looks. The flag is in the
   markup and the border is a shade firmer, which is the whole of what says the
   archive allocated this one rather than a person. The selected state is left
   to .pill-tag.on, which outranks this by a class. */
.pill-reserved { border-color: var(--color-neutral-400); }

/* Tag browser. The checkbox is the toggle, so the full vocabulary is
   reachable with JavaScript off; the search box inside is the enhancement. */
.browse-toggle { position: absolute; opacity: 0; pointer-events: none; }
.browse-more { cursor: pointer; }
.tag-browse-panel { display: none; }
.browse-toggle:checked ~ .tag-browse-panel {
  display: block;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 20;
  width: min(560px, 100%);
  border: 2px solid var(--color-text);
  background: var(--color-paper);
  box-shadow: var(--shadow-lg);
}
.tag-browse-panel input {
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--color-divider);
  padding: 10px;
  font: 13px var(--font-body);
  color: var(--color-text);
  outline: none;
}
.tag-browse-list {
  max-height: 220px;
  overflow: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
.tag-browse-list a {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 8px 10px;
  font-size: 13px;
  text-decoration: none;
  color: var(--color-text);
}
.tag-browse-list a:hover { background: var(--color-neutral-100); }
.tag-browse-list a.on { color: var(--color-accent-700); }
.tag-browse-list .n { font-family: var(--font-mono); font-size: 10px; color: var(--color-neutral-600); }
.tag-browse-foot {
  padding: 8px 10px;
  border-top: 1px solid var(--color-divider);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}

/* The collapsed filter control and its sheet. On a wide screen none of this
   shows and the checkbox has no effect; the bar below renders as normal. */
.sheet-toggle { position: absolute; opacity: 0; pointer-events: none; }
.filter-summary,
.sheet-scrim,
.sheet-head { display: none; }

.filter-date {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}
.filter-date-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.filter-date-row > .micro { margin-right: 2px; }

/* Segmented control: one hairline box, dividers between, ink fill for the
   selection. Ink is the resting selection — a sort order, all time — because
   those say how you are looking rather than narrowing what you see.
   A segment that is genuinely excluding documents takes the accent instead,
   so an applied date range reads as the filter it is, next to the tag pills
   that are already accent-filled. */
.seg { display: flex; border: 1px solid var(--color-divider); }
.seg a {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 7px 10px;
  text-decoration: none;
  color: var(--color-neutral-800);
  background: transparent;
}
.seg a + a { border-left: 1px solid var(--color-divider); }
.seg a.on { background: var(--color-text); color: var(--color-bg); }
/* Only the segments that hold documents back. "All time" is selected but
   excludes nothing, so it stays ink. */
.seg a.on.filtering { background: var(--color-accent); color: var(--color-bg); }
.sort-dir .dir-arrow { display: none; }

.range-custom {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
}
.range-custom .input {
  width: auto;
  min-height: 30px;
  font-size: 12px;
  padding: 4px 6px;
}
.range-custom .sep {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-neutral-600);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Index — results
   ═══════════════════════════════════════════════════════════════════════ */

.results-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 14px var(--space-6);
  border-bottom: 2px solid var(--color-divider);
}
.results-head .count {
  margin: 0;
  font-size: 14px;
  color: var(--color-neutral-700);
}
.results-head .count strong {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  color: var(--color-text);
}
/* Two controls: the field, and which end to start from. They share the
   segmented-control shape but sit in separate boxes, because they answer
   separate questions. */
.results-head .sort {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.results-head .sort > .micro { margin-right: 2px; }

/* — selection — */

/* The design's own square, drawn rather than the browser's. 18px with a 2px
   edge, filling with the accent when ticked, like every other control. */
.pick {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  flex: none;
  margin: 0;
  padding: 0;
  border: 2px solid var(--color-neutral-400);
  background: transparent;
  cursor: pointer;
  display: grid;
  place-items: center;
  /* Above the row's stretched link, or ticking a box would open the
     document instead. */
  position: relative;
  z-index: 2;
}
.pick:checked,
.pick:indeterminate {
  border-color: var(--color-accent);
  background: var(--color-accent);
}
.pick:checked::after,
.pick:indeterminate::after {
  content: "✓";
  font: 700 12px/1 var(--font-body);
  color: var(--color-bg);
}
.pick:indeterminate::after { content: "–"; }

/* An 18px square is a small thing to aim at, and every pixel around it belongs
   to the row's stretched link — so a near miss opened the document instead of
   ticking the box. The label is the real target: padded out to 44px square and
   pulled back by the same amount, so it occupies exactly the space the box
   did while catching everything within 13px of it. */
.pick-hit {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  padding: 13px;
  margin: -13px;
  cursor: pointer;
  /* Above the stretched link, or the label's own clicks would fall through. */
  position: relative;
  z-index: 2;
}
.row > .pick-hit { margin-top: -11px; }

.picked {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.picker-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
/* The short spellings exist for phones; here the full ones speak. */
.bulk-short { display: none; }
/* Invisible, not absent: removing it would shove the results down and back
   every time the first box is ticked.
   Asked of the checkboxes themselves rather than of a count JavaScript writes
   onto the form. The attribute version could only match once picker.js had
   run, so every page load painted the buttons for a frame and then took them
   away — and with scripting off they never went away at all. The select-all
   box is excluded because on its own, unscripted, it selects no documents. */
.picker:not(:has(.pick:not(.pick-all):checked)) .picker-actions { visibility: hidden; }
.picked-count {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  white-space: nowrap;
}
/* The two secondary actions are buttons for the form's sake but read as the
   plain text links they sit beside. */
button.pill-plain {
  border: 0;
  background: none;
  cursor: pointer;
  white-space: nowrap;
}

/* Adding or removing a tag across the selection. The popover is a <details>,
   so it opens and closes with no script and with the keyboard; picker.js only
   adds the courtesies a native popover would come with, such as closing when
   the reader clicks somewhere else. */
.bulk-tag { position: relative; }
/* The marker would sit inside the button and break its shape, and there is no
   one property that removes it in every browser. */
.bulk-tag > summary {
  list-style: none;
  cursor: pointer;
}
.bulk-tag > summary::-webkit-details-marker { display: none; }
.bulk-pop {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  /* Above the rows and their stretched links, below the filter popover. */
  z-index: 25;
  width: 280px;
  display: flex;
  gap: var(--space-2);
  padding: 10px;
  border: 2px solid var(--color-text);
  background: var(--color-bg);
  box-shadow: var(--shadow-lg);
}
.bulk-pop input {
  flex: 1;
  min-width: 0;
  padding: 7px 8px;
  border: 1px solid var(--color-neutral-400);
  background: var(--color-paper);
  font: 400 13px/1.2 var(--font-body);
  color: var(--color-text);
}
.bulk-pop input:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* Escalating a selection from this page to everything the filter matches.
   Only once the whole page is ticked is "and the rest" a question worth
   asking; and once the answer is yes it stays on screen to say so. Asked of
   the checkbox itself rather than of anything JavaScript writes, so the strip
   is correct on the first paint and with scripting off. */
.picker:not(:has(.pick-scope:checked)):has(.pick:not(.pick-all):not(:checked)) .scope-bar { display: none; }
.picker:has(.pick-scope:checked) .scope-page { display: none; }
.picker:not(:has(.pick-scope:checked)) .scope-all { display: none; }

.scope-bar {
  padding: 10px var(--space-6);
  border-bottom: 2px solid var(--color-accent);
  background: var(--color-accent-100);
  font-size: 13px;
}
/* Escalated: the strip inverts, because "all four thousand of them" is a state
   worth noticing from across the room. */
.picker:has(.pick-scope:checked) .scope-bar {
  background: var(--color-accent);
  color: var(--color-bg);
}
/* The label is the control — the whole strip is the target, not the words in
   it — and it holds the checkbox, which needs a positioned ancestor to be
   taken out of the flow against. */
.scope-label {
  display: block;
  position: relative;
  cursor: pointer;
}
/* Hidden without display:none, deliberately: a display:none checkbox is
   unreachable by keyboard, and — the part that matters — a hidden checkbox
   still posts its value, which is the entire mechanism. scope=filtered rides
   along with whichever action button is pressed. */
.scope-label .pick-scope {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  pointer-events: none;
}
/* The offer, and the way back from it. Not an <a> — there is nowhere to go —
   so it is dressed as the link it behaves like. */
.scope-bar em {
  font-style: normal;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}
/* The box still takes focus — that is why it is hidden this way rather than
   with display:none — but there is nothing of it to see, so the strip standing
   in for it wears the ring. */
.scope-label:has(.pick-scope:focus-visible) {
  outline: 2px solid var(--color-text);
  outline-offset: 2px;
}

/* Two columns where there is room for two, and one where there is not. No
   media query on purpose: auto-fit with a minimum track means the column count
   follows the container, not the viewport, so this stays right inside whatever
   the results are placed in rather than only at the widths someone thought to
   name. */
.rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* Two columns at most, and no breakpoint to say so. A track is never
     narrower than half the row, so a third can never fit however wide the
     window gets — on a 2560px desktop auto-fit alone was laying out four, and
     a row of four is a spreadsheet, not a list of documents. The 620px floor
     still decides when the second column is affordable, so the count follows
     the container rather than the viewport. */
  grid-template-columns: repeat(auto-fit, minmax(max(620px, 50%), 1fr));
}

.row {
  position: relative;
  display: flex;
  gap: 20px;
  padding: 22px var(--space-6);
  border-bottom: 1px solid var(--color-divider);
  border-right: 1px solid var(--color-divider);
}
.row:hover { background: var(--color-neutral-100); }

.row .thumb {
  width: 112px;
  height: 148px;
  flex: none;
  border: 2px solid var(--color-text);
  background: repeating-linear-gradient(
    135deg,
    var(--color-neutral-200) 0 6px,
    var(--color-neutral-100) 6px 12px
  );
  overflow: hidden;
}
.row .thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

.row-body { flex: 1; min-width: 0; }
.row-top {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}

/* The document number, in the same treatment everywhere it appears — this is
   the number you write on the paper original. */
.code {
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.08em;
  padding: 5px 7px;
  border: 1px solid var(--color-neutral-400);
  color: var(--color-neutral-700);
  white-space: nowrap;
  background: transparent;
}

.row-meta {
  display: flex;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}
.row-meta .status { color: var(--color-accent-700); }
/* A failure wears the accent as a fill rather than as text: the design draws
   it as a label on the row, not as one more word in the meta line, because it
   is the reason that row looks the way it does. Only failed — a document that
   is merely processing is not an alarm. */
.row-meta .status.failed {
  padding: 3px 6px;
  background: var(--color-accent);
  color: var(--color-bg);
}
/* In the trash is a state the document is in, not an alarm about it: outlined
   and grey, where a failure is the one thing on the row that wears the accent.
   Boxed rather than bare text so it reads as a label on a document rather than
   as one more fact in the meta line beside it. */
.row-meta .status.trashed {
  padding: 3px 6px;
  border: 1px solid var(--color-neutral-400);
  color: var(--color-neutral-600);
}

.row-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}
.row-head h3 { font-size: 22px; margin: 0 0 var(--space-2); min-width: 0; }
.row-head h3 a { color: var(--color-text); text-decoration: none; }
/* Stretching the title link over the whole row makes the box clickable
   without nesting anchors, which is invalid HTML. Everything that needs its
   own click — tags, Open — is raised above it. */
.row-head h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}
.row:hover .row-head h3 a { color: var(--color-accent-700); }

.open-link {
  position: relative;
  z-index: 1;
  flex: none;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 7px 9px;
  border: 1px solid var(--color-divider);
  color: var(--color-neutral-700);
  text-decoration: none;
}

/* A failed row carries the reason where a summary or a snippet would have
   gone — it has neither — so it reads in the same voice, in the accent the
   FAILED badge above it already uses. */
/* No measure of its own. 72ch was one, from when a row was the full width of
   the page and a line of text would otherwise have run the whole way across
   it; in a two-column grid the column is already the measure, and the cap only
   held the text to little more than half the card it sits in. */
.row .snippet,
.row .summary,
.row .fail-reason {
  margin: 0 0 var(--space-3);
  color: var(--color-neutral-800);
  text-wrap: pretty;
}
/* A point smaller than the summary it stands in for, and in the accent: it is
   an explanation of the badge above it rather than a description of the
   document, and should not read as the thing the row is about. */
.row .fail-reason {
  color: var(--color-accent-700);
  font-size: 13px;
}

.row-tags {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.chip {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 8px;
  border: 1px solid var(--color-divider);
  color: var(--color-neutral-800);
  text-decoration: none;
}
.chip.on {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-bg);
}

.empty {
  padding: 64px var(--space-6);
  text-align: center;
  color: var(--color-neutral-700);
}
.empty h4 { color: var(--color-text); }

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
  padding: var(--space-6);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}
.pager a { text-decoration: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   Document page
   ═══════════════════════════════════════════════════════════════════════ */

.doc {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.doc-head {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 14px var(--space-6);
  border-bottom: 2px solid var(--color-divider);
}
.doc-head .code { cursor: pointer; }
.doc-head-title { flex: 1; min-width: 220px; }
.doc-head-actions { display: flex; gap: var(--space-2); flex: none; }

/* Through the listing, one document at a time. */
.doc-nav { display: flex; align-items: center; gap: 6px; flex: none; }
.doc-nav .arrow { padding: 7px 11px; font-size: 13px; }
.doc-nav .arrow[aria-disabled] { opacity: 0.35; pointer-events: none; }
.doc-pos {
  font: 10px ui-monospace, Menlo, monospace;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
  white-space: nowrap;
}

/* Open/Download are words on a desktop and 44px icon squares on a phone. */
.doc-head-actions .act-icon { display: none; }

/* Editable in place: the heading is the field. The border only appears on
   hover, so the page does not look like a form until you aim at it. */
.doc-title {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 16px;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  cursor: text;
  padding: 4px 6px;
  margin: -4px -6px;
  border: 1px solid transparent;
}
.doc-title:hover {
  border-color: var(--color-divider);
  background: var(--color-neutral-100);
}

.inline-edit {
  width: 100%;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 16px;
  padding: 4px 6px;
  margin: -4px 0;
  border: 2px solid var(--color-accent);
  background: var(--color-paper);
  color: var(--color-text);
  outline: none;
}
.doc-date-wrap .inline-edit { font-size: 20px; }

.doc-body {
  display: flex;
  flex: 1;
  min-height: 0;
  align-items: stretch;
}

.doc-preview {
  flex: 1;
  min-width: 0;
  background: var(--color-neutral-200);
}
.doc-preview iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.doc-side {
  width: 340px;
  flex: none;
  border-left: 2px solid var(--color-divider);
  padding: var(--space-6);
  overflow: auto;
}
.doc-side h6 { margin: 0 0 var(--space-3); }
.doc-side form { margin: 0; }

/* — the three document actions — */
.tools {
  display: flex;
  gap: var(--space-2);
  margin-bottom: 20px;
}
/* Sits in the row with the tools rather than over the page, because it is a
   remark about the thing just edited and not news. Accent-filled and gone in
   under two seconds: long enough to be caught out of the corner of an eye,
   short enough that it never has to be dismissed. */
.saved {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0 10px;
  font: 10px/1 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: var(--color-accent);
  color: var(--color-bg);
}
.tool {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-divider);
  background: transparent;
  cursor: pointer;
  color: var(--color-neutral-800);
  padding: 0;
}
.tool[disabled] { opacity: 0.45; cursor: not-allowed; }
.tool svg { display: block; }

.confirm {
  margin-bottom: 20px;
  border: 2px solid var(--color-accent);
  background: var(--color-accent-100);
  padding: 14px;
}
.confirm h5 { margin: 0 0 var(--space-1); font-size: 14px; }
.confirm p {
  margin: 0 0 var(--space-3);
  font-size: 13px;
  color: var(--color-neutral-800);
}
.confirm-actions { display: flex; gap: var(--space-2); }

/* — date — */
.doc-date {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 22px;
  line-height: 1.2;
  cursor: pointer;
  display: inline-block;
  border-bottom: 2px dashed var(--color-neutral-400);
}
.doc-date:hover {
  border-bottom-color: var(--color-accent);
  color: var(--color-accent-700);
}
.doc-date.unset { color: var(--color-neutral-500); }

/* — tags — */
.pills { display: flex; flex-wrap: wrap; gap: 6px; }
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 7px 7px 7px 9px;
  border: 1px solid var(--color-divider);
}
/* A tag pill is only clickable at its ×, so the × carries the weight the
   pill itself does not: bigger and bolder than the label beside it, and in
   the pill's own colour at reduced opacity rather than a fixed grey that
   would disappear once the pill fills on hover. */
.pill-x {
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  color: currentColor;
  opacity: 0.55;
}
.pill-x:hover { opacity: 1; }
.tag-add {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 7px 9px;
  border: 1px dashed var(--color-accent);
  background: transparent;
  color: var(--color-accent-700);
  cursor: pointer;
}

.tag-input-row {
  position: relative;
  margin-top: 10px;
  border: 2px solid var(--color-text);
  background: var(--color-paper);
}
.tag-input {
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--color-divider);
  padding: 10px;
  font: 13px var(--font-body);
  color: var(--color-text);
  outline: none;
  background: transparent;
}
.tag-suggest {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 220px;
  overflow: auto;
}
.tag-suggest li { padding: 9px 10px; font-size: 13px; cursor: pointer; }
.tag-suggest li:hover,
.tag-suggest li.on { background: var(--color-neutral-100); }

/* The plain fields the form keeps for the no-JavaScript path. */
.plain-field {
  display: block;
  margin-bottom: var(--space-3);
  font-size: 12px;
  color: var(--color-neutral-700);
}
.plain-field input {
  display: block;
  width: 100%;
  margin-top: 4px;
  min-height: 36px;
  padding: 6px 10px;
  font: inherit;
  font-size: 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-divider);
  color: var(--color-text);
}

.doc-summary {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--color-neutral-800);
  text-wrap: pretty;
}
.doc-summary.none { color: var(--color-neutral-500); }

/* — processing timeline — */
@keyframes docPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
  display: flex;
  gap: var(--space-3);
  padding-bottom: 14px;
}
.timeline .dot {
  width: 9px;
  height: 9px;
  flex: none;
  margin-top: 5px;
  background: var(--color-neutral-400);
}
.timeline .step { flex: 1; min-width: 0; }
.timeline .what { font-size: 13px; line-height: 1.35; display: block; }
/* Extra lines a step can carry: what it spent, and the name the document
   arrived under. The filename is boxed rather than run into the line, because
   scanner filenames are long and unpunctuated and would read as prose. */
.timeline .cost,
.timeline .file {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.4;
  color: var(--color-neutral-700);
  margin-top: 3px;
}
.timeline .cost { letter-spacing: 0.04em; }
.timeline .file {
  padding: 4px 6px;
  border: 1px solid var(--color-divider);
  background: var(--color-neutral-100);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.timeline .detail {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--color-neutral-600);
  margin-top: 2px;
  overflow-wrap: anywhere;
  /* Two lines and no more: a long original filename or a long error message
     would otherwise push the rest of the timeline off the page. The full
     string stays reachable in the tooltip. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.timeline .done .dot { background: var(--color-accent); }
.timeline .pending .dot,
.timeline .working .dot {
  background: var(--color-accent);
  animation: docPulse 1s ease-in-out infinite;
}
.timeline .pending .what,
.timeline .working .what {
  color: var(--color-accent-700);
  font-weight: 600;
}
.timeline .failed .dot { background: var(--color-accent-800); }
.timeline .failed .what { color: var(--color-accent-800); }
.timeline .skipped .dot { background: var(--color-neutral-300); }
.timeline .skipped .what { color: var(--color-neutral-600); }

.doc-foot {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: 12px;
  color: var(--color-neutral-600);
}

.banner {
  border: 2px solid var(--color-accent);
  background: var(--color-accent-100);
  padding: 12px 14px;
  margin-bottom: var(--space-4);
  font-size: 13px;
}
.banner.info {
  border-color: var(--color-divider);
  background: var(--color-surface);
}

/* A failure is the one thing on this page asking for something to be done, so
   it gets a box at the head of the timeline rather than a line among the
   banners — and, when the thing it wants is a password, the field to type it
   into. Unfilled, unlike a banner: the border carries it, and a tinted panel
   with a form in it reads as a dialog that has lost its way. */
.fail-box {
  border: 2px solid var(--color-accent);
  padding: 14px;
  margin-bottom: 20px;
}
.fail-box h5 { font-size: 14px; }
.fail-box p {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--color-neutral-800);
  /* A wrapped tool error carries an absolute path, which has nowhere to break. */
  overflow-wrap: anywhere;
}

.unlock { margin-top: var(--space-3); }
.unlock-bad {
  margin-top: 6px;
  font-size: 12px;
  color: var(--color-accent-700);
}
.unlock-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.extracted { margin-top: var(--space-4); }
.extracted summary {
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}
.extracted summary:hover { color: var(--color-accent-700); }
.extracted pre {
  margin: var(--space-3) 0 0;
  max-height: 320px;
  overflow: auto;
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-divider);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.extracted[data-empty="1"] summary { color: var(--color-neutral-500); }

/* ═══════════════════════════════════════════════════════════════════════════
   Tables and stats — status page
   ═══════════════════════════════════════════════════════════════════════ */

.page {
  padding: var(--space-6);
  max-width: 1100px;
  width: 100%;
}
.page > section { margin-bottom: var(--space-8); }

.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
  padding: var(--space-2);
  border-bottom: 2px solid var(--color-divider);
  font-weight: 400;
}
.table td {
  padding: var(--space-2);
  border-bottom: 1px solid var(--color-divider);
}
.table tbody tr:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }

.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  background: var(--color-divider);
  border: 1px solid var(--color-divider);
}
.stat {
  flex: 1 1 140px;
  background: var(--color-bg);
  padding: var(--space-3) var(--space-4);
}
.stat .k {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-neutral-600);
}
.stat .v {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 22px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Upload
   ═══════════════════════════════════════════════════════════════════════ */

.uploader {
  border: 2px dashed var(--color-divider);
  padding: var(--space-8);
  text-align: center;
}
.uploader input[type="file"] { margin: var(--space-4) 0; }

.flash {
  border: 2px solid var(--color-divider);
  background: var(--color-surface);
  padding: 10px 14px;
  margin-bottom: var(--space-2);
  font-size: 14px;
}
.flash.bad {
  border-color: var(--color-accent);
  background: var(--color-accent-100);
}
/* On the index the flash is a direct child of <main>, which has no padding of
   its own — the rows and the header bring their own gutter — so it asks for the
   same one rather than sitting flush against the edge. */
.results-notice { margin: var(--space-4) var(--space-6) 0; }

/* ═══════════════════════════════════════════════════════════════════════════
   Drag-and-drop overlay and toasts
   ═══════════════════════════════════════════════════════════════════════ */

.drop-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-8);
  background: rgba(243, 242, 242, 0.94);
}
.drop-overlay.on { display: flex; }
.drop-overlay > div {
  width: 100%;
  height: 100%;
  border: 2px dashed var(--color-accent);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  text-align: center;
  padding: var(--space-6);
}
/* The two buttons only belong to the overlay you opened on purpose. A drag is
   already carrying the files, so during one this row is not there at all. */
.drop-actions { display: none; gap: 10px; margin-top: var(--space-2); }
.drop-overlay.picking .drop-actions { display: flex; }

.drop-overlay .big {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 24px;
}

.toasts {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: min(420px, calc(100vw - 32px));
}
.toast {
  border: 2px solid var(--color-text);
  background: var(--color-paper);
  box-shadow: var(--shadow-md);
  padding: 10px 14px;
  font-size: 13px;
}
.toast.bad {
  border-color: var(--color-accent);
  background: var(--color-accent-100);
}
.toast a { margin-left: 6px; }

/* ═══════════════════════════════════════════════════════════════════════════
   Narrow screens
   ═══════════════════════════════════════════════════════════════════════ */

@media (max-width: 1080px) {
  .doc-side { width: 300px; }
}

@media (max-width: 860px) {
  .topbar {
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
  }
  .searchbox { order: 3; flex-basis: 100%; }
  /* The nav takes the rest of the brand's row so the name can stretch and
     truncate inside it; flex-end keeps the buttons on the right edge when
     nobody is signed in and there is no name to do the stretching. */
  .topbar nav { flex: 1; min-width: 0; justify-content: flex-end; }

  /* One line in place of the whole bar: a row of tag pills beside a
     five-segment date control does not fit, and wrapping them both just
     pushes the results off the screen. */
  .filter-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin: var(--space-3) var(--space-4);
    padding: 10px 12px;
    border: 1px solid var(--color-divider);
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }
  .filter-summary .caret { color: var(--color-accent-700); }

  /* The anchor the panel hangs from; on a wide screen this is an inert
     wrapper and the bar inside it lays out as normal. */
  .filterbar { position: relative; }
  .filters { display: none; }

  .sheet-toggle:checked ~ .sheet-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 39;
    background: rgba(32, 30, 29, 0.45);
  }
  /* Hangs off the control that opened it, which is what the caret promises,
     rather than rising from an edge of the screen the eye has to travel to. */
  .sheet-toggle:checked ~ .filters {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    position: absolute;
    top: 100%;
    left: var(--space-4);
    right: var(--space-4);
    z-index: 40;
    max-height: 70vh;
    overflow: auto;
    padding: 0 var(--space-4) var(--space-4);
    background: var(--color-bg);
    border: 2px solid var(--color-text);
    box-shadow: var(--shadow-lg);
  }
  .sheet-toggle:checked ~ .filters .sheet-head {
    display: flex;
    /* Ahead of the date section, which orders itself above the tags. */
    order: -2;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    /* Sticky so Done stays reachable however long the tag list runs. */
    position: sticky;
    top: 0;
    z-index: 1;
    margin: 0 calc(var(--space-4) * -1);
    /* The panel's own border already separates it from the page. */
    padding: 14px var(--space-4);
    background: var(--color-bg);
    border-bottom: 2px solid var(--color-divider);
  }
  .sheet-title {
    font-family: var(--font-heading);
    font-weight: var(--font-heading-weight);
    font-size: 15px;
  }
  .sheet-done {
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-accent-700);
  }

  /* Date leads in the sheet, as the design has it. */
  .filter-date { align-items: flex-start; width: 100%; order: -1; }
  /* Each label heads its own section rather than sitting inline with the
     controls, which is what gives the two groups room to read as separate
     things. */
  .filter-tags > .micro,
  .filter-date-row > .micro {
    flex-basis: 100%;
    margin: 0 0 2px;
  }
  .filter-date-row { flex-wrap: wrap; }
  .seg { flex-wrap: wrap; }
  .range-custom { flex-wrap: wrap; }

  /* The sheet shows the whole vocabulary rather than six of it behind a
     "more" control: there is room here, and scanning a list beats guessing
     which six a popover chose. The pills and that control both go — but not
     the reserved three, which the vocabulary below deliberately does not
     list, and which hiding here would put out of reach entirely. */
  .tag-pills > .pill-tag:not(.browse-more),
  .browse-more { display: none; }

  /* No popover to position against inside a scrolling sheet, so the panel
     simply joins the flow — and the checkbox stops mattering. */
  .browse-toggle ~ .tag-browse-panel,
  .browse-toggle:checked ~ .tag-browse-panel {
    display: block;
    position: static;
    width: 100%;
    box-shadow: none;
    border: 0;
    margin-top: var(--space-2);
  }
  .tag-filter {
    border: 2px solid var(--color-text) !important;
    padding: 11px;
    font-size: 14px;
  }
  .tag-browse-list {
    grid-template-columns: 1fr;
    max-height: none;
    overflow: visible;
    margin-top: var(--space-2);
  }
  .tag-browse-list a { padding: 10px; font-size: 14px; }
  .tag-browse-foot { border-top: 1px solid var(--color-divider); }

  .results-head {
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
  }
  /* Per the mock: count on the left, sort on the right, and the bulk actions
     on a whole line under both instead of squeezing beside the count.
     display:contents lifts the group's children into the results-head row,
     so the actions' 100% is the whole bar rather than the sliver the sort
     control leaves over. Display none rather than the desktop's visibility
     hidden: an invisible row that still reserved its line would put a
     permanent blank stripe under every phone's result count. */
  .picked { display: contents; }
  .picked .count { margin-right: auto; }
  .picker-actions { order: 5; flex-basis: 100%; flex-wrap: wrap; row-gap: 6px; }
  .picker:not(:has(.pick:not(.pick-all):checked)) .picker-actions { display: none; }
  .bulk-long { display: none; }
  .bulk-short { display: inline; }
  .results-head .sort { flex-wrap: wrap; gap: 6px; }
  .results-head .sort > .micro { display: none; }
  .sort-dir .dir-full { display: none; }
  .sort-dir .dir-arrow { display: inline; }
  .results-head,
  .scope-bar,
  .row { padding-inline: var(--space-4); }
  /* One column, said outright. auto-fit only drops to one track when the
     container can hold one — below the 620px minimum the track keeps its size
     and the rows hang off the side of a phone instead. The divider between
     columns goes with the columns. */
  .rows { grid-template-columns: 1fr; }
  .row { gap: 14px; padding-block: var(--space-4); border-right: 0; }
  .row .thumb { width: 76px; height: 100px; }
  .row-head h3 { font-size: 16px; line-height: 1.25; }
  .row .snippet,
  .row .summary { font-size: 13px; line-height: 1.45; }

  /* The two panes stack rather than shrink: a 300px-wide PDF is unreadable,
     and the metadata is what you came to edit on a phone. */
  .doc-body { flex-direction: column; }
  .doc-preview { flex: none; height: 60vh; }
  .doc-side {
    width: 100%;
    border-left: 0;
    border-top: 2px solid var(--color-divider);
    overflow: visible;
  }
  .doc-head {
    flex-wrap: wrap;
    gap: 10px;
    padding: var(--space-3) var(--space-4);
  }
  /* The mock's mobile order: back button, code chip centred, position and
     arrows at the right; the title on its own line; Open and Download as a
     right-aligned row of icon squares below it. */
  .doc-head .code { order: 1; margin: 0 auto; }
  .doc-nav { order: 2; margin-left: auto; }
  .doc-nav .arrow { padding: 8px 11px; font-size: 12px; }
  .doc-nav .doc-pos { order: -1; }
  .doc-head-title { flex-basis: 100%; order: 3; }
  .doc-head-actions { order: 4; margin-left: auto; }
  .doc-head-actions .act-label { display: none; }
  .doc-head-actions .act-icon { display: block; }
  .doc-head-actions .act { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; padding: 0; }
  .iconbtn { width: 34px; height: 34px; }
  .iconbtn svg { width: 16px; height: 16px; }
  /* Per the mock: the name rides between the brand and the buttons,
     stretched and ellipsized rather than hidden. order pulls it ahead of
     Upload — in the DOM it sits next to Sign out, which it belongs to. */
  .who {
    order: -1;
    flex: 1;
    min-width: 0;
    max-width: none;
    font-size: 10px;
    text-align: left;
  }
  .tool { width: 44px; height: 44px; }
  .pill-x { font-size: 17px; }
  .page { padding: var(--space-4); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Hover
   ═══════════════════════════════════════════════════════════════════════ */

/* Everything that responds to a click fills with the accent. One treatment
   across pills, chips, segments, icon buttons and secondary buttons, so
   "this does something" is a single learnable signal rather than a different
   guess per component. Declared last so it beats each component's resting
   state without needing !important. */
.btn-secondary:hover,
.pill-tag:hover,
.pill-dashed:hover,
.seg a:hover,
.chip:hover,
.open-link:hover,
.code:hover,
.tool:hover,
.tag-add:hover,
.pill:hover,
.filter-summary:hover {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-bg);
}
/* The count inside a pill and the caret on the collapsed filter control both
   ride the fill rather than keeping a grey of their own. */
.pill-tag:hover .n,
.filter-summary:hover .caret { color: color-mix(in srgb, var(--color-bg) 75%, transparent); }
