/* The demo page loads only fonts.css, variables.css and this file. It does NOT load
   continuum.css, so it never inherited that file's reset, and without border-box every
   border added OUTSIDE the height it was given. That is why the banner measured 43px
   against a 42px token and covered content at every width: the number was not wrong,
   the box model was. */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
img, svg { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }

/* ============================================================================
   CONTINUUM — the product surface.
   A different register from the marketing site: instrumental, not cinematic.
   120-200ms interactions, zero spectacle, density over drama. Same tokens.
   ========================================================================= */

.app {
  padding-top: var(--demo-banner);
  --sidebar: 232px;
  --rail: 56px;
  --topbar: 56px;
  --demo-banner: 42px;   /* includes the 1px border: box-sizing is border-box */
  min-height: 100vh;
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}

/* ── the demo banner ───────────────────────────────────────────────────────
   IN THE COMPONENT TREE, on every viewport, deliberately not an overlay and
   deliberately not dismissible. A demo that can be screenshotted without its
   label becomes a claim about a product that does not exist yet. It occupies
   real layout space so it cannot be cropped out by scrolling either. */
.demo-banner {
  /* FIXED, not sticky. Sticky measured as scrolling away at 390px because the
     document's scroll container is the body here, and 1440 only appeared to pass
     because that page is shorter than the viewport and never scrolled at all.
     The requirement is not a particular position value, it is that the label is on
     screen in every screenshot anyone can take. .app reserves the space so the
     banner still occupies layout and is not an overlay pasted on top of content. */
  position: fixed; top: 0; inset-inline: 0; z-index: 60;
  display: flex; align-items: center; gap: 10px;
  height: var(--demo-banner);
  padding-inline: clamp(12px, 3vw, 24px);
  background: linear-gradient(90deg, rgba(157,124,255,0.20), rgba(52,230,224,0.14));
  border-bottom: 1px solid rgba(157,124,255,0.38);
  font-size: 12.5px;
  color: var(--text-primary);
}
.demo-banner strong { font-weight: 700; letter-spacing: 0.02em; }
.demo-banner span { color: var(--text-secondary); }
.demo-banner a { color: var(--aqua); text-decoration: underline; text-underline-offset: 2px; }
/* ONE variable drives both the banner's height and the space reserved for it, so they
   cannot drift apart. They already had: the token said 40px while the banner measured
   41px on desktop (the 1px border) and 55px on mobile (auto height plus padding), so
   the banner was covering content at EVERY width. A fixed height also means the mobile
   text has to fit rather than silently reflowing the layout. */
@media (max-width: 560px) {
  .app { --demo-banner: 58px; }
  .demo-banner { padding-block: 6px; line-height: 1.3; align-items: center; }
  .demo-banner .demo-banner__long { display: none; }
}

/* ── shell ─────────────────────────────────────────────────────────────── */
.shell { display: grid; grid-template-columns: var(--sidebar) 1fr; min-height: calc(100vh - var(--demo-banner)); }
@media (max-width: 900px) { .shell { grid-template-columns: 1fr; } }

.side {
  border-right: 1px solid var(--border);
  background: var(--bg-deepest);
  padding: 16px 12px;
  display: flex; flex-direction: column; gap: 22px;
  position: sticky; top: var(--demo-banner); height: calc(100vh - var(--demo-banner)); overflow-y: auto;
}
@media (max-width: 900px) { .side { display: none; } }

.side__brand { display: flex; align-items: center; gap: 9px; padding: 4px 8px 0; }
.side__brand img { width: 26px; height: 26px; }
.side__brand b { font-size: 15px; letter-spacing: -0.02em; }

.zone { display: flex; flex-direction: column; gap: 2px; }
.zone__label {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-faded); padding: 0 8px 6px;
}
.navitem {
  display: flex; align-items: center; gap: 10px;
  min-height: 34px; padding: 0 8px; border-radius: 7px;
  color: var(--text-secondary); cursor: pointer; border: 0; background: none;
  width: 100%; text-align: left; font-size: 13.5px;
  transition: background-color 120ms linear, color 120ms linear;
}
.navitem:hover { background: var(--bg-glass); color: var(--text-primary); }
.navitem[aria-current='page'] { background: var(--bg-glass-strong); color: var(--text-primary); font-weight: 600; }
.navitem__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dot, var(--iris)); flex: 0 0 7px; }
.navitem__key { margin-left: auto; font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faded); }
.navitem__badge {
  margin-left: auto; min-width: 19px; height: 19px; padding: 0 6px; border-radius: 10px;
  background: var(--iris); color: #0A0B16; font-size: 11px; font-weight: 700;
  display: grid; place-items: center;
}

