/* Index - one shared shopping list. Calm, adult, clinical-but-warm.
   Neutral skeleton shared with the appnest family; the clay accent is Index's own.
   Index is a STANDALONE tool - it links only to Divido, its sibling in spirit. */

:root {
  --bg: #f6f7f9;
  --surface: #ffffff;
  --ink: #1c2430;
  --ink-soft: #5b6674;
  --ink-faint: #8d97a5;
  --accent: #a4553a;        /* warm clay - Index's identity */
  --accent-ink: #ffffff;
  --accent-soft: #f7e7e0;
  --line: #e3e7ec;
  --input-bg: #fbfcfd;
  --input-focus-bg: #ffffff;
  --btn-primary-hover: #8a4530;
  --chip-hover: #efd8cd;
  --summary-bg: #f3f5f7;
  /* semantic colours - kept separate from the accent so "in the basket" reads
     as done rather than as another accent-coloured thing to look at */
  --good: #2f7d4f;
  --good-soft: #e6f2ec;
  --danger: #b3423a;
  --danger-soft: #fdecea;
  --del-hover-bg: #fdf1f0;
  --radius: 12px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .05), 0 4px 16px rgba(16, 24, 40, .06);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color-scheme: light dark;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* Read by screen readers, invisible on screen. Absolutely positioned so it
   cannot add a flex/grid gap where it sits. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
}
.tnum { font-variant-numeric: tabular-nums; }

/* ---------------- top bar ---------------- */

.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: 880px;
  margin: 0 auto;
  padding: 18px 20px 10px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--accent);
  text-decoration: none;
  letter-spacing: -.01em;
}
.tagline { color: var(--ink-faint); font-size: .85rem; }
.topbar-controls { margin-left: auto; display: flex; gap: 8px; }

.unit-toggle { display: inline-flex; border: 1px solid var(--line); border-radius: 7px; overflow: hidden; }
.unit-toggle button {
  border: none;
  background: var(--surface);
  color: var(--ink-faint);
  font: inherit;
  font-size: .72rem;
  font-weight: 700;
  line-height: 1;
  padding: 6px 9px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
}
.unit-toggle button.on { background: var(--accent); color: var(--accent-ink); }
.unit-toggle button svg { display: block; }

main { max-width: 880px; margin: 0 auto; padding: 0 20px 48px; }

/* ---------------- buttons ---------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 9px 16px;
  font: inherit;
  font-weight: 600;
  font-size: .92rem;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s, border-color .15s, transform .05s;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--btn-primary-hover); }
.btn-ghost { background: var(--surface); border-color: var(--line); color: var(--ink-soft); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-lg { padding: 13px 26px; font-size: 1.05rem; }
.btn-sm { padding: 6px 11px; font-size: .82rem; border-radius: 8px; }
.btn-danger { color: var(--danger); border-color: var(--line); background: var(--surface); }
.btn-danger:hover { background: var(--del-hover-bg); border-color: var(--danger); }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* ---------------- cards ---------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 22px;
  margin-top: 16px;
}
.card h2 { margin: 0 0 14px; font-size: 1.05rem; letter-spacing: -.01em; }

/* ---------------- landing ---------------- */

.hero { text-align: center; padding: 52px 0 28px; }
.hero h1 { font-size: clamp(1.6rem, 4vw, 2.4rem); letter-spacing: -.02em; line-height: 1.2; margin: 0 0 16px; text-wrap: balance; }
.lede { max-width: 560px; margin: 0 auto 8px; color: var(--ink-soft); font-size: 1.05rem; }

/* Layout lives here rather than in style attributes: the strict CSP (no
   'unsafe-inline') refuses the style ATTRIBUTE, so anything set that way in the
   markup silently never applies. */
.create h2 { margin-top: 0; }
.field-label { font-size: .8rem; font-weight: 600; color: var(--ink-soft); display: block; margin-bottom: 5px; }
/* the name takes the full width, then the button sits centred under it with
   room to breathe - it is the one thing to press on this page */
.create-input { width: 100%; }
.create-actions { display: flex; justify-content: center; margin-top: 20px; }
.create-note { margin: 16px 0 0; text-align: center; }

