/* Birdseye base styles: design tokens, the page ground, and the hover and
   focus states that inline JSX cannot express.

   ONE copy, linked by every entry page. dashboard.html and planner.html each
   carried a byte-identical 2129-byte copy of this block, which is two files to
   keep in step and no mechanism for keeping them there. Linked rather than
   imported through JS so the tokens and the body background apply on the first
   paint instead of after the bundle runs. */

/* Geist, self-hosted, so neither app depends on a third party at runtime.
   Free under the SIL Open Font License; files copied from the `geist` npm
   package into public/fonts. Three sans weights and two mono weights, which is
   every weight the type system uses. Weight 700 is deliberately absent: the
   system tops out at 600, and a face that is not loaded cannot be used by
   accident. Source: Wiki/Systems/Geist Handoff for Claude Code.md section 1. */
@font-face { font-family: "Geist"; src: url("/fonts/Geist-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist"; src: url("/fonts/Geist-Medium.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist"; src: url("/fonts/Geist-SemiBold.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist Mono"; src: url("/fonts/GeistMono-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist Mono"; src: url("/fonts/GeistMono-Medium.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }

:root {
  color-scheme: light;
  /* The type system's two families. theme.ts carries the same two stacks for
     Mantine; these variables are for the plain CSS in this file and for any
     markup outside React. */
  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "Cascadia Mono", monospace;

  /* ============================================================
     THE COLOR BLOCK. Every color this stylesheet and the two plain HTML pages
     draw, declared once. Josh's handoff `Birdseye - Claude Design -
     Hard-coded colors to tokens - 2026-11-02 - 2350`, item 1: the same tokens
     as `COLOR` in web/src/app/theme.ts, under the same names, so changing the
     palette means editing those two blocks and nothing else.

     A VARIABLE WHOSE TOKEN IS A STEP ON THE GRAPHITE SCALE CARRIES THAT
     STEP'S VALUE, written out rather than read from Mantine, because
     auth.html and auth-callback.html link this file and never load Mantine.

     THE LINES WERE FOUR DIFFERENT ALPHAS OF COOL INK, `rgba(15, 23, 42, ...)`,
     so each one took a blue cast from whatever sat behind it, and a media
     query bumped two of them below 992px because the old cool page swallowed
     anything lighter. Flat warm colors need no per-width correction, so that
     media query is gone with them.

     Nothing outside this block may carry a color. `scripts/test-no-stray-colors.mjs`
     fails the build when one does.
     ============================================================ */
  --bb-ground: #f5f5f7;
  --bb-surface: #ffffff;
  --bb-surface-fade: rgba(255, 255, 255, 0);
  --bb-ground-fade: rgba(245, 245, 247, 0);
  --bb-line: #e3e8ee;
  --bb-line-hover: #c5cfdb;
  --bb-card-line: #eef1f5;
  --bb-card-line-hover: #c5cfdb;
  --bb-edge: #c5cfdb;
  --bb-edge-strong: #7689a3;
  --bb-ink: #1b2638;
  --bb-ink-soft: #445877;
  --bb-muted: #5b6f8c;
  --bb-stripe: #f5f6f8;
  --bb-row-stripe: rgba(27, 38, 56, 0.02);
  --bb-row-stripe-opaque: #f9fafb;
  --bb-tag-ground: #e3e8ee;
  --bb-icon-button-hover: #e3e8ee;
  /* Channels, so a rule can set its own alpha: rgba(var(--bb-shadow-ink), .06) */
  --bb-shadow-ink: 27, 38, 56;
  --bb-sheen: rgba(255, 255, 255, 0.6);
  --bb-on-color: rgba(255, 255, 255, 0.8);
  --bb-button: #334560;
  --bb-button-hover: #26344a;
  --bb-amber: #c89656;
  --bb-amber-ink: #7a5d2e;
  --bb-coral-7: #b53d1b;
  --bb-focus-ring: #7d93b8;
  /* GOOGLE'S OWN, on the Google sign-in button, which is the one control in
     Birdseye deliberately drawn in somebody else's palette. The four in the G
     itself are in web/src/data/trello-colors.ts with Trello's. */
  --bb-google-border: #dadce0;
  --bb-google-surface: #ffffff;
  --bb-google-ink: #3c4043;
  --bb-google-hover: #f8faff;
  --bb-google-hover-border: #d2e3fc;
}
html, body, #root { height: 100%; }
/* THE GROUND WINS OVER MANTINE'S OWN BODY COLOR. Mantine paints the body from
   `--mantine-color-body`, which follows the theme's `white`, now the warm
   surface `#fffdf9`. The page's ground is the darker `#f3f1ec`, so the rule
   below is written with `html body` to outrank Mantine's single-element rule
   whichever order the two stylesheets land in. Measured on staging
   2026-11-02: the body came back 255,253,249 with the plain `body` rule in
   place. */
html body { background: var(--bb-ground); }
body {
  margin: 0;
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  /* Match graphite[0] in theme.ts, the ground of Josh's warm palette of
     2026-11-02. The ink is graphite[9]. */
  background: var(--bb-ground);
  color: var(--bb-ink);
}
/* Rail toggle hover state per prototype .bb-rail-toggle:hover —
   inline JSX styles can't express :hover, and the project doesn't
   use CSS modules, so the rule lives here. */
.bb-rail-toggle:hover {
  background: var(--bb-surface);
  color: var(--mantine-color-graphite-8);
  border-color: var(--bb-line-hover);
}
/* THE ACTIVE WORD IN A SEGMENTED CONTROL IS THE ACCENT. Brief / Matrix /
   Timeline on the Planner bar, and the rail's Status and Due date controls.
   Option A, Josh 2026-10-02: the accent marks where you are. Same pill, same
   white chip, same shadow, same size; only the word's color moves.

   HERE, not in theme.ts, and this is the third time the same mistake has been
   made in that file. Mantine's `styles` API writes PLAIN INLINE STYLES, so a
   key carrying a selector, `'&[data-active]'` or `'&:hover'` or `'& > div'`,
   is dropped without a word. Measured on staging 2026-10-08 and again on
   2026-10-09: the label's own `style` attribute carried the nine flat
   declarations and nothing else, stylesheet rules naming a color for an
   active segmented label came to 0, and Brief, Matrix and Timeline all read
   rgb(91, 111, 140) before and after a real click.

   The RESTING color has to come from this rule too, exactly as the Matrix
   card's resting border does below: an inline color outranks any stylesheet,
   so a label whose resting color is inline can never go accent. Both rules
   carry a second compound, `[data-active]` and `:not([data-active])`, so they
   outrank Mantine's own single-class label rule whichever order the sheets
   land in.

   accent-6 is ink `#141414` as of Josh's palette handoff of 2026-11-02, which
   scores 18.4:1 on the `#fffdf9` chip behind the active word. It was the
   indigo `#5b6db5` at 4.88:1 until then. The resting word stays graphite-5,
   now `#5f5a52`, so position is still the difference between muted and ink
   rather than between two colors. */
.mantine-SegmentedControl-label:not([data-active]) {
  color: var(--mantine-color-graphite-5);
}
.mantine-SegmentedControl-label[data-active] {
  color: var(--mantine-color-accent-6);
}
/* The Matrix card's frame, here for the same reason the rail toggle above is:
   a hover cannot be written inline. The RESTING border has to come from this
   rule too, because an inline border outranks any stylesheet and a card whose
   resting border is inline can never lift. 1px on all four sides, which
   replaces the 2px graphite left border every Matrix card used to carry and
   that read as an accent nobody asked for.

   A milestone card keeps Trello's purple on its own left edge: that one border
   is still set inline in PlannerMatrix.tsx, so it outranks both of these rules
   on the left side and survives the hover. */
.bb-matrix-card {
  border: 1px solid var(--bb-card-line);
}
.bb-matrix-card:hover {
  border-color: var(--bb-card-line-hover);
}
/* A DASHBOARD CARD ROW, and the reason every value is here rather than in the
   component is the one the Matrix card above records: an inline ground or
   border outranks every stylesheet, so a row whose resting white comes from a
   `bg` prop can never dip. Both values moved together in the same edit.

   What this replaces: a `'&:hover'` key inside `Card.styles.root` in
   CardListItem.tsx, which never reached a browser on any shipped build,
   because Mantine's `styles` prop emits flat inline styles and cannot carry a
   selector. Measured with a real pointer on 2026-10-10: a row read
   rgb(255, 255, 255) at rest and rgb(255, 255, 255) under the pointer, on all
   114 clickable rows. docs/BUGS.md, 2026-10-10, item 2.

   The doubled class in each selector outranks Mantine's own single-class
   Card and Paper rules whichever order the sheets land in, exactly as the
   segmented control's two rules do above.

   The component sets `data-hoverable` only on a row that is neither archived
   nor inert, so the dip is the row's way of saying "this is a target" and a row
   that takes no click stays flat. An archived row keeps the page gray it rests
   on and does not move. The 120ms transition stays on the component, beside the
   opacity and the shadow. */
.bb-card-row.bb-card-row {
  /* The warm surface of Josh's palette handoff of 2026-11-02 item 1, where
     this rule carried pure white. A card is a surface. */
  background-color: var(--bb-surface);
  border-color: var(--bb-card-line);
}
.bb-card-row.bb-card-row[data-archived='true'] {
  background-color: var(--mantine-color-graphite-0);
}
.bb-card-row.bb-card-row[data-hoverable='true']:hover {
  background-color: var(--mantine-color-graphite-0);
  border-color: var(--bb-card-line-hover);
}
/* A Matrix cell's scroll area. 2px all round so the first and last card's
   border and shadow are not clipped by the viewport's own edge.

   The [data-scrollbars] in both selectors is there to outrank Mantine's own
   offset rules, which are a single class deep and would otherwise zero the
   side padding in a cell with nothing to scroll. */
.bb-matrix-cell-scroll .mantine-ScrollArea-viewport[data-scrollbars] {
  padding: 2px;
}
/* A CELL NEVER SCROLLS SIDEWAYS. Josh, 2026-09-30 and again 2026-10-03:
   "there should not be horizontal scrolling in a list."

   ScrollArea.Autosize is two boxes, not one: an outer box carrying this class
   with `overflow: auto` of its own, and inside it a flex item holding the
   ScrollArea. `scrollbars="y"` governs MANTINE's scrollbars on the ScrollArea,
   and the outer box's native overflow is not one of them, so a cell whose
   content would not fit grew a native horizontal scrollbar that Mantine never
   knew about and that the app-wide 8px scrollbar rule below painted gray.

   The flex item takes Mantine's default `min-width: auto`, which floors it at
   the cards' min-content width. A card's min-content comes from its board-name
   line, which is `white-space: nowrap` so it can ellipsize, and
   "BS - BBP Master Project List - REQ" measures 192px against a 204px cell.
   Measured on staging 2026-10-03, BS - Master Project List: 17 of 38 cells
   overflowed, the worst by 65px, and a real browser painted a bar on all 17.

   `min-width: 0` lets the flex item shrink back to the cell, and the lines that
   are too long ellipsize, which is what they are built to do. Nothing is
   clipped without saying so: of the 245 elements inside cards whose text
   overruns its box after this rule, every one carries text-overflow: ellipsis
   and none is silently cut. */
.bb-matrix-cell-scroll > * {
  min-width: 0;
}
/* THE ACTION MATRIX SCROLLS SIDEWAYS ON ITS OWN VIEWPORT, not on the box
   outside it. ScrollArea.Autosize renders outer(flex, overflow auto) >
   inner(flex: 1) > root > viewport, and the inner flex item keeps the default
   `min-width: auto`, so a 4,399px grid stops it shrinking and the outer box
   ends up doing the horizontal scrolling. The sticky first column pins against
   the VIEWPORT, so it had nothing to hold on to. One rule, on our own class, so
   it reaches only this grid. */
.bb-matrix-grid-scroll > div {
  min-width: 0;
}
/* 8px of clear space between the cards and the scrollbar, and ONLY in a cell
   that genuinely scrolls: Mantine marks a viewport with nothing to scroll
   [data-vertical-hidden], so a cell holding one card keeps its full width.
   16px is the 8px bar plus the 8px gap, because the bar overlays the
   viewport's right edge rather than sitting beside it. */
.bb-matrix-cell-scroll .mantine-ScrollArea-viewport[data-scrollbars]:not([data-vertical-hidden]) {
  padding-inline-end: 16px;
}
/* ONE focus ring for the whole app, the type system's own value from
   `Wiki\Systems\Birdseye and Prism Type System.md` section 3: a 2px white halo
   so the ring reads against a dark control, then #7d93b8 outside it. A ring
   rather than an outline because it follows a rounded or rotated control's own
   box, which an outline on a transformed element does not.

   Scoped to the things a keyboard actually lands on. Text inputs are left to
   Mantine's own focus border, which is part of the input's chrome rather than a
   ring around it. The rail toggle used to carry its own 2px outline here; the
   whole point of one rule is that a control cannot gain a second focus style, so
   the toggle now takes this one. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bb-surface), 0 0 0 4px var(--bb-focus-ring);
}
/* iOS Safari / Chrome auto-zoom on any input whose computed
   font-size is under 16px when focused. The rail's search inputs
   are styled at 12.5px to match the prototype, which triggers
   the zoom and forces the user to pinch back. Override on phone
   only — desktop stays at the prototype sizes. Same rule covers
   textareas and select elements so future inputs do not regress.
   Matches the same <md (992px) breakpoint Birdseye already uses
   for mobile UX. */
@media (max-width: 991.98px) {
  input, textarea, select {
    font-size: 16px !important;
  }
}

/* Thin styled scrollbars, app wide. Copied from Prism's rule
   (service/prism/web/static/index.html) so the two apps carry one
   scrollbar rather than two, which is what Josh chose on 2026-09-30
   when asked whether the standard is Birdseye's 6px or Prism's 8px:
   "8px". Consistency handoff section 7b.

   The thumb only gains contrast on hover, so a resting column reads
   as content rather than as chrome. The 2px transparent border plus
   background-clip is what makes an 8px track carry a 4px thumb. */
* { scrollbar-width: thin; scrollbar-color: var(--mantine-color-graphite-2) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--mantine-color-graphite-2);
  border-radius: 999px;
  border: 2px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--mantine-color-graphite-4);
  background-clip: content-box;
}
*::-webkit-scrollbar-corner { background: transparent; }

/* THE ALWAYS-VISIBLE SCROLLBAR CARRIES A PALE TRACK, which is what makes a
   Mantine ScrollArea look like Claude Design's preview rather than merely
   carrying the same thumb. Josh, 2026-10-05: "the scrollbars do not look like
   what Claude Design had in its preview."

   Read off the preview itself, `Birdseye Review Pass.dc.html` lines 22 and 23
   in the 2026-10-02 handoff folder, rather than from anybody's memory of it:

     [data-always-scroll] { scrollbar-color: #c5cfdb #eef1f5; }
     [data-always-scroll]::-webkit-scrollbar-track { background: #eef1f5;
                                                    border-radius: 999px; }

   The preview marks six areas that way and every one of them is a Mantine
   ScrollArea in Birdseye: the filter rail, the Matrix grid, a Matrix cell, the
   Unplaced tray and the two long lists. So the rule belongs on the ScrollArea's
   own scrollbar element and nowhere else.

   The page's ordinary scrollbars keep the transparent track above, which is
   also what the preview does: its `*` rule leaves the track transparent and
   only [data-always-scroll] paints one. A resting bar on a casual scroller
   reads as chrome; a bar on an area built to scroll reads as a control.

   THE TRACK IS graphite-1 AND THE THUMB graphite-2, as of Josh's instruction
   of 2026-11-02, where both were hard-coded cool values the warm palette could
   not reach: `#eef1f5` for the track and `#c5cfdb` for the thumb. Named
   through the scale rather than as hexes, so the next palette change carries
   them. The thumb's hover stays graphite-4. */
.mantine-ScrollArea-scrollbar {
  background: var(--mantine-color-graphite-1) !important;
  border-radius: 999px;
}
.mantine-ScrollArea-scrollbar:hover {
  background: var(--mantine-color-graphite-1) !important;
}

/* THE MANTINE THUMB DARKENS UNDER THE POINTER, which is what the comment above
   has claimed since 2026-10-05 and what the native bars at the top of this
   section have always done. The Mantine thumb is a div rather than a painted
   scrollbar part, so `*::-webkit-scrollbar-thumb:hover` cannot reach it, and
   its hover sat in `theme.ts` as a `'&:hover'` key inside Mantine's `styles`
   prop, which emits flat inline styles and drops any key carrying a selector.
   So no Mantine ScrollArea in the app had ever responded to the pointer:
   measured on the deployed staging build, 14 thumbs, 1 on the dashboard and 13
   on the Matrix of BS - Master Project List, every one of them
   `rgb(197, 207, 219)` at rest and `rgb(197, 207, 219)` under a real
   `page.mouse.move` onto the thumb. After this rule: the same 14 rest at
   `rgb(197, 207, 219)` and the hovered one reads graphite-4
   `rgb(118, 137, 163)`. Driven by
   scripts/drive-recipes/scrollarea-thumb-hover.mjs.

   BOTH COLORS HAD TO MOVE, not just the hover, exactly as the SegmentedControl
   label's did in `684d735`: a resting color written through `styles` lands in
   the thumb's own `style` attribute and an inline color outranks every
   stylesheet, so the hover rule could never have won while the resting color
   stayed in `theme.ts`. The resting value is unchanged, graphite-2, so no
   scrollable surface looks different at rest.

   The class is doubled so the resting pair outranks Mantine's own resting rule,
   `:where([data-mantine-color-scheme=light]) .m_d8b5e363`, whichever order the
   sheets land in: a `:where()` counts for nothing, so theirs is one class
   against two.

   THE HOVER HANGS OFF THE SCROLLBAR, NOT THE THUMB, and that is copied from
   Mantine rather than chosen: their rule is
   `.m_c44ba933:hover > .m_d8b5e363`, so the pointer anywhere on the track
   darkens the thumb, which is the behavior a person gets everywhere else. It
   also settles a tie. A first attempt wrote the hover on the thumb alone,
   which scored the same three classes as Mantine's rule, lost on source order
   because Mantine's sheet lands after this one, and measured
   `rgba(0, 0, 0, 0.5)` under the pointer instead of graphite-4. Four classes
   wins outright. `:active` is in for the same reason: Mantine paints the same
   color while the thumb is being dragged. */
.mantine-ScrollArea-thumb.mantine-ScrollArea-thumb {
  background: var(--mantine-color-graphite-2);
  border-radius: 999px;
}
.mantine-ScrollArea-scrollbar:hover .mantine-ScrollArea-thumb.mantine-ScrollArea-thumb,
.mantine-ScrollArea-scrollbar:active .mantine-ScrollArea-thumb.mantine-ScrollArea-thumb {
  background: var(--mantine-color-graphite-4);
}

/* THE MARKDOWN INSIDE THE CARD DRAWER, the rules that cannot be written inline.
   `.bb-md` wraps a rendered description and a rendered comment body; `.bb-desc`
   is on the description alone. Until 2026-10-08 the class carried no CSS at
   all, so a list's spacing was the browser's and a bold label sat directly on
   the value under it.

   Josh's handoff of 2026-10-08, item 2: "4px between list items, including
   nested items. Nested lists keep their indent and their hollow bullet" and
   "2px from a bold label ('Title:', 'Need By Date:') to its value on the next
   line." Neither is reachable from a React style object: one needs a sibling
   combinator and one needs to see what follows the label. Measured on staging
   before the change, on Jagricole Sell Sheet: list items sat 0px apart.

   The indent and the hollow bullet are left alone deliberately. The `ul` and
   `ol` overrides in CardPreviewSidebar.tsx set the 16px padding, and a nested
   list's hollow bullet is the browser's own second-level marker. */
.bb-md ul,
.bb-md ol {
  margin: 0;
}
.bb-md li + li {
  margin-top: 4px;
}
.bb-md li > ul,
.bb-md li > ol {
  margin-top: 4px;
}

/* NUMBERED LISTS IN A DESCRIPTION READ AS TRELLO DRAWS THEM: 1, 2 at the first
   level, a, b at the second, i, ii at the third. Josh's handoff of 2026-10-28
   00:45, item 3: "Numbering in nested ordered lists: match Trello."

   Here rather than in CardPreviewSidebar.tsx because a style object cannot say
   "this list is inside two others", and ::marker has no inline form at all.
   The 24px step per level is the `ol` override in that file.

   The numerals sit in graphite.4, so the words carry the reading weight and
   the numbering stays navigation. A browser right-aligns an outside marker
   against the content edge by default, which is what lines the WORDS up down
   the list whether an item is numbered 9 or 10. */
.bb-desc ol {
  list-style-type: decimal;
}
.bb-desc ol ol {
  list-style-type: lower-alpha;
}
.bb-desc ol ol ol {
  list-style-type: lower-roman;
}
.bb-desc ol > li::marker {
  color: var(--mantine-color-graphite-4);
}

/* A block nested inside another block keeps the 8px rhythm it had. The two
   wrappers zero `--bb-md-block` and space their own top-level blocks with a
   flex gap instead, and that zero would otherwise inherit into a blockquote,
   a list item or a table cell and close every gap inside it. */
.bb-md blockquote,
.bb-md li,
.bb-md td,
.bb-md th {
  --bb-md-block: 8px;
  --bb-md-block-top: 8px;
}

/* THE BOLD LABEL AND ITS VALUE. Trello authors write `**Need By Date:**` and
   press Enter, which `hardBreaks` turns into a <br>, so the label and the value
   are two line boxes inside ONE paragraph and nothing sits between them to
   carry a gap. Measured on staging 2026-10-08, the real DOM:

     <p><strong>Title:</strong><br>Create Worthy Park Jagricole Embeddable</p>

   `:has(+ br)` matches a bold run that IS the whole first line, which is
   exactly the label shape, and leaves `**bold** then more words on the same
   line` untouched. The <br> is then hidden, because a line break after a block
   would open an empty line under the label. */
.bb-desc p > strong:first-child:has(+ br) {
  display: block;
  margin-bottom: 2px;
}
.bb-desc p > strong:first-child:has(+ br) + br {
  display: none;
}

/* THE ATTACHMENT ROW. Josh's v4 item 10b, 2026-10-09: "The whole row is the
   download control. Clicking anywhere on it downloads the file."

   Here rather than in the JSX because the three states the item asks for,
   hover, focus and the name's underline, are pseudo-classes and a descendant
   selector, none of which an inline style can express. The focus RING itself is
   the shared one above, which already reaches every `a` and `button`.

   The row sits 8px further left than the section text it belongs under, which
   is the `margin-inline-start` on the wrapper in CardPreviewSidebar.tsx, so the
   hover tint closes around the icon instead of starting at it. A block wrapper
   with a negative left margin grows leftward and keeps its right edge, so
   nothing overflows the panel.

   Only an `a` or a `button` tints: a file Birdseye will not serve is drawn with
   the same geometry as a plain div, and a tint on a row that cannot be clicked
   is a lie about what a click does. */
/* Qualified by element, so the 8px of padding beats Mantine's own
   `.mantine-UnstyledButton-root { padding: 0 }`, which is one class and ships
   later in the cascade. Measured on staging 2026-10-09: the unqualified rule
   lost its padding outright and the icon sat flush against the row's left edge,
   8px left of the section text instead of in line with it. */
a.bb-att-row,
button.bb-att-row,
div.bb-att-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 32px;
  min-height: 32px;
  padding-inline: 8px;
  border-radius: 6px;
  background-color: transparent;
  color: inherit;
  text-align: left;
  text-decoration: none;
}
a.bb-att-row:hover,
a.bb-att-row:focus-visible,
button.bb-att-row:hover,
button.bb-att-row:focus-visible {
  background-color: var(--mantine-color-graphite-0);
}
a.bb-att-row:hover .bb-att-name,
a.bb-att-row:focus-visible .bb-att-name,
button.bb-att-row:hover .bb-att-name,
button.bb-att-row:focus-visible .bb-att-name {
  text-decoration: underline;
}
/* The name takes the squeeze and ends in an ellipsis; the size never shrinks,
   so it stays visible however long the name is. */
.bb-att-row .bb-att-name {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 13.5px;
  line-height: 1;
  color: var(--mantine-color-graphite-9);
}
.bb-att-row .bb-att-size {
  flex: 0 0 auto;
  font-size: 12.5px;
  line-height: 1;
  color: var(--mantine-color-graphite-4);
}
/* Lifted 1px, per the item, because a glyph's optical center sits below the
   cap height of the words beside it. */
.bb-att-row .bb-att-icon {
  flex: 0 0 14px;
  display: inline-flex;
  align-items: center;
  transform: translateY(-1px);
  color: var(--mantine-color-graphite-5);
}
/* A PHONE KEEPS 44px. Josh's v4 item 10b names 32px, and his d14 from
   2026-10-07 sets 44px tap targets on a phone for every control in this drawer,
   which is what the Download button this row replaces already did. The item
   says nothing about phones, so the recorded touch rule stands and the 32px is
   the desktop row. Raised with Josh in docs/BACKLOG.md. */
a.bb-att-row--touch,
button.bb-att-row--touch,
div.bb-att-row--touch {
  height: 44px;
  min-height: 44px;
}

/* THE SIGN-IN CARD, on every surface where somebody signs in to Birdseye.
   Claude Design's spec of 2026-10-27, "Birdseye - Claude Design - Sign-in card".

   HERE rather than in the components, because four surfaces have to be the
   same card and two of them are not React: the dashboard's session-ended
   screen, the dashboard's signed-out screen, web/auth.html and
   web/auth-callback.html. Only this file is linked by all four.

   Literal hex rather than var(--mantine-color-*), for the same reason: the
   Mantine variables are injected by MantineProvider and do not exist on the
   two plain HTML pages. Each value names the token it came from so the two
   cannot drift apart silently.

   The border is graphite-2, the palette's border token, and not the
   graphite-1 the spec first named. Josh, 2026-10-27: "use the border token,
   graphite.2 (#c5cfdb), so the card edge matches every other card." The token
   is `#c9c2b4` since his warm palette of 2026-11-02; the role is unchanged. */
.bb-signin-page {
  display: flex;
  justify-content: center;
  padding-inline: 16px;
}
/* THE CARD SITS IN THE MIDDLE OF THE WINDOW, not at the top of it. Josh,
   2026-10-29: "please center the login area." It is the only thing on the
   screen, so the eye should land on it rather than travel up to it.

   Only the React sign-in screens take this. The Power-Up's own authorize
   popup and its callback page use the same card inside a short Trello popup
   that the card nearly fills, where a full-window height would add a
   scrollbar and center nothing.

   It is the whole window, because the sign-in screen draws no header and no
   rail. Measured on staging while the card still sat inside AppShell.Main:
   367px above it against 255px below it at 1440x900, low by exactly the
   header height the shell reserves whether or not a header is rendered.
   App.tsx now returns these screens outside the shell, so this element is
   the page.

   CENTERED WITH `margin-block: auto` RATHER THAN `align-items: center`,
   because a flex item centered by alignment overflows equally in both
   directions when it is taller than its container, and the top of the card
   then sits above the window with no way to scroll to it. A short window and
   a tall card are exactly what a phone gives. */
.bb-signin-page--fill {
  box-sizing: border-box;
  min-height: 100vh;
  padding-block: 32px;
}
.bb-signin-page--fill .bb-signin-card {
  margin-block: auto;
}
.bb-signin-card {
  box-sizing: border-box;
  width: 100%;
  max-width: 400px;
  padding: 40px;
  background: var(--bb-surface);
  border: 1px solid var(--bb-edge);   /* the edge token */
  /* The `lg` step of Birdseye's own radius scale, so the card matches Prism's.
     Josh, 2026-10-27: "use the lg radius, 10px, not 12px." */
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(var(--bb-shadow-ink), 0.06), 0 8px 24px rgba(var(--bb-shadow-ink), 0.06);
}
/* A PHONE KEEPS THE CARD AND LOSES THE PADDING. Below 440px the card fills
   the width inside the page's 16px gutter and its own padding drops to 24px.
   The order and the gaps do not change. */
@media (max-width: 439.98px) {
  .bb-signin-card { padding: 24px; }
}
/* The primary lockup, 16px tall, width from the artwork. Everything in the
   card shares this left edge. */
.bb-signin-logo {
  display: block;
  height: 16px;
  width: auto;
}
/* The type system's Section title role, theme.ts TYPE.sectionTitle, rather
   than a size of its own. Josh, 2026-10-27: "use the Section title role,
   20px / 500 / -0.02em, not 24px." */
.bb-signin-title {
  margin: 32px 0 0 0;
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--bb-ink);               /* body ink */
}
.bb-signin-text {
  margin: 8px 0 0 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--bb-ink-soft);          /* graphite-6 */
}
/* GOOGLE'S OWN WHITE BUTTON, which is the one Prism shows and the one people
   recognize as a Google sign-in. Josh, 2026-10-27. Its values are Google's,
   not Birdseye's palette, which is the point: a sign-in button that looks
   like the product it signs you into is read faster than a styled one.
   Full card width and 40px rather than Birdseye's standard 32px, because it
   is the only action on the page.

   The mark sits 12px in from the left and the words stay centered in the whole
   button, so the icon is absolutely placed rather than part of the flow. */
.bb-signin-button {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 100%;
  height: 40px;
  margin-top: 32px;
  border: 1px solid var(--bb-google-border);
  border-radius: 4px;
  background: var(--bb-google-surface);
  color: var(--bb-google-ink);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
}
.bb-signin-button:hover {
  background: var(--bb-google-hover);
  border-color: var(--bb-google-hover-border);
}
.bb-signin-button .bb-signin-g {
  position: absolute;
  left: 12px;
  top: 50%;
  width: 18px;
  height: 18px;
  transform: translateY(-50%);
}
/* A failed round trip, 8px under the button, where it has always been. */
.bb-signin-error {
  margin: 8px 0 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--bb-coral-7);                     /* coral-7 */
}

/* THE MATRIX GRID'S OWN SIDEWAYS SCROLLBAR IS HIDDEN, because the Matrix now
   draws one pinned to the bottom of the window instead. Josh's handoff of
   2026-10-28 00:15, item 2. The box still scrolls: only the bar is gone, so
   the drag, the wheel and the pinned bar all still move it.

   Both spellings, because Chrome did not support the standard property until
   121 and Birdseye's own harness drives Chrome. */
.bb-matrix-grid-scroll {
  scrollbar-width: none;
}
.bb-matrix-grid-scroll::-webkit-scrollbar {
  height: 0;
  width: 0;
}
/* The pinned bar is the one a person uses, so it is always drawn rather than
   fading in on hover, and it is tall enough to grab. */
.bb-matrix-bottom-scrollbar {
  scrollbar-width: thin;
  scrollbar-color: var(--bb-edge) transparent;
}
.bb-matrix-bottom-scrollbar::-webkit-scrollbar {
  height: 10px;
}
.bb-matrix-bottom-scrollbar::-webkit-scrollbar-thumb {
  background: var(--bb-edge);
  border-radius: 5px;
}
.bb-matrix-bottom-scrollbar::-webkit-scrollbar-track {
  background: transparent;
}