/* ── main ──────────────────────────────────────────────────────────────── */
.main { display: flex; flex-direction: column; min-width: 0; }

.topbar {
  display: flex; align-items: center; gap: 14px;
  height: var(--topbar); padding-inline: clamp(14px, 3vw, 28px);
  border-bottom: 1px solid var(--border);
  position: sticky; top: var(--demo-banner); z-index: 40;
  background: var(--bg-primary);
}
.topbar__title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.topbar__sub { color: var(--text-muted); font-size: 12.5px; }
.topbar__spacer { margin-left: auto; }

.kbtn {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 32px; padding: 0 11px; border-radius: 7px;
  border: 1px solid var(--border-strong); background: transparent;
  color: var(--text-secondary); font-size: 12.5px; cursor: pointer;
  transition: border-color 120ms linear, color 120ms linear;
}
.kbtn:hover { border-color: var(--border-gold-strong); color: var(--text-primary); }
kbd {
  font-family: var(--font-mono); font-size: 10.5px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  border-radius: 4px; padding: 1px 5px; color: var(--text-muted);
}

.view { padding: clamp(18px, 3vw, 32px); max-width: 1080px; width: 100%; }
/* The view is focused programmatically on every route change so screen readers
   announce the new surface. That is a correct thing to do and a wrong thing to
   PAINT: a ring appeared around the whole content area for every navigation.
   Keep it focusable, drop the ring, since the user never put focus here. */
.view:focus { outline: none; }
.view__head { margin-bottom: 22px; }
.view__h { font-size: 21px; font-weight: 600; letter-spacing: -0.02em; margin-bottom: 5px; }
.view__meta { color: var(--text-muted); font-size: 12.5px; }

/* ── cards ─────────────────────────────────────────────────────────────── */
.cards { display: grid; gap: 12px; }
@media (min-width: 720px) { .cards { grid-template-columns: repeat(2, 1fr); } }

.tcard {
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-card); padding: 15px 16px;
  display: flex; flex-direction: column; gap: 8px;
  transition: border-color 140ms linear, transform 140ms var(--ease-out-quart);
}
.tcard:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.tcard__slot {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--slot, var(--text-muted));
}
.tcard__title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.tcard__body { color: var(--text-secondary); font-size: 13.5px; }
.tcard__foot { display: flex; align-items: center; gap: 10px; margin-top: 2px; }
.tcard__why {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-size: 12px; color: var(--text-muted); text-decoration: underline; text-underline-offset: 2px;
}
.tcard__why:hover { color: var(--aqua); }
.tcard__whytext {
  font-size: 12.5px; color: var(--text-muted); border-left: 2px solid var(--border-gold);
  padding-left: 10px; margin-top: 2px;
}
.tcard--care { border-color: rgba(255,194,122,0.34); }

/* ── inbox ─────────────────────────────────────────────────────────────── */
.rows { border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
.row {
  display: grid; grid-template-columns: auto 1fr auto; gap: 12px; align-items: center;
  padding: 13px 15px; border-bottom: 1px solid var(--border);
  cursor: pointer; background: var(--bg-card);
  transition: background-color 120ms linear, opacity 180ms linear, transform 180ms var(--ease-out-quart);
}
.row:last-child { border-bottom: 0; }
.row:hover { background: var(--bg-elevated); }
.row[data-sel='true'] { background: var(--bg-elevated); box-shadow: inset 2px 0 0 var(--iris); }
.row.is-out { opacity: 0; transform: translateX(24px); pointer-events: none; }
.row__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--dot, var(--iris)); }
.row__t { font-size: 13.5px; font-weight: 600; }
.row__s { font-size: 12px; color: var(--text-muted); }
.row__src { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faded); text-align: right; }

.hint { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 14px; color: var(--text-muted); font-size: 12px; }
.hint span { display: inline-flex; align-items: center; gap: 5px; }

/* ── library ───────────────────────────────────────────────────────────── */
.cluster { margin-bottom: 26px; }
.cluster__h {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: 10px;
}
.syslist { display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 10px; }
.sys {
  border: 1px solid var(--border); border-radius: 10px; background: var(--bg-card);
  padding: 12px; display: flex; flex-direction: column; gap: 6px; cursor: pointer;
  transition: border-color 140ms linear, transform 140ms var(--ease-out-quart);
  text-align: left; width: 100%;
}
.sys:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.sys__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dot); }
.sys__n { font-size: 13.5px; font-weight: 600; }
.sys__s { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faded); }
.sys[data-state='active'] .sys__s { color: var(--mint); }

