/* The bar wraps onto as many lines as the screen needs: on a phone the links,
   the upload form and the account sit on their own rows rather than pushing
   the page wider than the screen. */
nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;

  .nav-left,
  .nav-right {
    flex: 1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
  }

  .nav-right {
    justify-content: flex-end;
  }

  .user-info {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
  }
}

.nav-notifications {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.notification-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-color: red;
  color: white;
  border-radius: 50%;
  font-size: 0.75rem;
  font-weight: bold;
  width: 1.25rem;
  height: 1.25rem;
}

.notification-unread {
  font-weight: bold;
}

.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 1rem;
  box-sizing: border-box;
}

.auth-container {
  width: 100%;
  max-width: 20rem;
  text-align: center;
}

.auth-title {
  margin: 0 0 1.5rem 0;
  font-size: 2rem;
  font-weight: normal;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  text-align: left;
}

.auth-form input[type="email"],
.auth-form input[type="password"] {
  width: 100%;
  padding: 0.5rem;
  box-sizing: border-box;
}

.auth-form input[type="submit"] {
  padding: 0.5rem 1rem;
  cursor: pointer;
}

.auth-links {
  margin-top: 1rem;
}

turbo-frame {
  display: block;
}

table {
  border-collapse: collapse;
  width: 100%;
}

th, td {
  text-align: left;
  padding: 0.5rem;
  border-bottom: 1px solid #ccc;
}

th {
  font-weight: bold;
}

/* A table keeps the width its columns need and scrolls inside this wrapper, so
   a five-column table on a phone never widens the page around it. */
.table-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}

/* Scrolling in one axis clips the other, which would cut off a header menu
   that opens past the last row. A table short enough for that reserves the room
   the open menu needs — its sort options, and the moving and hiding of its
   column; a taller one has the rows to draw it over. */
.table-scroll:has(details.table-menu[open]) {
  padding-bottom: 11rem;
}

/* Cells of a definition-backed table hold one declared value each and read
   better whole, so they keep to one line and the wrapper does the scrolling.
   A column carrying prose says `wrap: true` and wraps. */
table.table-nowrap th,
table.table-nowrap td {
  white-space: nowrap;
}

table.table-nowrap th.cell-wrap,
table.table-nowrap td.cell-wrap {
  white-space: normal;
}

/* The row "j" and "k" walked to. Focus is on the row itself, so the mark is
   the row's own rather than a link's: an outline that stays inside the row so
   it does not paint over the one below, and a ground behind it for the readers
   whose browser draws no outline on a collapsed table row. Only the rows the
   controller walks have a tabindex, so only they are marked. */
tbody tr[tabindex]:focus {
  outline: 2px solid currentcolor;
  outline-offset: -2px;
  background-color: #f0f0f0;
}

/* The bar above a table, one row that wraps on a phone: the search box, then
   the Views menu, the Filter… button and the Columns menu as a line of links,
   the export link at the far end, and the chips on a row of their own
   beneath. The views menu writes with forms of its own, so it stands beside
   the toolbar's form rather than inside it; `display: contents` on the form
   lets the controls inside it take their places on the same row. */
.table-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  margin-bottom: 0.75rem;
}

.table-toolbar-form {
  display: contents;
}

/* The search box leads the row — the one thing on it that is typed into — and
   takes the width the row can spare, up to a comfortable measure. It is set
   in the page's own font rather than the browser's control font, so the row
   reads as one line of text. */
.table-toolbar input[type="search"] {
  order: -1;
  flex: 1 1 12rem;
  max-width: 24rem;
  box-sizing: border-box;
  min-height: 2.5rem;
  padding: 0 0.75rem;
  font: inherit;
  color: inherit;
  background-color: white;
  border: 1px solid #bbb;
  border-radius: 0.25rem;
}

/* Everything else on the row is a link, or reads as one: the Filter… button,
   the summaries that open the Views and Columns menus, the export. The
   page's link colour and underline, no box of their own — and 2.5rem tall so
   each stays a fingertip's target. */
.table-toolbar .table-filter,
.table-toolbar .table-export,
.table-toolbar .table-columns > summary,
.table-toolbar .table-views > summary {
  display: inline-flex;
  align-items: center;
  min-height: 2.5rem;
  margin: 0;
  padding: 0;
  font: inherit;
  color: LinkText;
  background: none;
  border: 0;
  text-decoration: underline;
  cursor: pointer;
}

/* The export stands apart at the far end of the row: it takes away what is
   on the screen rather than changing it. */
.table-toolbar .table-export {
  margin-left: auto;
}

.table-chips {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border: 1px solid #ccc;
  border-radius: 1rem;
}

/* The label part of a chip opens the picker on that filter, so it is a button
   that has to read as the chip's text. */
