/* Web 1.0 aesthetics, web 2.0 optimization — spec grabatool-spec.md §9.3. No
   rounded corners, no shadows, no gradients, no transitions. */

* {
  box-sizing: border-box;
}

/* This app has no dark theme (spec §9.3 — Craigslist-style, light only).
   Without this, a phone in OS dark mode still gets native dark-mode
   rendering for form controls and checkboxes from the browser's own UA
   stylesheet, even though every color on the page is set explicitly by
   this file — the mismatch is exactly what made buttons render white text
   on the light grey background *this file* sets, and made checkboxes
   render with barely-visible check marks against their light surroundings. */
:root {
  color-scheme: light;
}

body {
  font-family:
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Helvetica,
    Arial,
    sans-serif;
  font-size: 15px;
  color: #111;
  background: #fff;
  margin: 0;
}

a {
  color: #0645ad;
  text-decoration: underline;
}

a:visited {
  color: #551a8b;
}

header.site {
  padding: 8px 16px;
  /* Extends the header's own grey background up under the status bar/notch
     (user request: "correctly inform the notch color on iOS") — iOS's
     `black-translucent` status bar (views/layout.tsx) draws over the page
     rather than reserving its own bar, so without this the notch area
     would show whatever's behind it (the white body background) instead of
     matching the header. `env()` is 0 with no safe area (desktop, Android,
     a browser tab), so this is a no-op everywhere else. */
  padding-top: calc(8px + env(safe-area-inset-top));
  border-bottom: 1px solid #999;
  background: #f2f2f2;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

header.site .brand {
  font-weight: bold;
  text-decoration: none;
  color: #111;
}

header.site nav a {
  margin-right: 12px;
}

header.site .user {
  margin-left: auto;
  font-size: 14px;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

header.site .user-name {
  font-weight: bold;
}

header.site .user form {
  margin: 0;
}

/* Pull-to-refresh indicator (user request), injected by pwa.js. The
   browser's own native pull-to-refresh only exists inside an ordinary
   mobile browser tab — once installed to the home screen (this app's
   manifest sets `display: standalone`), there's no browser chrome left to
   provide it, so this small banner and the gesture that drives it
   (pwa.js) replace it everywhere, tab or installed. Positioned above the
   header, off-screen by default; pwa.js slides it down (`translateY`) as
   the user drags. */
.pull-refresh-indicator {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  padding: 8px 16px;
  padding-top: calc(8px + env(safe-area-inset-top));
  text-align: center;
  font-size: 0.9em;
  color: #111;
  background: #f2f2f2;
  border-bottom: 1px solid #999;
  transform: translateY(-100%);
}

.pull-refresh-indicator.pull-armed {
  transition: none; /* follows the finger 1:1 while dragging, no lag */
}

.pull-refresh-indicator.pull-releasing {
  transition: transform 0.15s ease-out; /* snaps back (or to 0, on refresh) once released */
}

/* Hamburger toggle (checkbox hack — no JS). Hidden entirely above the
   mobile breakpoint below; visually hidden but still focusable/keyboard-
   operable above it, per the label it controls. */
.nav-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.nav-toggle-label {
  display: none;
}

main {
  padding: 16px;
  max-width: 1100px;
}

h1 {
  font-size: 20px;
}

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

/* Wraps every `.library-table` (the shared component behind /library,
   /search, a friend's profile, and home's "recently added by friends"
   panel — views/library.tsx's `LibraryTable`) so a table wider than its
   container scrolls horizontally inside itself instead of overflowing it.
   Previously scoped to the mobile breakpoint only, on the assumption a
   desktop viewport is always wide enough — false inside a narrow
   `.dashboard-grid` panel, where a full Image/Title/Tags/Owner/Type/State
   table routinely is wider than a ~280px grid column and spilled straight
   through the panel's own border. Applying this at every width fixes that
   without needing a separate desktop-only rule. */
.library-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

th,
td {
  border: 1px solid #999;
  padding: 4px 8px;
  text-align: left;
  font-size: 14px;
  vertical-align: top;
}

th {
  background: #eee;
}

tbody tr:nth-child(even) {
  background: #f7f7f7;
}

tbody tr:hover {
  background: #f0f0f0;
}

/* Selectable /library rows: the whole row toggles the checkbox on click
   (public/islands/row-select.js) — cursor:pointer signals that beyond the
   checkbox cell itself, everywhere except the real links/buttons in the row. */
tr.row-selectable {
  cursor: pointer;
}

/* Selection is shown by highlighting the whole row (user request), not a
   visible checkbox — the checkbox itself still exists in the DOM (see
   `.row-select-checkbox` below) purely so the form has something real to
   submit; row-select.js keeps this class in sync with it. `!important`
   because this needs to visibly win over both the plain zebra-striping and
   the hover background above regardless of source order. */
tr.row-selectable.selected {
  background: #dce8fb !important;
}

/* The checkbox that actually gets submitted with the form — visually
   hidden the same way the nav hamburger's own checkbox is (clipped, not
   display:none, so it stays focusable/keyboard-operable), never shown as a
   literal checkbox UI. `!important` on every property: this exact pattern
   has already been fought over sizing rules twice this session (see
   CLAUDE.md), so nothing else in this file — now or later — should be able
   to accidentally resize or reveal it. */
.row-select-checkbox {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* `auto` here would NOT restore the browser's own hand cursor for links —
   that default comes from the UA stylesheet's own `cursor: pointer` rule on
   `a[href]`, and author CSS always wins over UA CSS regardless of
   specificity. Overriding with `auto` discards that rule entirely, and
   `auto`'s own generic resolution over a link's actual text glyphs is the
   text-selection I-beam, not a hand — exactly the bug this was showing.
   Setting `pointer` explicitly is what actually gets the hand cursor back. */
tr.row-selectable a,
tr.row-selectable button {
  cursor: pointer;
}

tr.row-selectable input {
  cursor: auto;
}

.filters {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
  flex-wrap: wrap;
  align-items: center;
}

input,
select,
textarea,
button {
  font: inherit;
  color: #111;
  padding: 4px 6px;
  border: 1px solid #999;
  background: #fff;
}

button {
  background: #f0f0f0;
  cursor: pointer;
}

/* A `<button>` that should read as a de-emphasized, secondary action rather
   than a normal prominent one (item detail's "Archive", next to the
   real/primary "Edit" button) — still a real <button> for correct POST
   semantics, just stripped down to look like a plain text link. */
.link-button {
  background: none;
  border: none;
  padding: 0;
  color: #0645ad;
  text-decoration: underline;
  font: inherit;
}

/* Checkboxes and radios render as small native widgets, not text-box-like
   controls — the padding/border above (meant for text inputs/selects) was
   landing on them too, which is what made a radio's own little circle sit
   oddly out of line with the label text next to it. Reset those two
   properties back to nothing so the browser's native widget renders at its
   normal size with nothing boxed around it. */
input[type='checkbox'],
input[type='radio'] {
  padding: 0;
  border: none;
  background: transparent;
  vertical-align: middle;
  accent-color: #0645ad;
}

.field-row {
  position: relative;
  margin-bottom: 10px;
  max-width: 480px;
}

.field-row label {
  display: block;
  font-size: 13px;
  margin-bottom: 2px;
}

.field-row input,
.field-row select,
.field-row textarea {
  width: 100%;
}

.error {
  color: #b3261e;
  font-size: 13px;
}

.empty {
  color: #555;
}

.actions {
  margin: 12px 0;
}

/* Grouped sections (currently just the homepage dashboard) — a grey box
   header over a bordered body, the same light-grey-bar-over-white-panel
   pattern Craigslist uses for its category groupings. Panels lay out
   side by side via .dashboard-grid instead of stacking the full page
   width, so wide viewports show more than one column of nearly-empty
   whitespace. */
.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
  align-items: start;
  margin-top: 16px;
}

.panel {
  border: 1px solid #999;
  /* A grid item's default `min-width: auto` lets it grow past its own
     track to fit its content's intrinsic width instead of shrinking to
     fit — a wide `.library-table` (home's "recently added by friends"
     panel) pushed the whole panel wider than its grid column and past its
     own border as a result. `min-width: 0` lets the panel shrink to the
     track's actual width, so `.library-table-wrap`'s own horizontal
     scrolling below can do its job instead. */
  min-width: 0;
}

.panel > h2 {
  margin: 0;
  padding: 6px 10px;
  background: #eee;
  border-bottom: 1px solid #999;
  font-size: 15px;
}

.panel-body {
  padding: 10px;
}

.panel-body ul {
  margin: 0;
  padding-left: 18px;
}

.panel-body .empty {
  margin: 0;
}

/* Borrower combobox dropdown (spec §9.1) — plain list, matches table borders. */
.combobox-list {
  position: absolute;
  z-index: 1;
  top: 100%;
  left: 0;
  right: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  background: #fff;
  border: 1px solid #999;
  border-top: none;
  max-height: 200px;
  overflow-y: auto;
}

.combobox-list li {
  padding: 4px 6px;
  cursor: pointer;
}

.combobox-list li.active,
.combobox-list li:hover {
  background: #f0f0f0;
}

/* Loan state — a plain coloured word, never a pill or chip (spec §9.3). */
.state-available {
  color: #146c2e;
}

.state-out {
  color: #8a6d00;
}

@media (max-width: 640px) {
  table,
  thead,
  tbody,
  tr,
  th,
  td {
    display: block;
  }
  thead {
    display: none;
  }
  /* A bottom-border separator between rows, not a bordered box around each
     one — full-border "cards" plus one-field-per-line stacking below is what
     made the mobile library view read as gigantic; this is a plain compact
     list instead. overflow:hidden clears the floated thumb cell below so
     the border sits under it rather than cutting through. */
  tbody tr {
    border-bottom: 1px solid #ccc;
    padding: 6px 2px;
    overflow: hidden;
  }
  td {
    border: none;
    padding: 1px 4px;
    font-size: 13px;
  }
  td[data-label]::before {
    content: attr(data-label) ': ';
    font-weight: bold;
  }
  /* Empty-label cells (the thumbnail) have nothing worth a "label: " prefix
     — without this, attr() renders a stray ": " with nothing after it.
     Same specificity as the rule above; wins because it comes later. */
  td[data-label='']::before {
    content: none;
  }
  /* Library rows: float the thumbnail left so the title sits beside it and
     the rest of the row wraps below — two compact lines per item instead
     of one full-width line per field. */
  .col-thumb {
    float: left;
    padding: 0 6px 0 0;
  }
  .col-title {
    overflow: hidden; /* clears the float without a guessed fixed margin */
    padding-top: 2px;
    font-weight: bold;
  }
  .col-title a {
    display: inline;
    min-height: auto;
    line-height: 1.3;
    padding: 0;
  }
  .col-thumb a {
    display: block;
    min-height: auto;
    line-height: 1;
    padding: 0;
  }
  td[data-label='Title']::before {
    content: none;
  }
  /* Secondary metadata (not the title, not the state/actions) is de-
     emphasized and packed tighter — it's context, not the point of the row. */
  td[data-label='Owner'],
  td[data-label='Type'],
  td[data-label='Tags'] {
    clear: both;
    color: #555;
    font-size: 12px;
  }
  input,
  select,
  button {
    min-height: 44px;
  }
  /* Nav and action links are as tappable as buttons everywhere else on the
     page — same 44px minimum, via padding since a link has no min-height
     effect on its own inline box the way a form control's does. */
  header.site nav a,
  .actions a,
  td a {
    display: inline-block;
    min-height: 44px;
    line-height: 44px;
    padding: 0 4px;
  }
  .combobox-list li {
    min-height: 44px;
    line-height: 44px;
    padding: 0 6px;
  }
  /* Filter rows (search + tag select + button) stack full-width instead of
     cramming into whatever space three inline flex items happen to get on a
     narrow screen — same "stack below 640px" treatment as the table above. */
  .filters {
    flex-direction: column;
    align-items: stretch;
  }
  .filters > * {
    width: 100%;
  }
  .dashboard-grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  /* .library-table (library/search/friend profile/home's "recently added"
     panel) gets a completely different, much simpler mobile treatment: it
     stays a real table instead of the block-per-field stack above — made
     compact and horizontally scrollable, per user request, rather than
     tall and vertically stacked.

     `!important` throughout this block is deliberate, not a shortcut: two
     earlier attempts at this same override (plain specificity, then a
     `:not()` exclusion on the rules above) each shipped a real bug caught
     only by a live user on a real phone — this project has no way to test
     CSS rendering in this environment (see CLAUDE.md), so plain specificity
     math that "should" win isn't trustworthy enough here. `!important`
     removes the ambiguity entirely: these values apply, full stop,
     regardless of anything above or added later. (`.library-table-wrap`'s
     own overflow-x rule now lives above, at the top of the file, applying
     at every width — not just here — since a narrow `.dashboard-grid`
     panel needs it on desktop too.) */
  .library-table {
    display: table !important;
    table-layout: fixed !important;
    width: 100% !important;
  }
  .library-table thead {
    display: table-header-group !important;
  }
  .library-table tbody {
    display: table-row-group !important;
  }
  .library-table tr {
    display: table-row !important;
  }
  .library-table th,
  .library-table td {
    display: table-cell !important;
    float: none !important;
    clear: none !important;
    overflow: visible !important;
    border: 1px solid #999 !important;
    padding: 3px 4px;
    font-size: 12px;
    /* Aggressive wrap, not horizontal scroll (user request — the previous
       nowrap approach let a row run off the screen edge instead of fitting
       it). table-layout:fixed above pins every column to the widths set on
       the <col> elements below, so wrapping here has a fixed box to wrap
       inside rather than growing the table wider than the viewport. */
    white-space: normal;
    overflow-wrap: anywhere;
    word-break: break-word;
  }
  /* Column widths, set on <col> (views/library.tsx's <colgroup>) rather than
     on th/td directly — table-layout:fixed's column-sizing algorithm is
     spec-defined to key off <col> or the first row's cells, and this project
     has no way to verify "should work by spec" CSS in a real browser (see
     CLAUDE.md) after getting burned twice already trying cleverer
     approaches, so this uses the mechanism the spec actually guarantees.
     col-state is left unset — it takes whatever's left over. */
  .library-table .col-thumb {
    width: 34px !important;
  }
  .library-table .col-title {
    width: 26% !important;
  }
  .library-table .col-tags {
    width: 24% !important;
  }
  .library-table .col-owner {
    width: 18% !important;
  }
  .library-table .col-type {
    width: 12% !important;
  }
  .library-table td[data-label]::before {
    content: none !important;
  }
  .library-table td a,
  .library-table td button {
    display: inline !important;
    min-height: auto !important;
    line-height: inherit;
    padding: 0;
    font-size: inherit;
  }
  .library-table .col-thumb img {
    width: 28px;
    height: 28px;
  }
}

/* Hamburger breakpoint — deliberately wider than the 640px touch/table
   breakpoint above. With nine nav links plus the brand and user block, the
   nav's natural width runs to roughly 1000px+ (rough estimate, not measured
   in a real browser — see CLAUDE.md's other notes on that limitation in this
   environment); leaving the hamburger switch at 640px would let the nav wrap
   onto a second header line on ordinary narrow-desktop/tablet widths well
   above phone size, breaking the "chrome is one header line" rule (spec
   §9.3). 1100px matches `main`'s own max-width, so the two breakpoints where
   the layout visibly changes line up instead of being two arbitrary numbers.
   Collapses nav + the user/logout block behind the toggle, leaving only the
   brand and the toggle button on the header's first line; both reappear,
   stacked full-width, once checked. */
@media (max-width: 1100px) {
  .nav-toggle-label {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-left: auto;
    border: 1px solid #999;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
  }
  .nav-toggle:focus-visible + .nav-toggle-label {
    outline: 2px solid #0645ad;
    outline-offset: 2px;
  }
  header.site nav,
  header.site .user {
    display: none;
    width: 100%;
    margin-left: 0;
  }
  header.site nav {
    flex-direction: column;
  }
  header.site .user {
    align-items: center;
    gap: 8px;
    padding-top: 6px;
    border-top: 1px solid #ccc;
  }
  .nav-toggle:checked ~ nav,
  .nav-toggle:checked ~ .user {
    display: flex;
  }
}
