/* Contract: contracts/web/rules.md
   Image-first archive browser. Dark by default because artwork reads better on it;
   follows the OS in either direction. */

:root {
  color-scheme: light dark;
  --bg:        light-dark(#f6f5f2, #14141a);
  --panel:     light-dark(#ffffff, #1c1c24);
  --panel-2:   light-dark(#eceae5, #23232d);
  --ink:       light-dark(#1a1a1f, #eceaf2);
  --ink-dim:   light-dark(#6a6a75, #9a9aa8);
  --line:      light-dark(#dcd9d2, #2f2f3b);
  --accent:    light-dark(#b8442c, #ff7a5c);
  --ok:        light-dark(#2f7d54, #52c48a);
  --warn:      light-dark(#9a6a12, #e0b458);
  --radius: 10px;
  --bar-h: 62px;
  /* One height for every control in the filter bar. Taller than the old 32px:
     these are the controls a 70-year-old uses on a laptop trackpad. */
  --control-h: 38px;
  --sidebar-w: 236px;
}

* { box-sizing: border-box; }

/* `hidden` means hidden.
   The user agent's rule for it is `display: none` at the weakest possible
   specificity, so any component rule that sets display — .btn, .dlg, .dropveil,
   .uploads — silently outranks it and the element stays on screen with its
   .hidden property cheerfully reporting true. That has now caused the same bug
   four separate times in this file, each fixed locally. This is the general
   fix, and it is one of the few places !important is the correct tool: the
   whole job of the rule is to outrank the component. */
[hidden] { display: none !important; }

/* Chrome that gets dragged across should not turn blue.
   Cards are draggable onto folders now, and a drag that starts a hair off a
   card — or ends short of one — sweeps a text selection over every label it
   passes. Captions and filenames stay selectable; the furniture does not. */
.sidebar, .tabs, .filters, .folderbar, .selbar, .card .meta .name,
.chip-toggle, .frow, .newfolder, .tabadd, .badge, .chips {
  user-select: none; -webkit-user-select: none;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.5 ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
}

/* ---------- 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 is 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.

   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 > .tabs,
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); }

/* ---------- grid ---------- */
.grid {
  display: grid; gap: 14px; padding: 18px 20px 60px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; cursor: pointer; transition: transform .12s ease, border-color .12s ease;
}
.card:hover { transform: translateY(-2px); border-color: var(--accent); }
.shot {
  aspect-ratio: 1; background: var(--panel-2);
  display: flex; align-items: center; justify-content: center; position: relative;
}
.shot img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* Transparency, shown rather than implied.
   A cutout flattened onto white is indistinguishable from artwork that really
   does have a white background, which matters when the whole point of the file
   is that it drops onto any backdrop. The checkerboard is drawn behind the
   image rather than baked into it, so it stays crisp at any size and the
   thumbnail the classifier reads is untouched. */
.alpha-bg {
  --sq: 10px;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #d8d8dc 25%, transparent 25%, transparent 75%, #d8d8dc 75%),
    linear-gradient(45deg, #d8d8dc 25%, transparent 25%, transparent 75%, #d8d8dc 75%);
  background-size: calc(var(--sq) * 2) calc(var(--sq) * 2);
  background-position: 0 0, var(--sq) var(--sq);
}
.inspector .big.alpha-bg { --sq: 14px; }

/* Hover playback: the clip fades in over the still, so there is no jump. */
.shot .preview {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; opacity: 0; transition: opacity .18s ease; pointer-events: none;
}
.shot.playing .preview { opacity: 1; }
.shot.playable::after {
  content: '▶'; position: absolute; right: 7px; bottom: 7px;
  font-size: 10px; line-height: 1; padding: 4px 6px; border-radius: 5px;
  background: color-mix(in srgb, var(--panel) 78%, transparent);
  color: var(--ink-dim); backdrop-filter: blur(6px); transition: opacity .18s ease;
}
.shot.playing::after { opacity: 0; }

/* Right-click menu */
.ctx {
  position: fixed; z-index: 60; min-width: 190px; padding: 5px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 12px 34px rgba(0,0,0,.32);
}
.ctx button {
  display: block; width: 100%; text-align: left; padding: 7px 10px;
  background: none; border: 0; border-radius: 6px;
  color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
}
.ctx button:hover { background: var(--panel-2); }
.ctx button.danger { color: var(--accent); }
.ctx hr { border: 0; border-top: 1px solid var(--line); margin: 5px 2px; }

.btn.danger { background: var(--accent); }
.cfname { font-weight: 600; margin: 0 0 8px; word-break: break-word; }
.shot .none { color: var(--ink-dim); font-size: 26px; }
.badge {
  position: absolute; top: 7px; left: 7px;
  padding: 2px 7px; border-radius: 6px; font-size: 10px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  background: color-mix(in srgb, var(--panel) 82%, transparent); backdrop-filter: blur(6px);
}
.badge.canonical { background: var(--ok); color: #08120c; }
.badge.deck { background: var(--warn); color: #14141a; }
.meta { padding: 9px 11px 11px; }
.meta .name {
  font-size: 12.5px; font-weight: 560; margin-bottom: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.meta .sub { font-size: 11.5px; color: var(--ink-dim); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lowconf { color: var(--warn); font-weight: 600; }

.empty { padding: 60px 20px; text-align: center; color: var(--ink-dim); }

/* ---------- workspace: grid beside a permanent inspector ----------
   The inspector used to be a drawer over the grid with a scrim behind it, so
   checking six files meant six open-read-close cycles with the results hidden
   for all of them. It is a column now: clicking a card changes what it shows. */
.workspace {
  display: grid; grid-template-columns: 1fr var(--inspector-w);
  /* minmax(0, 1fr) rather than 1fr: a grid row sized `1fr` still refuses to go
     below the height of its contents, so an overflowing column would push the
     row past the frame instead of scrolling inside it. */
  grid-template-rows: minmax(0, 1fr);
  flex: 1; min-height: 0;
}
.results { min-width: 0; min-height: 0; position: relative; overflow-y: auto; }

.inspector {
  background: var(--panel); border-left: 1px solid var(--line);
  overflow-y: auto; padding: 20px;
}
.inspector-empty {
  color: var(--ink-dim); font-size: 13px; line-height: 1.6;
  padding: 28px 4px; text-align: center;
}
/* Only ever the escape hatch for the narrow overlay layout. */
.inspector-close { display: none; }

.inspector .big {
  width: 100%; border-radius: var(--radius); background: var(--panel-2);
  margin-bottom: 16px; display: block;
}
/* The 256px stand-in, blown up to panel width while the real one loads. A touch
   of blur is the honest rendering of it: without it the enlarged pixels read as
   a bad export rather than as a picture still arriving. */
.inspector .big.upgrading { filter: blur(1.2px); }
.inspector .big { transition: filter .18s ease; }
@media (prefers-reduced-motion: reduce) {
  .inspector .big { transition: none; }
}
.inspector h2 { font-size: 16px; margin: 0 0 4px; word-break: break-word; }
.inspector .caption { color: var(--ink-dim); font-size: 13.5px; margin: 0 0 16px; }
.rows { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; font-size: 13px; margin-bottom: 18px; }
.rows dt { color: var(--ink-dim); }
.rows dd { margin: 0; word-break: break-word; }
.rows code { font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--ink-dim); }
.tags { display: flex; flex-wrap: wrap; gap: 5px; }
.tag { background: var(--panel-2); border-radius: 6px; padding: 2px 7px; font-size: 11.5px; }
.transcript { margin: 4px 0 18px; font-size: 13px; }
.transcript summary { cursor: pointer; color: var(--ink-dim); font-size: 12px; font-weight: 600; }
.transcript p { background: var(--panel-2); border-radius: 8px; padding: 10px 12px; margin: 10px 0 0; line-height: 1.6; }
.transcript .translated { color: var(--ink-dim); }

.actions { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.btn {
  padding: 8px 14px; border: 0; border-radius: 8px; cursor: pointer;
  background: var(--accent); color: #fff; font: inherit; font-size: 13px; font-weight: 560;
  text-decoration: none; display: inline-block;
}
.btn.sec { background: var(--panel-2); color: var(--ink); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

.edit { border-top: 1px solid var(--line); padding-top: 16px; }
.edit h3 { font-size: 13px; margin: 0 0 10px; color: var(--ink-dim); font-weight: 600; }
.edit label { display: block; font-size: 12px; color: var(--ink-dim); margin-bottom: 10px; }
.edit select, .edit input {
  width: 100%; margin-top: 4px; padding: 7px 10px;
  background-color: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; font: inherit; font-size: 13px;
}
/* Keep the drawn chevron clear of the text — the shared select rule owns the
   right-hand padding, and a width-setting rule must not take it back. */
.edit select { height: 34px; padding: 0 32px 0 10px; }
.saved { color: var(--ok); font-size: 12.5px; margin-left: 10px; }

/* ---------- account + invites ---------- */
.ghost.tiny { padding: 2px 8px; font-size: 11.5px; }

.dlg {
  border: 1px solid var(--line); border-radius: 12px; padding: 22px;
  background: var(--panel); color: var(--ink); width: min(440px, 92vw);
}
.dlg::backdrop { background: rgba(0,0,0,.55); }
.dlg h3 { margin: 0 0 14px; font-size: 15px; }
.dlg h4 { margin: 18px 0 8px; font-size: 12px; color: var(--ink-dim); font-weight: 600; }
.dlg label { display: block; font-size: 12px; color: var(--ink-dim); margin-bottom: 12px; }
.dlg input, .dlg select {
  width: 100%; margin-top: 4px; padding: 8px 10px;
  background-color: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; font: inherit; font-size: 13px;
}
.dlg select { height: 36px; padding: 0 32px 0 10px; }
#invlink { font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; margin-bottom: 8px; }
.dlgactions { display: flex; gap: 8px; }
.inviterow {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  padding: 6px 0; border-top: 1px solid var(--line); font-size: 12.5px;
}
/* ---------- multi-select ---------- */
.card { position: relative; }
.pick {
  position: absolute; top: 8px; left: 8px; z-index: 2;
  width: 22px; height: 22px; display: grid; place-items: center;
  background: light-dark(rgba(255,255,255,.9), rgba(20,20,26,.85));
  border: 1px solid var(--line); border-radius: 6px;
  opacity: 0; transition: opacity .12s;
}
/* Visible on hover, and pinned visible for everything once a selection exists —
   otherwise the checkboxes vanish exactly when you are using them. */
.card:hover .pick, body.selecting .pick, .card.picked .pick { opacity: 1; }
.pick input { margin: 0; cursor: pointer; accent-color: var(--accent); }
.card.picked { outline: 2px solid var(--accent); outline-offset: -2px; }

.selbar {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 18px; z-index: 58;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  max-width: min(860px, calc(100vw - 36px));
  padding: 10px 16px; background: var(--panel);
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,.3);
}
.selbar[hidden] { display: none; }
.selbar strong { font-size: 13px; white-space: nowrap; }
.selactions { display: flex; gap: 8px; flex-wrap: wrap; }
.selbar .btn, .selbar .ghost { padding: 6px 12px; font-size: 12.5px; }
#selnote { flex-basis: 100%; margin: 0; }

.tagcommon { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.tagchip {
  padding: 3px 9px; font: inherit; font-size: 11.5px; cursor: pointer;
  background: var(--panel-2); color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 999px;
}
.tagchip:hover { color: var(--ink); border-color: var(--accent); }

/* ---------- drag and drop ---------- */
.dropveil {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center;
  background: light-dark(rgba(246,245,242,.86), rgba(20,20,26,.86));
  backdrop-filter: blur(2px);
  /* The veil must never eat the drop event it exists to advertise. */
  pointer-events: none;
}
/* A class setting `display` outranks the UA rule for [hidden], so without this
   the veil stays up forever after the first drag — a curtain over the whole
   app that no amount of setting .hidden will lift. */
.dropveil[hidden], .uploads[hidden] { display: none; }
.dropveil-inner {
  display: grid; gap: 6px; justify-items: center; text-align: center;
  padding: 32px 44px; border-radius: 16px;
  border: 2px dashed var(--accent); background: var(--panel);
}
.dropveil-inner strong { font-size: 17px; }
.dropveil-inner span { font-size: 13px; color: var(--ink-dim); }

.uploads {
  position: fixed; right: 18px; bottom: 18px; z-index: 55; width: min(380px, calc(100vw - 36px));
  max-height: min(52vh, 520px); overflow: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,.28); padding: 14px 16px;
}
.uploads-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.uploads-head strong { font-size: 13.5px; }
.uprow {
  display: grid; grid-template-columns: 1fr auto; gap: 3px 10px;
  padding: 7px 0; border-top: 1px solid var(--line); font-size: 12.5px;
}
.upname { overflow-wrap: anywhere; }
.upsize { color: var(--ink-dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
.upbar {
  grid-column: 1 / -1; height: 3px; border-radius: 2px;
  background: var(--panel-2); overflow: hidden;
}
.upbar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width .18s; }
.uprow.ok .upbar i  { background: var(--ok); }
.uprow.ok .upsize   { color: var(--ok); }
.uprow.bad .upbar i { background: var(--accent); width: 100% !important; }
.uprow.bad .upsize  { color: var(--accent); }

/* ---------- MCP access dialog ---------- */
.nomargin { margin-top: 0; }
/* Amber, not red: this is a "you only get one look" caution, not a failure. */
.warn-note {
  margin: 0 0 14px; padding: 10px 12px; font-size: 12.5px; line-height: 1.5;
  color: var(--ink); background: light-dark(#fdf3dc, #33290f);
  border: 1px solid var(--warn); border-radius: 8px;
}
.advanced { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 10px; }
.advanced summary {
  font-size: 12.5px; color: var(--ink-dim); cursor: pointer; margin-bottom: 8px;
}
.advanced summary:hover { color: var(--ink); }
#mcpurl, #mcpurl2, #mcpauth {
  font: 12px ui-monospace, SFMono-Regular, Menlo, monospace;
  overflow-wrap: anywhere;
}

/* ---------- upload status ---------- */
.chip {
  padding: 5px 10px; border-radius: 999px; font: inherit; font-size: 12px;
  background: var(--panel-2); color: var(--ink-dim);
  border: 1px solid var(--line); cursor: pointer; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.chip:hover { color: var(--ink); }
/* Amber, not red: a queue nobody is draining needs attention, not alarm. */
.chip.warn { color: var(--warn); border-color: var(--warn); }
.inforow {
  display: flex; align-items: baseline; gap: 12px; justify-content: space-between;
  padding: 7px 0; border-top: 1px solid var(--line); font-size: 12.5px;
}
.inforow span:first-child { color: var(--ink-dim); }
.inforow span:last-child { font-variant-numeric: tabular-nums; text-align: right; }
.failrow {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  padding: 8px 0; border-top: 1px solid var(--line); font-size: 12px;
}
.failkey { font-weight: 560; overflow-wrap: anywhere; }
.failwhen { color: var(--ink-dim); white-space: nowrap; }
.failerr {
  grid-column: 1 / -1; color: var(--accent);
  font: 11.5px ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere;
}

.state { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; font-weight: 700; }
.state.waiting { color: var(--warn); }
.state.used    { color: var(--ok); }
.state.expired { color: var(--ink-dim); }

/* ---------- sign-in page ---------- */
body.centred { display: grid; place-items: center; min-height: 100vh; }
.auth { width: min(430px, 90vw); text-align: center; padding: 30px; }
.brand.big { justify-content: center; margin-bottom: 22px; }
.brand.big .mark { width: 26px; height: 26px; }
.brand.big h1 { font-size: 19px; }
.lede { color: var(--ink-dim); font-size: 14.5px; line-height: 1.6; margin: 0 0 20px; }
.btn.wide { width: 100%; padding: 12px; font-size: 14px; }
.note { color: var(--ink-dim); font-size: 12.5px; margin: 14px 0 0; }
.err { color: var(--accent); font-size: 13px; margin: 14px 0 0; }

@media (max-width: 720px) {
  .bar { flex-wrap: wrap; height: auto; padding: 10px 14px; gap: 10px; }
  .searchwrap { order: 3; width: 100%; flex-basis: 100%; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); padding: 14px; }
}

/* ============================================================
   Restructured chrome: property tabs, header tools, card chips,
   endless scroll. Everything below replaces the old .modes/.who row.
   ============================================================ */

:root { --inspector-w: 380px; }

/* ---------- header tools ---------- */
.brand {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: inherit; font: inherit;
}
.brand:hover h1 { color: var(--accent); }

.headtools { display: flex; align-items: center; gap: 6px; flex: none; }

.iconbtn {
  display: inline-flex; align-items: center; gap: 5px;
  height: 32px; padding: 0 10px;
  background: transparent; color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: 13px; cursor: pointer;
}
.iconbtn:hover { color: var(--ink); border-color: var(--ink-dim); }
.iconbtn .ico { font-size: 14px; line-height: 1; }
.iconbtn.named { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iconbtn.warnish { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.iconbtn[hidden] { display: none; }

/* The sync button turns while the back end is working, which is the whole
   point of it: the state of the queue is otherwise invisible. */
@keyframes spin { to { transform: rotate(360deg); } }
#syncbtn.spinning .ico { display: inline-block; animation: spin 1.1s linear infinite; }

.menuwrap { position: relative; }
.menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  min-width: 210px; padding: 5px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 12px 34px rgba(0,0,0,.32);
}
.menu[hidden] { display: none; }
.menuname { padding: 7px 10px 5px; font-size: 12px; color: var(--ink-dim); }
.menuitem {
  display: block; width: 100%; text-align: left; padding: 7px 10px;
  background: none; border: 0; border-radius: 6px;
  color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
}
.menuitem:hover { background: var(--panel-2); }
.menuitem[hidden] { display: none; }
.menu hr { border: 0; border-top: 1px solid var(--line); margin: 5px 2px; }

/* ---------- property tabs ---------- */
.tabs {
  position: sticky; top: var(--bar-h); z-index: 19;
  display: flex; gap: 4px; align-items: center;
  padding: 8px 20px; overflow-x: auto; scrollbar-width: thin;
  background: var(--bg); border-bottom: 1px solid var(--line);
}
.tabs[hidden] { display: none; }
.tab {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 6px 12px; border: 1px solid transparent; border-radius: 999px;
  background: transparent; color: var(--ink-dim);
  font: inherit; font-size: 13px; cursor: pointer; white-space: nowrap;
}
.tab:hover { background: var(--panel-2); color: var(--ink); }
.tab.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 560; }
.tab.on .tab-n { background: rgba(255,255,255,.26); color: #fff; }
.tab-n {
  min-width: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--panel-2); color: var(--ink-dim);
  font-size: 11px; font-variant-numeric: tabular-nums; text-align: center;
}
/* A show nobody has filed anything under yet is still worth seeing — that is
   how you find out it exists. Dimmed, not hidden. */
.tab.empty { opacity: .45; }
.tab.muted .tab-label { font-style: italic; }

.filters[hidden] { display: none; }

/* ---------- card chips ---------- */
.chips {
  position: absolute; right: 7px; top: 7px;
  display: flex; gap: 4px; pointer-events: none;
}
.chip-type, .chip-size {
  padding: 2px 6px; border-radius: 5px;
  font-size: 10px; font-weight: 700; letter-spacing: .03em;
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  color: var(--ink-dim); backdrop-filter: blur(6px);
}
.chip-type { color: var(--ink); }
.chip-size { font-weight: 600; font-variant-numeric: tabular-nums; }

/* ---------- endless scroll + live arrivals ---------- */
.gridmore { display: flex; justify-content: center; padding: 8px 0 48px; }
.gridmore[hidden] { display: none; }
.spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--accent);
  opacity: 0; transition: opacity .2s ease;
}
.gridmore.busy .spinner { opacity: 1; animation: spin .8s linear infinite; }

/* Never injected into a filtered grid — the server owns which rows match, so
   this offers the count and re-runs the real query when clicked. */
.newpill {
  /* Sticky to the top of the results column, which is now its own scroller —
     so this no longer has to add up the heights of the bars above it. */
  position: sticky; top: 10px; z-index: 18;
  display: block; margin: 10px auto 0; padding: 7px 16px;
  background: var(--accent); color: #fff; border: 0; border-radius: 999px;
  font: inherit; font-size: 12.5px; font-weight: 560; cursor: pointer;
  box-shadow: 0 6px 18px rgba(0,0,0,.28);
}
.newpill[hidden] { display: none; }

/* ============================================================
   Chip filters, the project bar's add button, and folders.
   ============================================================ */

/* ---------- chip filter groups ----------
   Replacing two <select>s. A dropdown shows one value and hides the vocabulary,
   which made "narrow to images and video" a feature only someone who already
   knew about it would ever find. */
.chipgroup { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.chipgroup-label {
  font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-dim); margin-right: 2px;
}
.chip-toggle {
  height: var(--control-h); padding: 0 14px;
  background: var(--panel); color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 999px;
  font: inherit; font-size: 13.5px; cursor: pointer; white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s;
}
.chip-toggle:hover { color: var(--ink); border-color: var(--ink-dim); }
.chip-toggle.on {
  background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 560;
}
/* "All" is the resting state, not a choice you made — it reads as quieter. */
.chipgroup .chip-toggle:first-of-type.on {
  background: var(--panel-2); border-color: var(--ink-dim); color: var(--ink);
}
.chip-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- project bar: scroller + pinned add ---------- */
.tabs { gap: 10px; }
.tabscroll {
  display: flex; gap: 4px; align-items: center; min-width: 0; flex: 1;
  overflow-x: auto; scrollbar-width: thin; padding-bottom: 1px;
}
.tabadd {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  height: 30px; padding: 0 13px;
  background: transparent; color: var(--ink-dim);
  border: 1px dashed var(--line); border-radius: 999px;
  font: inherit; font-size: 13px; cursor: pointer; white-space: nowrap;
}
.tabadd:hover { color: var(--accent); border-color: var(--accent); border-style: solid; }
.tabadd span { font-size: 15px; line-height: 1; }

/* ---------- header icon buttons ---------- */
.iconbtn .ico { display: inline-flex; }
.iconbtn.big { height: 36px; width: 36px; padding: 0; justify-content: center; }
/* Still well up from the 14px it started at. The sync control is the only thing
   in the bar that says whether the archive is busy, so it has to be legible at
   a glance and its spin has to read as motion — but at 26px it was crowding the
   account button beside it. */
.iconbtn.big .ico { width: 22px; height: 22px; }
#syncbtn.spinning .ico { animation: spin 1.1s linear infinite; }

/* ---------- folder sidebar ---------- */
.workspace { grid-template-columns: var(--sidebar-w) 1fr var(--inspector-w); }

.sidebar {
  display: flex; flex-direction: column; gap: 8px;
  padding: 16px 12px; overflow-y: auto;
  background: var(--panel); border-right: 1px solid var(--line);
}
.sidebar[hidden] { display: none; }
.folderlist { display: flex; flex-direction: column; gap: 2px; }

.frow {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 9px 10px; border: 1px solid transparent; border-radius: 9px;
  background: transparent; color: var(--ink-dim);
  font: inherit; font-size: 13.5px; text-align: left; cursor: pointer;
}
.frow:hover { background: var(--panel-2); color: var(--ink); }
.frow.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 560; }
.frow.all { margin-bottom: 6px; }
.fico { flex: none; width: 18px; height: 18px; opacity: .75; }
.frow.on .fico { opacity: 1; }
.fname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fn {
  flex: none; min-width: 20px; padding: 0 6px; border-radius: 9px;
  background: var(--panel-2); color: var(--ink-dim);
  font-size: 11px; font-variant-numeric: tabular-nums; text-align: center;
}
.frow.on .fn { background: rgba(255,255,255,.26); color: #fff; }
.fempty { margin: 6px 4px 2px; font-size: 12px; line-height: 1.5; color: var(--ink-dim); }

.newfolder {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 10px; border: 1px dashed var(--line); border-radius: 9px;
  background: transparent; color: var(--ink-dim);
  font: inherit; font-size: 13.5px; cursor: pointer;
}
.newfolder:hover { color: var(--accent); border-color: var(--accent); }
.newfolder span { font-size: 16px; line-height: 1; }

.sidenote {
  margin: auto 4px 0; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 11.5px; line-height: 1.5; color: var(--ink-dim);
}

/* ---------- dragging assets into folders ---------- */
.droptarget {
  background: color-mix(in srgb, var(--accent) 18%, transparent) !important;
  border-color: var(--accent) !important; color: var(--ink) !important;
}
/* While a drag is in flight every target is outlined, so the answer to "can I
   drop this here?" is on screen before the pointer arrives. */
body.dragging-assets .frow:not(.all), body.dragging-assets .newfolder {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.dragghost {
  position: fixed; top: -1000px; left: -1000px;
  padding: 7px 12px; border-radius: 8px;
  background: var(--accent); color: #fff; font: 600 12.5px/1 ui-sans-serif, system-ui, sans-serif;
}

/* ---------- the bar shown inside a folder ---------- */
.folderbar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 14px 20px; border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}
.folderbar[hidden] { display: none; }
.folderbar-who { display: flex; flex-direction: column; gap: 1px; margin-right: auto; min-width: 0; }
.folderbar-who strong { font-size: 15px; }
.folderbar-who .note { margin: 0; }
.folderbar-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.folderbar .btn, .folderbar .ghost { height: 34px; padding: 0 14px; font-size: 13px; }

/* ---------- folder membership in the inspector ---------- */
.infolders { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 12px; }
.infolders-label { font-size: 12px; color: var(--ink-dim); }
.tag.link { border: 1px solid var(--line); cursor: pointer; font: inherit; font-size: 11.5px; color: var(--ink); }
.tag.link:hover { border-color: var(--accent); color: var(--accent); }

/* Where a cutout came from, and what has been cut out of this. Same visual
   weight as the folder list above: both answer "what else is this connected
   to", and neither is more important than the picture. */
.lineage { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 12px; }
.lineage-made { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; width: 100%; }
.lineage-label { font-size: 12px; color: var(--ink-dim); }
.lineage-op { font-size: 11.5px; color: var(--ink-dim); }
.lineage-failed { font-size: 11.5px; color: var(--warn); }

/* ---------- the add-files picker ---------- */
/* Scoped to [open] on purpose. A bare `display: flex` here outranks the user
   agent's `dialog:not([open]) { display: none }`, and the picker then sits
   permanently on top of the grid — the same trap the drop veil fell into. */
.dlg.wide { width: min(980px, 94vw); max-height: 88vh; }
.dlg.wide[open] { display: flex; flex-direction: column; gap: 12px; }
.pickfilters { display: flex; gap: 10px; flex-wrap: wrap; }
.pickfilters #pickq {
  flex: 1; min-width: 220px; height: var(--control-h); padding: 0 14px;
  background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 9px; font: inherit; font-size: 14px;
}
.pickfilters #pickq:focus { outline: none; border-color: var(--accent); }
/* Undoes .dlg select's full-width rule — in here it sits beside the search box. */
.pickfilters select { flex: none; width: auto; min-width: 180px; height: var(--control-h); }
.pickgrid {
  flex: 1; min-height: 200px; overflow-y: auto;
  display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
  padding: 4px 2px;
}
.ptile {
  display: flex; flex-direction: column; gap: 5px; padding: 0;
  background: none; border: 0; cursor: pointer; color: var(--ink); font: inherit; text-align: left;
}
.pshot {
  position: relative; aspect-ratio: 1; border-radius: 8px; overflow: hidden;
  background: var(--panel-2); border: 2px solid transparent;
  display: flex; align-items: center; justify-content: center;
}
.pshot img { width: 100%; height: 100%; object-fit: contain; }
.ptile.on .pshot { border-color: var(--accent); }
/* A tick, so "chosen" survives being looked at on a dark thumbnail. */
.ptile.on .pshot::after {
  content: '✓'; position: absolute; top: 5px; left: 5px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); color: #fff;
  font-size: 12px; font-weight: 700; display: grid; place-items: center;
}
.ptype {
  position: absolute; right: 5px; bottom: 5px; padding: 1px 5px; border-radius: 4px;
  font-size: 9.5px; font-weight: 700;
  background: color-mix(in srgb, var(--panel) 84%, transparent);
  color: var(--ink-dim); backdrop-filter: blur(6px);
}
.pname {
  font-size: 11px; line-height: 1.3; color: var(--ink-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pickmore { align-self: center; }
.dlgactions.sticky { border-top: 1px solid var(--line); padding-top: 12px; }

/* ---------- the "nothing was lost" line ---------- */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 18px; z-index: 70;
  max-width: min(640px, calc(100vw - 36px)); padding: 11px 18px;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--ok); border-radius: 11px;
  box-shadow: 0 10px 30px rgba(0,0,0,.3);
  font-size: 13px; line-height: 1.45; text-align: center;
}
.toast[hidden] { display: none; }
/* The selection bar sits here too; the toast wins and the bar steps up. */
body.selecting .toast { bottom: 78px; }

/* A menu that opens upward, for the selection bar pinned to the bottom. */
.menu.up { top: auto; bottom: calc(100% + 6px); max-height: 320px; overflow-y: auto; }

/* ---------- icon-only type chips ----------
   Five glyphs read faster than five words once learned and cost a fifth of the
   width, which is what let status go back to being a dropdown beside them. The
   label survives as the tooltip and the accessible name — an icon-only control
   that says nothing to a screen reader is a control that does not exist. */
.chip-toggle.iconic {
  width: var(--control-h); padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
}
.chip-toggle.iconic svg { width: 20px; height: 20px; }

/* ---------- pinned projects ---------- */
.tab-pin { width: 12px; height: 12px; flex: none; opacity: .75; }
.tab.on .tab-pin { opacity: 1; }

/* ---------- the inspector with several things selected ---------- */
.bulkstrip { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.bulkthumb {
  width: 54px; height: 54px; border-radius: 7px; overflow: hidden;
  background: var(--panel-2); display: grid; place-items: center;
}
.bulkthumb img { width: 100%; height: 100%; object-fit: cover; }
.bulkmore {
  width: 54px; height: 54px; border-radius: 7px;
  background: var(--panel-2); color: var(--ink-dim);
  display: grid; place-items: center; font-size: 12.5px; font-weight: 600;
}
.edit.bulk { border-top: 0; padding-top: 0; }
.edit.bulk .note { margin: -4px 0 12px; }
/* The selection bar floats over the bottom of the screen, and the bulk form's
   Apply button is the last thing in a panel that reaches it. Give the panel
   room to scroll past. */
body.selecting .inspector { padding-bottom: 96px; }

/* ---------- "are these the same thing?" ----------
   Sits above the grid rather than in a dialog: it is an offer, not a
   question that has to be answered before anything else can happen. */
.suggestbar {
  margin: 14px 20px 0; padding: 14px 16px;
  background: var(--panel); border: 1px solid var(--ok); border-radius: 12px;
}
.suggest-top {
  display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap;
  margin-bottom: 12px;
}
.suggest-top > div:first-child { flex: 1; min-width: 240px; }
.suggest-top strong { font-size: 14px; }
.suggest-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.suggest-actions .btn, .suggest-actions .ghost { height: 34px; padding: 0 14px; font-size: 13px; }

.suggest-list {
  display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  max-height: 260px; overflow-y: auto;
}
.stile {
  display: flex; flex-direction: column; gap: 3px; padding: 0;
  background: none; border: 0; color: var(--ink); font: inherit;
  text-align: left; cursor: pointer; opacity: .45;
}
.stile.on { opacity: 1; }
.sshot {
  position: relative; aspect-ratio: 1; border-radius: 8px; overflow: hidden;
  background: var(--panel-2); border: 2px solid transparent;
  display: grid; place-items: center;
}
.sshot img { width: 100%; height: 100%; object-fit: contain; }
.stile.on .sshot { border-color: var(--ok); }
.stile.on .sshot::after {
  content: '✓'; position: absolute; top: 4px; left: 4px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--ok); color: #08120c;
  font-size: 11px; font-weight: 700; display: grid; place-items: center;
}
.sname {
  font-size: 10.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The reason it was suggested, on the tile. A suggestion you cannot check is
   just an instruction. */
.swhy { font-size: 9.5px; color: var(--ink-dim); line-height: 1.25; }

/* While checking, the folder sidebar is gone and the grid takes its column. */
body.reviewing .workspace { grid-template-columns: 1fr var(--inspector-w); }

/* ---------- narrow screens ----------
   Below this the inspector cannot be a column without squeezing the grid to
   nothing, so it goes back to being an overlay — with a close button, which is
   why that button exists at all. */
@media (max-width: 1180px) {
  :root { --sidebar-w: 200px; }
}

@media (max-width: 900px) {
  /* One column, with the folder strip on its own row above a results column
     that still does the scrolling. */
  .workspace { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  /* The sidebar becomes a strip above the grid rather than disappearing:
     folders are the one structure this person made himself, so they do not get
     hidden behind a hamburger. */
  .sidebar {
    position: static; height: auto; flex-direction: row; align-items: center;
    gap: 8px; padding: 10px 14px; overflow-x: auto;
    border-right: 0; border-bottom: 1px solid var(--line);
  }
  .folderlist { flex-direction: row; gap: 6px; }
  .frow { width: auto; white-space: nowrap; }
  .newfolder { width: auto; white-space: nowrap; }
  .sidenote { display: none; }
  .inspector {
    position: fixed; top: 0; right: 0; bottom: 0; width: min(420px, 100vw);
    height: 100vh; z-index: 41; transform: translateX(100%);
    transition: transform .18s ease;
  }
  body.inspecting .inspector { transform: none; }
  body.inspecting .inspector-close {
    display: block; position: fixed; top: 10px; right: 10px; z-index: 42;
    width: 30px; height: 30px; border-radius: 50%;
    background: var(--panel); color: var(--ink);
    border: 1px solid var(--line); cursor: pointer; font-size: 14px;
  }
  .inspector-empty { display: none; }
}

/* ---------- a folder that somebody outside the studio can see ---------- */

/* Small, quiet, and always present rather than only on hover. The one fact
   about a folder that has consequences beyond this screen should not require
   a gesture to discover — but it also must not crowd out the folder's name,
   which is why it is a 14px mark and not the word "shared". */
.fshared { flex: none; width: 14px; height: 14px; opacity: 1; color: var(--warn); }
.frow.on .fshared { color: #fff; }
.folderbar .ghost.on { color: var(--warn); border-color: var(--warn); }

/* The Share dialog. Wider than the others because a URL that wraps is a URL
   somebody copies half of. */
.sharemake { border-top: 1px solid var(--line); margin-top: 16px; padding-top: 16px; }
.sharetoggle {
  display: flex !important; align-items: center; gap: 8px;
  font-size: 13px; color: var(--ink); margin-bottom: 8px; cursor: pointer;
}
.sharetoggle input { width: auto !important; margin: 0 !important; cursor: pointer; }

#shareout {
  margin-top: 16px; padding: 14px; border-radius: 10px;
  background: color-mix(in srgb, var(--ok) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--ok) 35%, transparent);
}
.sharerow-link { display: flex; gap: 8px; align-items: center; margin-top: 10px; }
.sharerow-link input {
  flex: 1; min-width: 0; margin: 0 !important;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px;
}
.sharerow-link .btn { flex: none; }

.sharelist { margin-top: 6px; }
.sharelist-title { margin: 20px 0 8px; font-size: 12px; color: var(--ink-dim); font-weight: 600; }
.sharerow {
  border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 14px; margin-bottom: 10px;
}
/* A stopped link stays listed rather than disappearing: "did I actually revoke
   Manolo's link?" is a question worth being able to answer later. */
.sharerow.dead { opacity: .55; }
.sharerow-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.sharerow-head .note { font-size: 11.5px; }
.sharerow-perms { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 10px; }
.sharerow-perms .sharetoggle { margin: 0; font-size: 12.5px; }
.sharerow-perms .danger { margin-left: auto; background: transparent; color: var(--accent); }
.btn.sec.tiny { padding: 4px 10px; font-size: 11.5px; }

/* ---------- the guest page (/s/<token>) ---------- */
/* Deliberately a different shape from the archive browser: no sidebar, no tabs,
   no filters. Somebody who has this link should not be able to tell how much
   more there is, and should not have to learn an interface to take one file. */

.sharepage .bar { gap: 16px; }
.sharewho { display: flex; flex-direction: column; gap: 1px; margin-right: auto; min-width: 0; }
.sharewho strong { font-size: 15px; }
.sharewho .note { margin: 0; font-size: 12px; }

.sharemain { padding: 22px 20px 60px; max-width: 1400px; margin: 0 auto; }
.sharegate { padding: 40px 0; text-align: center; }
.sharegate h2 { font-size: 17px; margin: 0 0 8px; }
.sharenote { margin: 24px 0; }

.sharemsg {
  margin: 0 0 18px; padding: 12px 14px; border-radius: 10px;
  background: var(--panel-2); font-size: 13.5px;
}
.sharemsg.ok  { background: color-mix(in srgb, var(--ok) 14%, transparent); color: var(--ink); }
.sharemsg.bad { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--ink); }

.sharegrid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}
.sharecard {
  margin: 0; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: hidden;
  display: flex; flex-direction: column;
}
.sharecard img {
  width: 100%; aspect-ratio: 1; object-fit: contain; background: var(--panel-2); display: block;
}
/* Transparent artwork on a flat panel reads as a white background, which is a
   lie about the file somebody is about to download. */
.sharecard.alpha img {
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #d9d9de 25%, transparent 25%, transparent 75%, #d9d9de 75%),
    linear-gradient(45deg, #d9d9de 25%, transparent 25%, transparent 75%, #d9d9de 75%);
  background-size: 16px 16px; background-position: 0 0, 8px 8px;
}
.sharenothumb {
  aspect-ratio: 1; display: grid; place-items: center;
  background: var(--panel-2); color: var(--ink-dim);
  font: 600 15px/1 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .06em;
}
.sharecard figcaption {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 10px 12px 12px;
}
.sharename { font-size: 12.5px; font-weight: 560; overflow-wrap: anywhere; }
.sharemeta { font-size: 11.5px; color: var(--ink-dim); }
.sharecard .btn { font-size: 12px; padding: 5px 12px; }

.sharedrop {
  margin-top: 32px; padding: 20px; border-radius: var(--radius);
  border: 1.5px dashed var(--line); background: var(--panel);
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
}
.sharedrop strong { font-size: 14px; }
.sharedrop .note { font-size: 12.5px; }

.shareuploads {
  margin-top: 20px; padding: 14px; border-radius: var(--radius);
  background: var(--panel); border: 1px solid var(--line);
}

@media (max-width: 720px) {
  /* On a phone the header actions matter more than the branding — this page is
     opened on phones far more often than the archive itself is. */
  .sharepage .bar { height: auto; padding: 10px 14px; flex-wrap: wrap; }
  .sharepage .brand h1 { display: none; }
  .sharegrid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
}

/* ---------- the phone's way in ----------
   A drop target is not an affordance a finger has. Everything above assumes a
   mouse and a window full of files to drag out of it; on a phone there is
   neither, and the only route into the archive was an "Add files…" item two
   taps deep in a menu behind somebody's name.

   Gated on the pointer rather than the width, because that is the actual
   condition: a browser window dragged narrow still has a mouse, the whole
   window is still a drop target, and it does not need a camera button. */
.addhere { display: none; }
.sharedrop-actions { display: flex; flex-wrap: wrap; gap: 8px; }

@media (pointer: coarse) {
  .addhere {
    display: block; position: fixed; z-index: 56;
    right: 18px; bottom: calc(18px + env(safe-area-inset-bottom));
  }
  /* 58px because it is a thumb target, not a toolbar icon: below about 48 the
     miss rate on a phone held one-handed stops being theoretical. */
  .addfab {
    display: grid; place-items: center; width: 58px; height: 58px;
    border: 0; border-radius: 50%; cursor: pointer;
    background: var(--accent); color: #fff;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .34);
    transition: transform .12s ease;
    /* Otherwise a tap paints a grey *square* over the round button — the one
       control on this page a finger is guaranteed to land on. */
    -webkit-tap-highlight-color: transparent;
  }
  .addfab:active { transform: scale(.94); }
  .addfab svg { width: 26px; height: 26px; }

  /* Wider and taller than the account menu, which is a mouse's menu. Three
     choices under a thumb, each on one line — a label that wraps reads as two
     choices rather than one. */
  .addmenu { min-width: min(268px, calc(100vw - 36px)); }
  .addmenu .menuitem { padding: 11px 12px; font-size: 14px; }
  .addmenu .menuname { font-size: 12.5px; }

  /* The other two things that live in this corner move up out of its way. Both
     arrive unannounced — the tray when an upload starts, the bar when something
     is selected — so neither can be allowed to land on top of the one control
     that is supposed to always be there. */
  .uploads, .selbar { bottom: calc(94px + env(safe-area-inset-bottom)); }
  /* And the last row of pictures stays reachable underneath it. */
  .grid { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
}
