/* ===========================================================================
   GRAPE — Base layer
   Reset, typography defaults, app shell layout, page-load motion, utilities.
   Consumes tokens from theme.css.
   =========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { -webkit-text-size-adjust: 100%; }

/* Scale the whole UI down on small phones. Every token is rem-based, so one
   root font-size step shrinks type AND spacing proportionally — more content
   fits, nothing is redesigned. (px media queries are unaffected by this, so
   layout breakpoints stay put; the fixed-px bottom nav keeps its tap size.) */
@media (max-width: 600px) { html { font-size: 93.75%; } } /* ~15px */
@media (max-width: 400px) { html { font-size: 87.5%; } }  /* ~14px — iPhone SE */

/* Large / 4K displays: widen the content column (--maxw drives page, nav, toast,
   etc.) and scale type up so it isn't a tiny centered column on a huge screen.
   rem-based tokens scale with the root font-size. */
@media (min-width: 1700px) { :root { --maxw: 1440px; } }
@media (min-width: 2400px) { :root { --maxw: 1760px; font-size: 112.5%; } }  /* ~18px */
@media (min-width: 3200px) { :root { --maxw: 2160px; font-size: 131.25%; } } /* ~21px — 4K */

body {
  font-family: var(--font-ui);
  font-size: var(--t-base);
  font-weight: 500;            /* bold baseline — everything reads confident */
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--bg);       /* flat — no grain, no gradient */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-smooth: always;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 800; line-height: var(--lh-tight); letter-spacing: var(--track-tight); }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }
ul { list-style: none; padding: 0; }

/* <details>: hide the native disclosure triangle — we render our own caret */
summary { list-style: none; cursor: pointer; }
summary::-webkit-details-marker { display: none; }
summary::marker { content: ""; }

::selection { background: var(--accent); color: var(--on-accent); }

/* scrollbars — match the design system: square, thin, grey (adapts to theme) */
* { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg-sunken); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 0; }
::-webkit-scrollbar-thumb:hover { background: var(--text-soft); }
::-webkit-scrollbar-corner { background: var(--bg-sunken); }

/* --- Eyebrow / label caps -------------------------------------------- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-soft);
}

/* --- Mono figures ----------------------------------------------------- */
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }

/* ===========================================================================
   APP SHELL — MOBILE FIRST
   Slim sticky top bar (brand · theme · account) + a fixed BOTTOM tab bar
   that is the primary navigation (thumb reach). Content scrolls between.
   Same structure scales up to desktop — tabs just go inline.
   =========================================================================== */
.shell { display: flex; flex-direction: column; min-height: 100vh; }

.topnav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: var(--border-w) solid var(--border);
}
.topnav .brand { margin-right: var(--s-2); }
.topnav .spacer { flex: 1; }

/* main is the scroll viewport: exactly the space above the bottom nav, so
   short pages don't scroll (no excess / no stray scrollbar) and list pages
   fill it. clears the status bar / camera cut-out via the top inset. */
.main { min-width: 0; display: flex; flex-direction: column;
  height: calc(100dvh - var(--botnav-h) - env(safe-area-inset-bottom, 0px));
  overflow-y: auto; overflow-x: hidden;   /* never scroll the page sideways */
  -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
  scroll-behavior: smooth;   /* programmatic snap-to-fill glides (not a jump) */
  padding-top: max(var(--s-5), env(safe-area-inset-top, 0px));
  padding-bottom: var(--s-5); }   /* breathing room; the toast overlays this area
                                     (snackbar-style) — it never reshapes the table */

/* bottom navigation — primary tab bar (thumb reach), flat + square */
.botnav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  background: var(--surface);
  border-top: var(--border-w) solid var(--border);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.botnav-inner { display: flex; max-width: var(--maxw); margin: 0 auto; overflow-x: auto; }

.page { padding: var(--s-4) var(--s-4) var(--s-5); width: 100%; max-width: var(--maxw); margin: 0 auto; }

/* per-page header — title + page-level actions, top of .page */
.pagehead { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s-3); margin-bottom: var(--s-5); flex-wrap: wrap; }
.pagehead h2 { font-size: var(--t-xl); }

/* --- Brand wordmark --------------------------------------------------- */
.brand {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.55rem;
  letter-spacing: var(--track-tight);
  display: inline-flex; align-items: center; gap: 0.55rem;
}
.brand .dot { width: 0.7rem; height: 0.7rem; background: var(--accent); border-radius: 50%; box-shadow: var(--shadow-sm); }

/* ===========================================================================
   PAGE-LOAD MOTION — staggered reveal. Bold but orchestrated, one moment.
   Add .reveal to elements; --i sets stagger index.
   =========================================================================== */
@keyframes rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }   /* end at none, NOT translateY(0): a
           lingering identity transform still establishes a containing block,
           which traps position:fixed descendants (e.g. the pager sheet). */
}
.reveal {
  opacity: 0;
  animation: rise var(--dur-slow) var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 70ms);
}

/* modal slide-in (centered overlays rise into place) */
@keyframes slideup {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}

/* newly-appended rows ease in (smooth infinite-scroll paging, no pop) */
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }
.tbl tbody tr { animation: fadein 220ms var(--ease-out) both; }

/* ===========================================================================
   UTILITIES
   =========================================================================== */
.row    { display: flex; align-items: center; }
.row-sb { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); }
.col    { display: flex; flex-direction: column; }
.gap-2  { gap: var(--s-2); } .gap-3 { gap: var(--s-3); } .gap-5 { gap: var(--s-5); }
.wrap   { flex-wrap: wrap; }
.grow   { flex: 1; }
.muted  { color: var(--text-soft); }
.center { text-align: center; }
.mt-2 { margin-top: var(--s-2); } .mt-3 { margin-top: var(--s-3); } .mt-4 { margin-top: var(--s-4); } .mt-5 { margin-top: var(--s-5); } .mt-6 { margin-top: var(--s-6); } .mt-7 { margin-top: var(--s-7); }
.mb-2 { margin-bottom: var(--s-2); } .mb-3 { margin-bottom: var(--s-3); } .mb-4 { margin-bottom: var(--s-4); } .mb-5 { margin-bottom: var(--s-5); }

/* grids — MOBILE FIRST: single column by default, widen up */
.grid  { display: grid; gap: var(--s-4); }
.split { display: grid; gap: var(--s-4); }
.grid-2, .grid-3, .split { grid-template-columns: 1fr; }

@media (min-width: 561px) {
  .grid-2 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 721px) {
  /* notch gap is mobile-only; on tablet/laptop recover the top space —
     trim the page top padding (no top bar to clear). */
  .main { padding-top: 0; }
  .page { padding: var(--s-4) var(--s-6) var(--s-6); }
  .pagehead { margin-bottom: var(--s-5); }
  .pagehead h2 { font-size: var(--t-xxl); }
  .topnav { padding: var(--s-3) var(--s-6); }
}
@media (min-width: 861px) {
  .grid  { gap: var(--s-5); }
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .split  { grid-template-columns: 360px 1fr; gap: var(--s-5); }
}

/* phone: tighter outer gutter (panels carry their own padding) + a smaller
   gap below the page header, so the fold shows content not whitespace. */
@media (max-width: 560px) {
  .page { padding: var(--s-3) var(--s-3) var(--s-5); }
  .pagehead { margin-bottom: var(--s-4); }
}

/* (Table snap-to-fill is measured in JS — see Shell's on:scroll: it only snaps
   a list panel to the top once ≥80% of it is on screen, and only while
   scrolling down, so a short scroll is never trapped.) */
