/* Contract: contracts/web/rules.md
 * the app shell, the top bar, the filter row
 *
 * Part of what was style.css — 1700 lines in one file. The parts load in a fixed
 * order and MUST stay in it: the cascade is decided by source order and
 * specificity exactly as it was, because this is a split and not a rewrite.
 *
 * There are deliberately no @layer rules. Layering is the tidier shape and it
 * would have changed behaviour — a later layer beats an earlier one regardless
 * of specificity, and this stylesheet has at least one pair, `body.app > .bar`
 * written above `.bar`, where the MORE specific rule comes first and wins on
 * specificity. Putting those two in different layers silently reverses them.
 * Splitting the file is worth doing on its own; changing the cascade is a
 * separate decision that wants somebody looking at the screen.
 */
/* ---------- the app shell ----------
   The browser page is a fixed-height frame with three independently scrolling
   columns, not a long document with sticky furniture on top of it.

   It was the latter, and the seams showed: the chrome above the grid was a
   header, a project bar and a filter bar, each a different height and one of
   them able to wrap onto a second line — so every sticky offset below it was a
   guess. The columns were sized `100vh - one bar`, which is why the whole thing
   hung past the bottom of the window by the height of the other two, and
   scrolling the grid far enough dragged the filter bar off the top with it.
   The project bar has since gone into the sidebar, so there are two; the
   arrangement is what stopped it mattering how many.

   Nothing is sticky here. The frame is the window, the three columns are the
   only things that scroll, and none of them has to know how tall the others are.
   Scoped to body.app so the login and share pages, which really are documents,
   keep scrolling like documents. */
body.app {
  height: 100dvh;
  display: flex; flex-direction: column;
  overflow: hidden;
}
/* Everything above the columns keeps its natural height and never scrolls away.
   position: static undoes the sticky each of them used to need. */
body.app > .bar,
body.app > .filters { position: static; flex: none; }

/* ---------- top bar ---------- */
.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 20px;
  height: var(--bar-h); padding: 0 20px;
  background: var(--panel); border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 10px; flex: none; }
.brand h1 { font-size: 15px; font-weight: 620; margin: 0; letter-spacing: -.01em; white-space: nowrap; }
.mark {
  width: 18px; height: 18px; border-radius: 5px;
  background: linear-gradient(135deg, var(--accent), light-dark(#e0904f, #ffb38a));
}

.searchwrap { flex: 1; position: relative; display: flex; align-items: center; }
#q {
  width: 100%; padding: 10px 84px 10px 14px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid transparent; border-radius: var(--radius);
  font-size: 14px; outline: none;
}
#q:focus { border-color: var(--accent); background: var(--bg); }
.count {
  position: absolute; right: 12px;
  font-size: 12px; color: var(--ink-dim); font-variant-numeric: tabular-nums;
}

.pill {
  display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 4px;
  background: var(--warn); color: #14141a;
  border-radius: 9px; font-size: 11px; font-weight: 700; text-align: center;
}

/* ---------- filters ---------- */
.filters {
  display: flex; gap: 10px 18px; align-items: center; flex-wrap: wrap;
  padding: 12px 20px; border-bottom: 1px solid var(--line);
}
.filterrest { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-left: auto; }

/* Safari sizes a native <select> from its own font metrics and ignores vertical
   padding on it entirely, so the same rule gave a 32px control in Chrome and a
   21px one here. `appearance: none` opts out of the native box — after which
   height is honoured everywhere and the two browsers agree — at the cost of
   having to draw the chevron ourselves. The dropdown itself is still the
   platform's own.

   The chevron is an inline data: SVG rather than a background-image file
   because it has to recolour with the theme, which a linked image cannot. */
select, .selectish {
  appearance: none; -webkit-appearance: none;
  height: var(--control-h);
  padding: 0 34px 0 12px;
  background-color: var(--panel); color: var(--ink);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23888895' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 11px 8px;
  border: 1px solid var(--line); border-radius: 9px;
  font: inherit; font-size: 13.5px; line-height: 1; cursor: pointer;
}
select:hover { border-color: var(--ink-dim); }
select:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }

.check {
  display: flex; align-items: center; gap: 7px; height: var(--control-h);
  font-size: 13px; color: var(--ink-dim);
}
.check input { accent-color: var(--accent); width: 15px; height: 15px; }
.ghost {
  padding: 6px 12px; background: transparent; color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 8px; font: inherit; font-size: 13px; cursor: pointer;
}
.ghost:hover { color: var(--ink); border-color: var(--ink-dim); }