.chip-edit {
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Taking a filter off is the one thing on a chip done with a fingertip, so the
   × is a 44px target at the default font size wherever the chip is drawn. */
.chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  text-decoration: none;
  font-weight: bold;
}

.chip-edit:focus-visible,
.chip-remove:focus-visible,
.chip-clear:focus-visible {
  outline: 2px solid currentcolor;
  outline-offset: 2px;
}

/* The picker takes the width it can get up to a comfortable reading measure,
   so it is the same dialog on a phone as on a desktop. Stacked, it keeps its
   title and its buttons in view and gives the rest of the height to the column
   or the values being picked, so Apply is never below the fold. */
dialog.table-filters {
  width: calc(100vw - 2rem);
  max-width: 32rem;
  max-height: calc(100dvh - 2rem);
  box-sizing: border-box;
  padding: 1rem;
  border: 1px solid #ccc;
  color: inherit;
  background-color: white;
}

/* Only while it is open: a closed dialog is `display: none`, and a display of
   its own here would show it. */
dialog.table-filters[open] {
  display: flex;
  flex-direction: column;
}

dialog.table-filters::backdrop {
  background-color: rgb(0 0 0 / 40%);
}

dialog.table-filters h2 {
  margin-top: 0;
  font-size: 1rem;
}

dialog.table-filters input[type="text"] {
  width: 100%;
  padding: 0.25rem 0.5rem;
  box-sizing: border-box;
}

/* Step one: the field, and the rows it narrows. It takes what height is left
   and gives it to the list, which scrolls under the field rather than pushing
   Apply off the bottom of the screen. `:not([hidden])` because a `display` of
   its own would otherwise show the step the controller hid when it stepped
   into one column's controls. */
.table-filters-step:not([hidden]) {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.table-filters-options {
  margin: 0;
  padding: 0;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
}

/* A row of the typeahead. `:not([hidden])` for the same reason as above: every
   row the typed term does not stand for is hidden. */
.table-filters-options li:not([hidden]) {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.5rem;
  min-height: 2.75rem;
  box-sizing: border-box;
  /* A row is not a button, so the pointer is what says it can be clicked — and
     what makes iOS Safari deliver a click to a plain element at all. */
  cursor: pointer;
}

/* The row Enter would take. It is marked rather than focused, so the cursor
   stays in the field while the arrows walk the list. */
.table-filters-options li[aria-selected="true"] {
  background-color: #eee;
}

/* What the picker says when the term stands for nothing at all. */
.table-filters-empty {
  padding: 0.375rem 0.5rem;
  color: #555;
}

/* A suggestion says the column it filters before the value it sets. The
   separator is drawn here rather than written into the row, so what the row
   says stays the words the typed term is matched against. */
.filter-option-column {
  color: #555;
}

.filter-option-value::before {
  content: "›";
  margin-right: 0.5rem;
  color: #999;
}

/* The values being picked take what height is left and scroll, rather than
   pushing the buttons under them off the screen. The scroller has to be this
   wrapper rather than the fieldset itself: a fieldset keeps its content at its
   own height however the dialog sizes it, so `overflow` on the fieldset leaves
   a long list painting over the buttons instead of scrolling. */
.table-filters-values {
  min-height: 0;
  overflow-y: auto;
}

dialog.table-filters fieldset {
  margin: 0.5rem 0;
  border: 1px solid #ccc;
}

/* `:not([hidden])` because a display of its own would otherwise show the
   labels the field over a long list of values hid. */
dialog.table-filters label:not([hidden]) {
  display: block;
}

/* A long list of values scrolls inside the dialog rather than pushing Apply
   off the bottom of the screen. */
.filter-group {
  margin-bottom: 0.5rem;
  max-height: 50vh;
  overflow-y: auto;
}

/* Everything the picker is driven by with a finger: 2.75rem is the 44px touch
   target at the default font size. */
dialog.table-filters button,
dialog.table-filters input[type="text"],
dialog.table-filters select {
  min-height: 2.75rem;
}

/* A select is as wide as its longest option, which for the date periods is
   wider than the dialog on a phone. */
dialog.table-filters select {
  max-width: 100%;
}

dialog.table-filters fieldset label {
  padding: 0.375rem 0;
}

/* The header menus and the toolbar's columns menu are the same control: a
   summary that opens a list of links over the table rather than pushing it
   down. */
details.table-menu,
details.table-columns,
details.table-views {
  display: inline-block;
  position: relative;

  summary {
    cursor: pointer;
    list-style: none;
  }

  summary::-webkit-details-marker {
    display: none;
  }

  ul {
    position: absolute;
    z-index: 1;
    margin: 0.25rem 0 0 0;
    padding: 0.25rem 0.75rem;
    list-style: none;
    white-space: nowrap;
    font-weight: normal;
    background-color: white;
    border: 1px solid #ccc;
  }
}

/* The Views and Columns menus open onto something, and their summaries say
   so with a marker. It is an inline block so the underline the summary wears
   in the bar stops short of it. */
.table-columns > summary::after,
.table-views > summary::after {
  content: "\25BE";
  display: inline-block;
  padding-left: 0.25rem;
  text-decoration: none;
}

/* One entry a line, with the markers down the left, so the entry that is not a
   link — the last column standing — is drawn where its link would be. The
   marker itself is a span inside the entry and keeps to the line. */
.table-columns li > a,
.table-columns li > span {
  display: block;
  padding: 0.25rem 0;
}

/* A view is a line: its name, then the two things done to it. The name takes
   the room it needs and the buttons keep their 44px targets beside it. */
.table-views li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
}