.recent { margin-top: 22px; font-size: .9rem; color: var(--ink-soft); }
.recent h2 { font-size: .95rem; }
.recent ul { list-style: none; margin: 8px 0 0; padding: 0; }
.recent li { padding: 6px 0; border-top: 1px solid var(--line); display: flex; gap: 10px; align-items: center; }
.recent li:first-child { border-top: none; }
.recent a { color: var(--accent); font-weight: 600; text-decoration: none; }
.recent a:hover { text-decoration: underline; }
.recent .when { color: var(--ink-faint); font-size: .8rem; margin-left: auto; }

/* the quiet pill that points at the sibling tool */
.more-tools {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin: 30px 0 6px;
  font-size: .88rem;
}
.more-label { color: var(--ink-faint); margin-bottom: 2px; }
.more-tool {
  min-width: 260px;
  justify-content: center;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 14px;
  color: var(--ink-soft);
  font-weight: 600;
  text-decoration: none;
  transition: border-color .15s, color .15s;
}
.more-tool:hover { border-color: var(--accent); color: var(--accent); }

/* ---------------- list header ---------------- */

.list-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-top: 22px; }
.list-name { font-size: 1.45rem; font-weight: 700; letter-spacing: -.02em; }
.list-sub { color: var(--ink-faint); font-size: .9rem; }
.list-actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------------- inputs ---------------- */

select, input[type=text] {
  font: inherit;
  background: var(--input-bg);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 9px;
  padding: 9px 10px;
}
select:focus, input:focus { outline: none; border-color: var(--accent); background: var(--input-focus-bg); }

/* ---------------- focus & touch ----------------
   Mobile browsers paint a blue rectangle over a tapped control
   (-webkit-tap-highlight-color) and desktop browsers leave their own ring after
   a click. Both are suppressed; keyboard users still get a clear clay ring
   because :focus-visible only matches keyboard/AT focus. */
html { -webkit-tap-highlight-color: transparent; }
button, .btn, a, select, input, [tabindex] { -webkit-tap-highlight-color: transparent; }
:focus:not(:focus-visible) { outline: none; }
button:focus-visible, .btn:focus-visible, a:focus-visible,
select:focus-visible, input:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
dialog:focus, dialog:focus-visible { outline: none; }

/* ---------------- quick add ----------------
   One row, always at the top of the list: type, Enter, type the next thing.
   The name field keeps the focus after a save so ten items go in without ever
   reaching for the mouse. */
.add-card { padding: 16px 18px; }
.add-row { display: flex; gap: 8px; align-items: center; }
.add-row #addName { flex: 1 1 auto; min-width: 0; }
.qty-input { width: 92px; flex: none; }
.add-row select { flex: none; max-width: 42%; }
.shop-input { flex: 0 1 130px; min-width: 0; }

/* ---------------- suggestions ---------------- */

.suggest-card { padding: 16px 18px; }
.suggest-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.suggest-head h2 { margin: 0; font-size: .95rem; }
.suggest-head .btn { margin-left: auto; }
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  border-radius: 999px;
  padding: 6px 12px;
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  cursor: pointer;
}
.chip:hover { border-color: var(--accent); color: var(--accent); background: var(--chip-hover); }
.chip .chip-qty { color: var(--ink-faint); font-weight: 600; margin-left: 5px; }

/* a suggestion is two controls in one pill: tap the name to add it, tap the ×
   to say "stop offering me this" - so they are two buttons sharing a border */
.chip-pair { display: inline-flex; align-items: stretch; border: 1px solid var(--line); border-radius: 999px; overflow: hidden; background: var(--surface); }
.chip-pair .chip { border: none; border-radius: 0; background: none; padding-right: 7px; }
.chip-pair:hover { border-color: var(--accent); }
.chip-x {
  border: none;
  background: none;
  color: var(--ink-faint);
  font: inherit;
  font-size: .95rem;
  line-height: 1;
  padding: 0 10px 0 4px;
  cursor: pointer;
}
.chip-x:hover { color: var(--danger); background: var(--del-hover-bg); }

/* which shop am I standing in? Only shown once a shop is actually in use. */
.shop-filter { margin-bottom: 14px; }
.chip.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.chip.on:hover { background: var(--btn-primary-hover); color: var(--accent-ink); }