/* ── access ────────────────────────────────────────────────────────────── */
.grant {
  display: grid; gap: 4px; padding: 15px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--bg-card);
  margin-bottom: 10px;
}
.grant__top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.grant__who { font-size: 14.5px; font-weight: 600; }
.grant__view {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--aqua); border: 1px solid var(--border-aqua); border-radius: 999px; padding: 2px 8px;
}
.grant__meta { color: var(--text-muted); font-size: 12.5px; }
.grant__revoke {
  margin-left: auto; min-height: 30px; padding: 0 12px; border-radius: 7px;
  border: 1px solid var(--border-strong); background: transparent; color: var(--text-secondary);
  font-size: 12.5px; cursor: pointer; transition: border-color 120ms linear, color 120ms linear;
}
.grant__revoke:hover { border-color: #FF6B7A; color: #FF9E9E; }
.grant[data-revoked='true'] { opacity: 0.55; }
.grant[data-revoked='true'] .grant__revoke { display: none; }

.empty {
  border: 1px dashed var(--border-strong); border-radius: 12px;
  padding: 26px; text-align: center; color: var(--text-secondary); font-size: 13.5px;
}

/* ── composer ──────────────────────────────────────────────────────────── */
.composer { display: grid; gap: 16px; }
@media (min-width: 900px) { .composer { grid-template-columns: 260px 1fr; align-items: start; } }
.topics { display: grid; gap: 7px; }
.topic {
  display: flex; align-items: center; gap: 9px; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--bg-card);
  cursor: pointer; font-size: 13px; text-align: left; width: 100%;
  transition: border-color 120ms linear;
}
.topic[aria-pressed='true'] { border-color: var(--border-aqua); }
.topic__box {
  width: 15px; height: 15px; border-radius: 4px; border: 1px solid var(--border-strong);
  display: grid; place-items: center; flex: 0 0 15px; font-size: 10px; color: #06070F;
}
.topic[aria-pressed='true'] .topic__box { background: var(--aqua); border-color: var(--aqua); }
.preview {
  border: 1px solid var(--border-strong); border-radius: 12px; overflow: hidden;
  background: var(--bg-deepest);
}
.preview__bar {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-bottom: 1px solid var(--border); background: var(--bg-elevated);
  font-size: 12px; color: var(--text-secondary);
}
.preview__body { padding: 16px; display: grid; gap: 13px; }
.pgroup__h { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.13em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 6px; }
.pline { display: flex; justify-content: space-between; gap: 14px; padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.pline:last-child { border-bottom: 0; }
.pline span:last-child { color: var(--text-secondary); text-align: right; }
.pnote { font-size: 12.5px; color: var(--text-muted); border-top: 1px solid var(--border); padding-top: 11px; }

/* ── command palette ───────────────────────────────────────────────────── */
.pal { position: fixed; inset: 0; z-index: 200; display: none; }
.pal[data-open='true'] { display: block; }
/* Solid scrim, never backdrop-filter: a live blur on a fixed full-screen layer
   is the measured iOS GPU whiteout on this estate. */
.pal__scrim { position: absolute; inset: 0; background: rgba(6,7,15,0.72); }
.pal__box {
  position: relative; margin: 12vh auto 0; width: min(560px, 92vw);
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  border-radius: 14px; box-shadow: var(--shadow-deep); overflow: hidden;
  transform: scale(0.985); opacity: 0;
  transition: transform 150ms var(--ease-out-quart), opacity 150ms linear;
}
.pal[data-open='true'] .pal__box { transform: none; opacity: 1; }
.pal__input {
  width: 100%; border: 0; background: transparent; color: var(--text-primary);
  padding: 15px 17px; font-size: 15px; outline: none;
  border-bottom: 1px solid var(--border);
}
.pal__list { max-height: 46vh; overflow-y: auto; padding: 6px; }
.pal__item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 11px; border-radius: 8px; border: 0; background: none;
  color: var(--text-secondary); cursor: pointer; font-size: 13.5px; text-align: left;
}
.pal__item[data-sel='true'] { background: var(--bg-glass-strong); color: var(--text-primary); }
.pal__item small { margin-left: auto; font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faded); }
.pal__none { padding: 18px; text-align: center; color: var(--text-muted); font-size: 13px; }