.table-views li > a {
  flex: 1 1 auto;
}

/* The view the table is drawn from right now. */
.table-views li > a[aria-current] {
  font-weight: bold;
}

.table-views button {
  min-width: 2.75rem;
  min-height: 2.75rem;
}

/* Naming a view is the last line of the menu, and wraps rather than widening
   it on a phone. */
.table-views-save form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.table-views-save input[type="text"] {
  flex: 1 1 8rem;
  min-width: 8rem;
  padding: 0.25rem 0.5rem;
}

th[aria-sort="ascending"] summary::after {
  content: " \25B2";
}

th[aria-sort="descending"] summary::after {
  content: " \25BC";
}

.status-processing {
  color: gray;
}

.status-extracting_metadata {
  color: orange;
}

.status-creating_document {
  color: blue;
}

.status-completed {
  color: green;
}

.status-duplicate {
  color: purple;
}

/* A tag reads as a chip wherever it appears — a document's details, the tags
   page, the checkbox list on the document form. Same shape as the filter
   chips above, but a tag carries a colour of its own, so the border and text
   are keyed to it the way `.status-<value>` keys a status. */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem 0.5rem;
  border: 1px solid #ccc;
  border-radius: 1rem;
  white-space: nowrap;
}

.tag-grey { border-color: #999; color: #555; }
.tag-red { border-color: #d98d8d; color: #a12b2b; }
.tag-orange { border-color: #dda76b; color: #9a5b12; }
.tag-yellow { border-color: #cfc060; color: #7a6a05; }
.tag-green { border-color: #8fbf8f; color: #2c7a2c; }
.tag-blue { border-color: #8fb0d9; color: #1f5799; }
.tag-purple { border-color: #b09ad4; color: #6a3fa0; }

/* A document's tags on its details list, side by side rather than stacked. */
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.tag-list a {
  text-decoration: none;
}

/* The checkbox list on the document form: the tag itself is the label, so the
   box sits inside the chip rather than beside it. */
.tag-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.tag-choices label {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  cursor: pointer;
}

/* The folder boxes on the document form: one per line, since a folder's name
   is a phrase rather than a word. */
.folder-choices label {
  display: block;
  cursor: pointer;
}

/* A select that can be typed into (SearchableSelectComponent): the field, and
   the menu that opens under it. The wrapper is inline so the `<br>` after it
   in a form field's markup wraps to the hint rather than leaving a blank line,
   and holds the width a name needs on a desktop while giving way on a phone. */
.searchable-select {
  position: relative;
  display: inline-block;
  width: 100%;
  max-width: 24rem;
  vertical-align: top;
}

.searchable-select input[type="text"] {
  width: 100%;
  box-sizing: border-box;
}

/* The menu is drawn over whatever follows the field rather than pushing it
   down, as wide as the field, and scrolls once the rows outgrow it. No display
   of its own: positioning makes the span a block, and a display here would
   show the menu the `hidden` attribute hides. */
.searchable-select-menu {
  position: absolute;
  z-index: 1;
  top: 100%;
  left: 0;
  right: 0;
  max-height: min(40vh, 16rem);
  overflow-y: auto;
  box-sizing: border-box;
  background-color: white;
  border: 1px solid #ccc;
}

.searchable-select-options {
  display: block;
}

/* A row of the list. `:not([hidden])` because a display of its own would
   otherwise show every row the typed term does not stand for. */
.searchable-select-options [role="option"]:not([hidden]) {
  display: flex;
  align-items: center;
  padding: 0.375rem 0.5rem;
  min-height: 2.75rem;
  box-sizing: border-box;
  /* A row is not a button, so the pointer is what says it can be clicked — and
     what makes iOS Safari deliver a click to a plain element at all. */
  cursor: pointer;
}

/* The row Enter would take. Marked rather than focused, so the cursor stays in
   the field while the arrows walk the list. */
.searchable-select-options [role="option"][aria-selected="true"] {
  background-color: #eee;
}

/* What the menu says when the term stands for no row at all. */
.searchable-select-empty:not([hidden]) {
  display: block;
  padding: 0.375rem 0.5rem;
  color: #555;
}

/* A record's page — a document's or an upload's: the details in a column and
   the file beside them, large enough to read. The two split the width down the
   middle until the screen is too narrow for both — a phone, a portrait tablet
   — and then the file goes under the details, which are the shorter of the two
   and are read first. */
.record-layout {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1rem 2rem;
}

.record-details {
  flex: 1 1 24rem;
  min-width: 0;
}

/* An upload's OCR text and metadata are <pre> blocks whose long lines used to
   widen the page; beside the file they would run under it instead, so they
   wrap within their column. */
.record-details pre {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The file stays in view while a long column beside it — the edit form has a
   dozen fields — scrolls past. */
.file-viewer {
  position: sticky;
  top: 1rem;
  flex: 1 1 24rem;
  min-width: 0;
  margin: 0;
}

/* The browser's PDF viewer has no size of its own, so it is given the height
   left under the heading, and never less than a page's worth. */
.file-viewer-frame {
  display: block;
  width: 100%;
  height: calc(100vh - 11rem);
  min-height: 24rem;
}

.file-viewer img {
  max-width: 100%;
  height: auto;
}

.file-viewer figcaption {
  margin-top: 0.5rem;
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: #1a1a1a;
    color: #e0e0e0;
  }

  a {
    color: #66b3ff;
  }

  a:visited {
    color: #b399ff;
  }

  th, td {
    border-bottom-color: #444;
  }

  .tag-grey { border-color: #666; color: #aaa; }
  .tag-red { border-color: #8a4444; color: #e89494; }
  .tag-orange { border-color: #8a6534; color: #e0a869; }
  .tag-yellow { border-color: #7d7333; color: #d8ca6a; }
  .tag-green { border-color: #4a7a4a; color: #8fd18f; }
  .tag-blue { border-color: #40628f; color: #8fbaea; }
  .tag-purple { border-color: #6a5490; color: #bda6e6; }

  tbody tr[tabindex]:focus {
    background-color: #2a2a2a;
  }

  details.table-menu ul,
  details.table-columns ul,
  details.table-views ul {
    background-color: #1a1a1a;
    border-color: #444;
  }

  .chip {
    border-color: #444;
  }

  /* The toolbar and the picker it carries are drawn dark, so the controls the
     browser draws itself inside them — a checkbox, a date field's calendar
     button, the scrollbar down a long list of values — are drawn dark too
     rather than as dark glyphs on a dark ground. */
  .table-toolbar {
    color-scheme: dark;
  }

  dialog.table-filters {
    background-color: #1a1a1a;
    border-color: #444;
  }

  dialog.table-filters fieldset {
    border-color: #444;
  }

  .table-filters-options li[aria-selected="true"] {
    background-color: #333;
  }

  .table-filters-empty,
  .filter-option-column {
    color: #aaa;
  }

  .filter-option-value::before {
    color: #777;
  }

  /* The buttons inside the views menu and the picker are drawn dark, like
     the bar they belong to. */
  .table-views button,
  dialog.table-filters button {
    background-color: #333;
    color: #e0e0e0;
    border: 1px solid #555;
  }

  .table-toolbar .table-filter,
  .table-toolbar .table-export,
  .table-toolbar .table-columns > summary,
  .table-toolbar .table-views > summary {
    color: #66b3ff;
  }

  .table-toolbar input[type="search"] {
    background-color: #222;
    color: #e0e0e0;
    border-color: #555;
  }

  input[type="date"],
  input[type="email"],
  input[type="number"],
  input[type="password"],
  input[type="search"],
  input[type="text"] {
    background-color: #2a2a2a;
    color: #e0e0e0;
    border: 1px solid #444;
  }

  input[type="submit"] {
    background-color: #333;
    color: #e0e0e0;
    border: 1px solid #555;
  }

  .status-processing {
    color: #999;
  }

  .status-extracting_metadata {
    color: #ffa500;
  }

  .status-creating_document {
    color: #6699ff;
  }

  .status-completed {
    color: #66cc66;
  }

  .status-duplicate {
    color: #cc99ff;
  }

  .notification-badge {
    background-color: #cc0000;
  }

  .searchable-select-menu {
    background-color: #1a1a1a;
    border-color: #444;
  }

  .searchable-select-options [role="option"][aria-selected="true"] {
    background-color: #333;
  }

  .searchable-select-empty {
    color: #aaa;
  }
}