/* ---------------- the list itself ---------------- */

.group + .group { margin-top: 14px; }
.group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--line);
}
.group-name { font-size: .72rem; font-weight: 700; color: var(--ink-soft); text-transform: uppercase; letter-spacing: .05em; }
.group-count { margin-left: auto; font-size: .75rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.item { display: flex; align-items: center; gap: 6px; border-top: 1px solid var(--line); }
.group-items .item:first-child, #bought .item:first-child { border-top: none; }

/* The whole row toggles: in a shop, one thumb, one tap, no aiming at a 16px
   checkbox. The edit button sits outside it (a button cannot nest in a button). */
.tick {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
  text-align: left;
  background: none;
  border: none;
  border-radius: 9px;
  font: inherit;
  color: inherit;
  padding: 11px 6px;
  cursor: pointer;
}
.tick:hover { background: var(--summary-bg); }
.box {
  flex: none;
  width: 22px;
  height: 22px;
  border: 2px solid var(--line);
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: transparent;
  transition: background .12s, border-color .12s, color .12s;
}
.box svg { display: block; }
.item.done .box { background: var(--good); border-color: var(--good); color: #fff; }
.item-main { min-width: 0; display: flex; flex-direction: column; }
/* the quantity is a padded pill, so it must be centred against the name rather
   than sitting on its baseline - on a baseline it reads as dropped by a pixel */
.item-line { display: flex; align-items: center; gap: 8px; min-width: 0; }
.item-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item-qty { flex: none; font-size: .82rem; font-weight: 600; line-height: 1.45; color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 1px 8px; }
.item-meta { display: flex; align-items: center; gap: 7px; min-width: 0; margin-top: 1px; }
.item-shop { flex: none; font-size: .75rem; font-weight: 600; color: var(--ink-soft); background: var(--summary-bg); border: 1px solid var(--line); border-radius: 999px; padding: 0 7px; }
.item-note { font-size: .8rem; color: var(--ink-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item.done .item-name { text-decoration: line-through; color: var(--ink-faint); font-weight: 500; }
.item.done .item-qty { color: var(--ink-faint); background: var(--summary-bg); }
.item-actions { display: flex; gap: 4px; flex: none; }
.icon-btn { border: none; background: none; color: var(--ink-faint); cursor: pointer; border-radius: 7px; padding: 6px 8px; font-size: .95rem; line-height: 1; }
.icon-btn:hover { color: var(--accent); background: var(--chip-hover); }
.icon-btn.del:hover { color: var(--danger); background: var(--del-hover-bg); }
.ic { display: inline-flex; align-items: center; justify-content: center; }
.ic svg { display: block; }

.bought-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.bought-head h2 { margin: 0; }
.bought-head .btn { margin-left: auto; }
#bought .item-main { opacity: .85; }

.empty { color: var(--ink-faint); text-align: center; padding: 18px 0; }

/* share / note */
.note { color: var(--ink-soft); font-size: .85rem; }
.link-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.link-pill { font-family: var(--mono); font-size: .8rem; background: var(--summary-bg); border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; color: var(--ink-soft); overflow-wrap: anywhere; }

/* ---------------- dialog ---------------- */

dialog {
  border: none;
  border-radius: var(--radius);
  box-shadow: 0 8px 40px rgba(16, 24, 40, .25);
  padding: 22px;
  width: min(560px, calc(100vw - 32px));
  /* tall dialogs scroll inside themselves. Use dvh so the cap follows the
     VISIBLE viewport on mobile (100vh ignores the address bar, which made the
     dialog taller than the screen with no way to scroll to the bottom). */
  max-height: calc(100vh - 40px);
  max-height: calc(100dvh - 40px);
  overflow: auto;
  background: var(--surface);
  color: var(--ink);
}
dialog::backdrop { background: rgba(20, 28, 38, .45); }
/* ...and the page behind a modal must not scroll */
html:has(dialog[open]) { overflow: hidden; }
.modal-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.modal-head h2 { margin: 0; font-size: 1.1rem; }
.close-x { border: none; background: none; font-size: 1.4rem; color: var(--ink-faint); cursor: pointer; line-height: 1; padding: 0 4px; }
.close-x:hover { color: var(--ink); }

.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.field > label { font-size: .8rem; font-weight: 600; color: var(--ink-soft); }
.field input, .field select { width: 100%; }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.name-row { display: flex; gap: 8px; }
.name-row input { flex: 1; min-width: 0; }
.link-pill.grow { flex: 1; }

/* In-dialog message. A toast can't be used there: a modal <dialog> paints in
   the browser's top layer, above any z-index, so a toast fired while a dialog
   is open is simply invisible - which reads as "nothing happens" on a failed
   save. The quick-add row carries the same slot for the same reason: its
   warning must appear next to the field, not float over the page. */
.form-msg { margin-top: 14px; padding: 9px 12px; border-radius: 9px; font-size: .85rem; font-weight: 600; }
.modal-head + .form-msg { margin: 0 0 14px; } /* settings shows it at the top */
.form-msg.err { background: var(--danger-soft); color: var(--danger); }
.form-msg.ok { background: var(--good-soft); color: var(--good); }
input.invalid, select.invalid { border-color: var(--danger); }

.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 18px; }
.modal-actions .btn-danger { margin-right: auto; }
.danger-zone { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }

/* ---------------- footer & toast ---------------- */

.footer { text-align: center; color: var(--ink-faint); font-size: .78rem; padding: 26px 20px; }
.footer-links { display: flex; align-items: center; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 6px; }
/* A <button> here must sit on exactly the same line as an <a>. Resetting the
   font and border is not enough: a button also carries UA padding (1px 6px),
   which pushes the text and its underline a pixel below the neighbouring link
   and makes the gaps uneven. */
.footer-link {
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  line-height: inherit;
}
.footer-link:hover { color: var(--accent); }

.toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--ink);
  color: var(--bg);
  padding: 10px 18px;
  border-radius: 10px;
  font-size: .9rem;
  box-shadow: var(--shadow);
  z-index: 50;
  transition: opacity .2s;
  max-width: calc(100vw - 32px);
}
.toast.err { background: var(--danger); color: #fff; }

@media (max-width: 560px) {
  .row2 { grid-template-columns: 1fr; }
  /* the add row wraps into three: name, then quantity + category, then shop + Add */
  .add-row { flex-wrap: wrap; }
  .add-row #addName { flex: 1 0 100%; }
  .add-row select { flex: 1 1 auto; max-width: none; }
  .qty-input { width: 74px; flex: 0 0 74px; }
  .shop-input { flex: 1 1 60%; }
  .name-row { flex-wrap: wrap; }
  .name-row input { flex: 1 0 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ---------------- dark mode ----------------
   Every visual difference is a variable override, so the OS preference and the
   manual toggle only swap tokens. head.js always stamps the EFFECTIVE theme on
   <html data-theme>, so this palette is written once here instead of being
   duplicated between a prefers-color-scheme block and the explicit selector -
   two copies that could (and did) drift apart. app.js keeps data-theme in step
   with the OS while the visitor has made no explicit choice. */
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #10151b;
  --surface: #1a222b;
  --ink: #e7ecf2;
  --ink-soft: #a6b1be;
  --ink-faint: #75808d;
  --accent: #e08a6a;
  --accent-ink: #2b1108;
  --accent-soft: #3b2419;
  --line: #2b3542;
  --input-bg: #141b22;
  --input-focus-bg: #10161c;
  --btn-primary-hover: #cf7a5b;
  --chip-hover: #4b2e20;
  --summary-bg: #141b22;
  --good: #58b581;
  --good-soft: #173026;
  --danger: #f07b72;
  --danger-soft: #3a1d19;
  --del-hover-bg: #3a2320;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 16px rgba(0, 0, 0, .35);
}

/* ---------------- print ----------------
   Ctrl+P gives a paper copy to take to the shop: the controls, the row actions
   and the share link (which is the credential) all drop out. */
@media print {
  .topbar-controls, .list-actions, .add-card, .suggest-card, .item-actions,
  .bought-head .btn, .footer-links, .share-card, .more-tools { display: none !important; }
  body { background: #fff; color: #000; }
  .card { box-shadow: none; border-color: #ccc; break-inside: avoid; }
}
