/* c0llect web — the iOS app's terminal design system, in CSS.
   Neutral tones are derived from the accent hue at runtime (see theme.js),
   exactly as Palette.retint does in the app. */

@font-face { font-family: "JetBrains Mono";  src: url("/fonts/JetBrainsMono.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "Fira Code";       src: url("/fonts/FiraCode-Regular.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "IBM Plex Mono";   src: url("/fonts/IBMPlexMono-Regular.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "IBM Plex Mono";   src: url("/fonts/IBMPlexMono-Bold.ttf") format("truetype"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Source Code Pro"; src: url("/fonts/SourceCodePro-Regular.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "Ubuntu Mono";     src: url("/fonts/UbuntuMono-Regular.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "Ubuntu Mono";     src: url("/fonts/UbuntuMono-Bold.ttf") format("truetype"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Inconsolata";     src: url("/fonts/Inconsolata.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "Anonymous Pro";   src: url("/fonts/AnonymousPro-Regular.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "Anonymous Pro";   src: url("/fonts/AnonymousPro-Bold.ttf") format("truetype"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Space Mono";      src: url("/fonts/SpaceMono-Regular.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "Space Mono";      src: url("/fonts/SpaceMono-Bold.ttf") format("truetype"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Roboto Mono";     src: url("/fonts/RobotoMono.ttf") format("truetype"); font-display: swap; }
@font-face { font-family: "VT323";           src: url("/fonts/VT323-Regular.ttf") format("truetype"); font-display: swap; }

:root {
  --bg: #060606;
  --bg1: #0C0C0C;
  --accent: #7DF0A6;
  --slash: #F07D8C;
  /* Gain and loss. Fixed, not derived from the accent: a rise must read as a
     rise whatever colour the interface happens to be themed. */
  --up: #7DF0A6;
  --down: #F07D8C;
  --text: #E8EFE6;
  --text2: #A9B5A4;
  --mute: #6F7A6B;
  --border: #1D241B;
  --glow: 0.65;
  --font: "JetBrains Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }

/* Must outrank any rule that sets `display` (.overlay, .tabbar), otherwise
   the hidden attribute has no effect and those elements sit over the page. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}

body { padding-bottom: env(safe-area-inset-bottom); }

button, input, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: var(--accent); text-decoration: none; }

.app {
  max-width: 960px;
  margin: 0 auto;
  padding: 0 18px 110px;
}

/* ---- type ---- */
.h1 { font-size: 26px; font-weight: 700; margin: 14px 0 0; font-family: system-ui, sans-serif; }
.big { font-size: 34px; font-weight: 700; color: var(--accent); text-shadow: 0 0 14px color-mix(in srgb, var(--accent) calc(var(--glow) * 45%), transparent); }
.mute { color: var(--mute); }
.dim { color: var(--text2); }
.small { font-size: 11px; }
.tiny { font-size: 10px; }
.err { color: var(--slash); font-size: 12px; }
.row { display: flex; align-items: center; gap: 10px; }
.between { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.col { display: flex; flex-direction: column; gap: 4px; }
.grow { flex: 1; min-width: 0; }
.ell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.section-tag {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; letter-spacing: 2px; color: var(--mute);
  text-transform: uppercase; margin: 18px 0 8px;
}
.section-tag .slash { letter-spacing: 0; }

.path { font-size: 16px; color: var(--mute); }
.path b { color: var(--accent); }

/* ---- containers ---- */
.card {
  background: color-mix(in srgb, var(--bg1) 70%, transparent);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 14px;
  display: block;
  width: 100%;
  text-align: left;
}
.card + .card { margin-top: 10px; }

/* The vertical rhythm only ever knew about cards, so any boundary involving a
   search field collapsed to nothing: the portfolio chart sat directly on the
   filter box, and on the search and collectors pages the box sat directly on
   the panel below it. Scoped to the view's own children so that fields nested
   inside a card — settings, admin, the login form — keep their own layout. */
#root > * + .field,
#root > .field + * { margin-top: 10px; }
.card.hl { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.card.tap { transition: transform .12s ease, opacity .12s ease; }
.card.tap:active { transform: scale(.985); opacity: .85; }

.divider { height: 1px; background: var(--border); margin: 12px 0; }

/* ---- controls ---- */
.chip {
  font-size: 11px; color: var(--text2);
  padding: 5px 10px; border: 1px solid var(--border); border-radius: 7px;
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
}
.chip.on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
.chip.fill { color: var(--bg); background: var(--accent); border-color: transparent; }

.pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--accent); color: var(--bg);
  font-size: 15px; padding: 13px 26px; border-radius: 999px;
  box-shadow: 0 0 16px color-mix(in srgb, var(--accent) calc(var(--glow) * 45%), transparent);
}
.pill[disabled] { opacity: .4; box-shadow: none; }
.pill.danger { background: var(--slash); }

.tbtn {
  font-size: 13px; color: var(--accent);
  padding: 9px 14px; border: 1px solid var(--border); border-radius: 10px;
}
.tbtn:active { background: var(--bg1); }
.tbtn.danger { color: var(--slash); }

.icon-btn {
  width: 36px; height: 36px; border-radius: 999px; border: 1px solid var(--border);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text2); font-size: 15px; flex: none;
}
.icon-btn.on { background: var(--accent); color: var(--bg); border-color: transparent; }

.field {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg1); border: 1px solid var(--border);
  border-radius: 12px; padding: 12px 13px;
}
.field:focus-within { border-color: color-mix(in srgb, var(--accent) 50%, transparent); }
.field input {
  background: none; border: 0; outline: none; width: 100%;
  font-size: 14px; color: var(--text);
}
.field input::placeholder { color: var(--mute); }
.field .cue { color: var(--accent); }

/* ---- tab bar ---- */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0;
  background: color-mix(in srgb, var(--bg1) 95%, transparent);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--border);
  display: flex; padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
  z-index: 20;
}
.tabbar button {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 6px 0; color: var(--mute); font-size: 9px; letter-spacing: 1px;
}
.tabbar button.on { color: var(--accent); }
.tabbar svg { width: 20px; height: 20px; }

/* ---- lists & grids ---- */
.grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
}
/* Larger thumbnails, but only where there is room for them. Raising the minimum
   everywhere cost a phone its third column — at 390px wide the grid dropped
   from three cards to two — so the bigger tile starts once the viewport can
   afford it. Above 960px the container stops growing, so this settles at six
   columns of 142px rather than the six of 119px it was. */
@media (min-width: 640px) {
  .grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
}
.tile img, .cardimg {
  width: 100%; aspect-ratio: 63 / 88; object-fit: contain;
  border-radius: 6px; background: var(--bg1); display: block;
}
.tile .name { font-size: 12px; margin-top: 6px; }
.tile .price { font-size: 12px; font-weight: 700; color: var(--accent); }
.tile.off img { opacity: .45; }
.owned-dot {
  position: absolute; top: 6px; right: 6px;
  width: 18px; height: 18px; border-radius: 999px;
  background: var(--accent); color: var(--bg);
  display: grid; place-items: center; font-size: 10px; font-weight: 700;
}
.tile { position: relative; }

/* ---- quick add: the + in the corner of a card's artwork ---- */
/* The overlays position against the picture, which is why it gets its own
   box: the tile around it is taller by a name and a price. */
.tileart { position: relative; line-height: 0; }
.quickadd {
  position: absolute; right: 5px; bottom: 5px;
  display: grid; place-items: center; cursor: pointer;
  width: 22px; height: 22px; border-radius: 999px;
  font-size: 15px; line-height: 1; padding-bottom: 1px;
  /* Near-solid, not the washed 78% it was: at that opacity the artwork came
     through as grey haze and swallowed the ring. A disc this dark reads as a
     deliberate plate, and the accent ring sits cleanly on it whatever the
     card underneath is doing. */
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  border: 1px solid var(--accent);
  color: var(--accent);
}
.quickadd:hover, .quickadd:focus-visible { background: var(--accent); color: var(--bg); }

/* ---- admin: artwork badge on a grid tile ---- */
.artbadge {
  position: absolute; top: 6px; left: 6px;
  font: inherit; font-size: 9px; line-height: 1;
  padding: 4px 6px; border-radius: 5px; cursor: pointer;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border: 1px dashed color-mix(in srgb, var(--accent) 70%, transparent);
  color: var(--accent);
}
.artbadge:hover { background: var(--accent); color: var(--bg); border-style: solid; }
/* Cards that already have a picture only need a quiet way in. */
.artbadge.has {
  border-style: solid; border-color: var(--border);
  color: var(--mute); opacity: .35; padding: 4px 5px;
}
.tile:hover .artbadge.has { opacity: 1; }
/* On a set logo the badge has no tile to hover, so it stays legible. */
.setart + .artbadge, .artbadge.has:hover { opacity: 1; }

.thumb { width: 46px; flex: none; position: relative; }
.setart { width: 62px; height: 34px; object-fit: contain; flex: none; }
/* The set page's header logo. It lived as an inline style on the element, which
   silently outranked this file — raising `.setart` did nothing there, because
   the header was never reading it. Kept as a class so the size is in one place
   and can actually be changed from here. */
.setart.lg { width: 92px; height: 53px; }

.bar { height: 3px; border-radius: 999px; background: var(--border); overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--accent); }

/* ---- swipe-free row actions ---- */
.rowacts { display: flex; gap: 6px; }

/* ---- overlay / modal ---- */
.overlay {
  position: fixed; inset: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  display: grid; place-items: center; padding: 18px;
}
.sheet {
  background: var(--bg); border: 1px solid var(--border); border-radius: 16px;
  width: 100%; max-width: 460px; padding: 18px; max-height: 86vh; overflow: auto;
}
/* ---- price movement ---- */
.move { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.move.up { color: var(--up); }
.move.down { color: var(--down); }
.move .arrow { display: inline-flex; align-items: center; line-height: 1; }

/* ---- bulk uploader ---- */
.sheet.bulk { max-width: 860px; width: 96vw; max-height: 90vh; display: flex; flex-direction: column; gap: 10px; }
.bulk-body { flex: 1; overflow: auto; margin: 4px -4px; }
.bulk-row {
  display: grid; grid-template-columns: minmax(120px, 1.6fr) repeat(auto-fit, minmax(92px, 1fr));
  gap: 6px; align-items: center; padding: 6px 4px;
  border-bottom: 1px solid var(--border);
}
.bulk-row.bulk-head { position: sticky; top: 0; z-index: 1; background: var(--bg); border-bottom-color: var(--accent); }
.bulk-name { min-width: 0; }
.bulk-cell { display: flex; flex-direction: column; gap: 2px; align-items: center; }
.bulk-cell.off { opacity: .25; }
.bulk-step {
  width: 22px; height: 26px; flex: none; cursor: pointer;
  background: var(--bg1); border: 1px solid var(--border); border-radius: 6px;
  color: var(--text2); font: inherit; font-size: 13px; line-height: 1;
}
.bulk-step:active { background: var(--accent); color: var(--bg); }
.bulk-qty {
  width: 34px; height: 26px; text-align: center; font: inherit; font-size: 12px;
  background: var(--bg1); border: 1px solid var(--border); border-radius: 6px;
  color: var(--mute); outline: none; padding: 0;
}
.bulk-qty.has { color: var(--accent); font-weight: 700; border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.bulk-total { border-top: 1px solid var(--accent); padding-top: 10px; }

.overlay.zoom { background: rgba(0,0,0,.94); }
.overlay.zoom img { max-width: 94vw; max-height: 88vh; border-radius: 12px; }

.avatar {
  width: 42px; height: 42px; border-radius: 999px; flex: none;
  border: 1px solid var(--border); object-fit: cover; background: var(--bg1);
}
.avatar.lg { width: 60px; height: 60px; }
.avatar-glyph {
  display: grid; place-items: center; color: var(--accent);
  font-size: 13px; font-weight: 700;
}

.spinner {
  width: 16px; height: 16px; border-radius: 999px;
  border: 2px solid var(--border); border-top-color: var(--accent);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(78px + env(safe-area-inset-bottom));
  background: var(--bg1); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px 14px; font-size: 12px; z-index: 30;
  box-shadow: 0 8px 30px rgba(0,0,0,.6);
}

/* charts */
/* Room under the plot for the date labels that hang below it. */
/* Two bands, not one box. The x labels used to be positioned below the svg
   while the lowest y label straddled that same edge, so the last date sat on
   top of the lowest price. Each now has room of its own. */
.chart-wrap { position: relative; margin-bottom: 14px; }
.chart-plot { position: relative; }
.chart-axis { position: relative; height: 14px; margin-top: 3px; }
/* Named apart from the layout `.grid`, which an svg line would otherwise
   inherit `display: grid` from. */
.chart-grid { stroke: var(--border); stroke-width: 1; vector-effect: non-scaling-stroke; }
/* Labels sit over the chart rather than inside it — the svg is stretched to
   fit its box, and text inside would stretch with it. */
.chart-y, .chart-x {
  position: absolute; font-size: 8px; color: var(--mute);
  pointer-events: none; white-space: nowrap;
}
.chart-y { right: 2px; transform: translateY(-50%); }
/* Nudged in from the edges so the first and last never clip. */
.chart-y:first-of-type { transform: translateY(0); }
.chart-y:last-of-type { transform: translateY(-100%); }
.chart-x { top: 0; }

/* The readout. A price chart you cannot read a price off is decoration. */
.chart-cursor {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: color-mix(in srgb, var(--accent) 45%, transparent);
  pointer-events: none;
}
.chart-dot {
  position: absolute; width: 7px; height: 7px; border-radius: 999px;
  background: var(--accent); box-shadow: 0 0 8px var(--accent);
  transform: translate(-50%, -50%); pointer-events: none;
}
.chart-tip {
  position: absolute; top: 2px; z-index: 3;
  font-size: 10px; white-space: nowrap; pointer-events: none;
  color: var(--text); background: color-mix(in srgb, var(--bg) 88%, transparent);
  border: 1px solid var(--border); border-radius: 6px; padding: 3px 7px;
}

.chart { width: 100%; height: 110px; display: block; }
.chart .line { fill: none; stroke: var(--accent); stroke-width: 1.6; }
.chart .area { fill: url(#g); }
.chart .grid { stroke: var(--border); stroke-width: 1; }
.chart-empty { position: relative; height: 110px; display: grid; place-items: center; }
.chart-empty .chart { position: absolute; inset: 0; filter: blur(7px); opacity: .4; }
.chart-empty span {
  position: relative; font-size: 11px; color: var(--text2);
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  padding: 6px 10px; border-radius: 8px;
}

/* Prev/next through a set, pinned to either edge of the viewport so they stay
   put while the card page scrolls. Only rendered for cards opened from a set,
   and never at the ends of the list. */
.card-step {
  position: fixed; top: 50%; transform: translateY(-50%);
  width: 34px; height: 52px; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border: 1px solid var(--border); color: var(--text2);
  font-size: 20px; line-height: 1; cursor: pointer;
  border-radius: 10px;
}
.card-step:hover { color: var(--accent); border-color: var(--accent); }
/* Flat against the edge it is pinned to. */
.card-step[style*="left"] { border-top-left-radius: 0; border-bottom-left-radius: 0; border-left: none; }
.card-step[style*="right"] { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: none; }

/* On a narrow screen the arrows would sit on top of the artwork, so they move
   to the bottom corners where the thumbs already are. */
@media (max-width: 560px) {
  .card-step { top: auto; bottom: 84px; transform: none; height: 44px; }
}

/* Every page's title row, and the gap beneath it.
   One rule rather than a margin written out at each call site: the pages had
   drifted to 14, 16 and 12px below their titles, so the same heading sat a
   different distance from its content depending which page you were on. */
.page-head { margin-top: 14px; margin-bottom: 14px; }

/* A key for the extra printing lines. Without names, a second line is a
   mystery rather than information. */
.chart-legend {
  display: flex; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 6px; font-size: 9px; color: var(--mute);
}
.chart-key { display: inline-flex; align-items: center; gap: 5px; }
.chart-swatch { width: 12px; height: 2px; border-radius: 1px; flex: none; }

/* A set logo inside a chip. Height is set by the label beside it, so a chip
   is the same height with or without one. */
.chip-icon {
  height: 13px; width: auto; max-width: 26px;
  object-fit: contain; flex: none;
}
.chip { display: inline-flex; align-items: center; gap: 6px; }

/* ---- Japanese-catalogue flag, bottom-right of the artwork ---- */
.jpflag {
  position: absolute; right: 4px; bottom: 4px;
  font-size: 12px; line-height: 1;
  padding: 1px 2px; border-radius: 3px;
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  pointer-events: none;
}
/* The quick-add button owns that corner on set pages, so the flag steps aside
   rather than sitting underneath it. */
.tileart:has(.quickadd) .jpflag { right: 30px; }
.thumb .jpflag { font-size: 9px; right: 1px; bottom: 1px; padding: 0 1px; }