/* ── mobile bottom bar ─────────────────────────────────────────────────── */
.tabbar {
  display: none;
  position: fixed; inset-inline: 0; bottom: 0; z-index: 50;
  background: var(--bg-deepest); border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom, 0);
}
@media (max-width: 900px) {
  .tabbar { display: grid; grid-template-columns: repeat(5, 1fr); }
  .main { padding-bottom: 68px; }
}
.tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: 56px; border: 0; background: none; cursor: pointer;
  color: var(--text-muted); font-size: 10.5px;
}
.tab[aria-current='page'] { color: var(--text-primary); }
.tab__ico { width: 18px; height: 18px; border-radius: 5px; border: 1.5px solid currentColor; }
.tab--center .tab__ico { background: var(--iris); border-color: var(--iris); }

/* ── toast ─────────────────────────────────────────────────────────────── */
.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 16px);
  z-index: 300; padding: 11px 17px; border-radius: 10px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  color: var(--text-primary); font-size: 13px; box-shadow: var(--shadow-deep);
  opacity: 0; pointer-events: none;
  transition: opacity 160ms linear, transform 200ms cubic-bezier(0.32,0.72,0,1);
}
.toast[data-show='true'] { opacity: 1; transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  .tcard, .row, .sys, .pal__box, .toast, .navitem, .kbtn, .grant__revoke { transition: none !important; }
  .row.is-out { transform: none !important; }
}

/* ============================================================================
   POLISH — 2026-07-31. The app register, not the marketing one: shorter
   durations, no spectacle, density preserved. Everything compositor-only.
   ========================================================================= */

/* Focus matches the marketing surface so the two read as one product. */
.app :focus-visible {
  outline: 2px solid var(--iris);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px rgba(157, 124, 255, 0.20);
  border-radius: 5px;
}

/* Elevation on the surface ramp rather than shadows, same law as the site. */
.tcard, .row, .sys, .grant, .plan, .preview { background: var(--e2); }
.tcard:hover, .sys:hover { background: var(--e3); }
.row:hover { background: var(--e3); }

/* The selected inbox row needs to be findable at a glance from across the room,
   not just distinguishable on inspection. The bar is the signal; the tint is
   support. */
.row[data-sel='true'] {
  background: var(--e3);
  box-shadow: inset 3px 0 0 var(--iris);
}

/* Slot colours carry meaning, so give the card a matching edge. A person should
   be able to tell DUE from NEXT before reading either. */
.tcard { border-left: 2px solid transparent; }
.tcard:has(.tcard__slot) { border-left-color: color-mix(in srgb, var(--slot, transparent) 55%, transparent); }

/* A revoked grant reads as ended at a glance, not by parsing its wording. */
.grant[data-revoked='true'] { border-color: rgba(255, 107, 122, 0.28); }
.grant[data-revoked='true'] .grant__view { color: var(--danger); border-color: rgba(255, 107, 122, 0.4); }
.grant__revoke:hover { border-color: var(--danger); color: var(--danger); }

/* Press states. Without these a click on a slow device feels like nothing
   happened, and people click again. */
.navitem:active, .tab:active, .sys:active, .topic:active, .kbtn:active { transform: scale(0.985); }
.navitem, .tab, .sys, .topic, .kbtn { transition: background-color 120ms linear, color 120ms linear, transform 120ms var(--ease-out-quart), border-color 120ms linear; }

/* The palette is the keyboard-first surface; its selected row should be as
   obvious as a selected inbox row. */
.pal__item[data-sel='true'] { background: var(--e3); box-shadow: inset 2px 0 0 var(--iris); }

/* The active nav item earns a marker, not just a weight change. */
.navitem[aria-current='page'] { box-shadow: inset 2px 0 0 var(--iris); }

/* Same grain as the marketing site, at half strength: the app has far more
   surface area per screen and needs less texture to avoid banding. */
.app::before {
  content: '';
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none; opacity: 0.02;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

@media (prefers-reduced-motion: reduce) {
  .navitem, .tab, .sys, .topic, .kbtn { transition: none !important; }
  .navitem:active, .tab:active, .sys:active, .topic:active, .kbtn:active { transform: none !important; }
}

/* REGRESSION GUARD. The polish pass added `.app :focus-visible`, which is more
   specific than the earlier `.view:focus { outline: none }` and so reinstated the
   ring around the entire content column on every route change. The view is
   focused programmatically for screen-reader announcement; the user never put
   focus there and must not see it land. Keep it focusable, keep it unpainted.
   Verified by measuring the computed outline, not by reading the rule. */
.app .view:focus,
.app .view:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}
