﻿/* ==================================================================
   POSTO portal — shell

   Every colour, radius, shadow, type step and duration comes from
   tokens.css. Nothing is redefined here: this file describes shell
   structure only, so a token change lands on the shell and all four
   modules at once.
   ================================================================== */

/* tokens.css is linked ahead of this file in the document head — a <link>
   parallelises where an @import would force a serial round-trip. */

:root {
  --topbar-h: 58px;
  --sidenav-w: 244px;
  --measure: 68ch; /* ~65 characters — the readable line length */
  --focus: 0 0 0 2px var(--bg), 0 0 0 3px var(--brand-2);
}

* { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--step-0);
  color: var(--text);
  background:
    radial-gradient(1100px 620px at 82% -8%, #16234a 0%, transparent 58%),
    radial-gradient(900px 520px at 6% 2%, #122043 0%, transparent 55%),
    var(--bg);
  background-attachment: fixed;
  line-height: 1.6;
  min-height: 100dvh; /* dvh, not vh — mobile URL bar */
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
}

/* Four weights, not two — 500 and 600 carry most of the hierarchy so
   headings don't have to shout at 700 to read as headings. */
h1, h2, h3, h4 {
  margin: 0;
  line-height: 1.18;
  text-wrap: balance; /* no orphaned last words in headings */
}
h1 { font-size: var(--step-4); font-weight: 600; letter-spacing: var(--track-display); }
h2 { font-size: var(--step-2); font-weight: 600; letter-spacing: var(--track-title); }
h3 { font-size: var(--step-1); font-weight: 550; letter-spacing: var(--track-title); }
h4 { font-size: var(--step-0); font-weight: 600; }
p { margin: 0; text-wrap: pretty; }
ul { margin: 0; padding: 0; list-style: none; }
a { color: var(--brand-2); }

code, pre, .font-mono { font-family: var(--mono); }
/* Tabular figures keep credit counts and IP columns from jittering. */
.tnum, .meter__value, td.num { font-variant-numeric: tabular-nums; }

.icon { flex: none; }

/* Visually hidden but announced — for labels on compact inline controls. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- focus: never removed, always visible ------------------------- */
:focus-visible {
  outline: none;
  box-shadow: var(--focus);
  border-radius: var(--radius-sm);
}

.skip-link {
  position: absolute;
  left: var(--space-3);
  top: -100px;
  z-index: var(--z-toast);
  padding: var(--space-3) var(--space-4);
  background: var(--brand);
  color: var(--brand-ink);
  font-weight: 650;
  border-radius: var(--radius-sm);
  transition: top 0.15s var(--ease-out);
}
.skip-link:focus { top: var(--space-3); }

/* ==================================================================
   App frame
   ================================================================== */

.app {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-areas: 'topbar' 'main';
  min-height: 100dvh;
}

@media (min-width: 1024px) {
  .app {
    grid-template-columns: var(--sidenav-w) 1fr;
    grid-template-areas:
      'topbar topbar'
      'sidenav main';
  }
}

/* ---------------- Topbar ---------------- */

.topbar {
  grid-area: topbar;
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: var(--topbar-h);
  padding-inline: var(--space-3);
  /* Safe-area inset for notched devices in landscape. */
  padding-left: max(var(--space-3), env(safe-area-inset-left));
  padding-right: max(var(--space-3), env(safe-area-inset-right));
  background: var(--bar-bg);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-soft);
}

.topbar__spacer { flex: 1; }

.topbar__burger {
  display: inline-grid;
  place-items: center;
  width: 44px;  /* touch-target-size */
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}
@media (min-width: 1024px) { .topbar__burger { display: none; } }

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text);
  text-decoration: none;
  font-weight: 750;
  letter-spacing: 0.02em;
}
.brand__mark { color: var(--brand-2); display: inline-grid; place-items: center; }
.brand--auth { justify-content: center; margin-bottom: var(--space-5); font-size: 1.15rem; }

.account {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}
.account__email {
  font-size: 0.85rem;
  color: var(--text-dim);
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 719px) { .account__email { display: none; } }

.badge {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 3px var(--space-2);
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-dim);
  background: var(--surface-2);
}
.badge--admin { color: var(--brand-2); border-color: var(--brand-line); background: var(--brand-dim); }
.badge--active { color: var(--green); border-color: var(--green-line); background: var(--green-soft); }
.badge--pending { color: var(--yellow); border-color: var(--yellow-line); background: var(--yellow-soft); }
.badge--suspended { color: var(--red); border-color: var(--red-line); background: var(--red-soft); }

/* ---------------- Credit meter ---------------- */

/* Admin variant: one chip, no bar, no note. */
.meter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px var(--space-3);
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: var(--step--1);
  font-weight: 550;
  white-space: nowrap;
}
.meter-chip .icon { color: var(--green); }

/* Hairline between the balance and the account block — they are different
   kinds of information and were reading as one run-on cluster. */
.topbar__rule {
  width: 1px;
  height: 22px;
  flex: none;
  background: var(--border-soft);
}
@media (max-width: 899px) { .topbar__rule { display: none; } }

.meter { min-width: 168px; }
.meter__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.meter__label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-faint);
  font-weight: 650;
}
.meter__value { font-size: 0.82rem; color: var(--text-dim); }
.meter__value strong { color: var(--text); font-size: 0.95rem; }

.meter__track {
  height: 6px;
  margin-top: var(--space-1);
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
.meter__fill {
  height: 100%;
  border-radius: inherit;
  background: var(--brand);
  transition: width 0.3s var(--ease-out);
}
.meter--low .meter__fill { background: var(--yellow); }
.meter--low .meter__value strong { color: var(--yellow); }
.meter--empty .meter__fill { background: var(--red); }
.meter--empty .meter__value strong { color: var(--red); }

.meter__note {
  margin-top: var(--space-1);
  font-size: 0.72rem;
  color: var(--text-faint);
}

.topbar__meter { display: none; }
@media (min-width: 900px) { .topbar__meter { display: flex; align-items: center; } }

/* Three stacked rows don't fit a 58px bar. The reset date is still shown in
   full on Overview and Settings, so the topbar keeps only the balance. */
.topbar__meter .meter__note { display: none; }
.topbar__meter .meter { min-width: 150px; }
.topbar__meter .meter__head { gap: var(--space-4); }

/* ---------------- Side navigation ---------------- */

.sidenav {
  grid-area: sidenav;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-3);
  padding-bottom: max(var(--space-4), env(safe-area-inset-bottom));
  border-right: 1px solid var(--border-soft);
  background: var(--rail-bg);
  overflow-y: auto;
}

/* Below 1024 the sidenav becomes an off-canvas drawer. */
@media (max-width: 1023px) {
  .sidenav {
    position: fixed;
    inset: var(--topbar-h) auto 0 0;
    width: min(300px, 84vw);
    z-index: var(--z-drawer);
    background: var(--bg-2);
    transform: translateX(-102%);
    transition: transform 0.24s var(--ease-out);
    box-shadow: var(--shadow);
  }
  .sidenav[data-open='true'] { transform: translateX(0); }
}

.sidenav__close { display: none; }
@media (max-width: 1023px) {
  .sidenav__close {
    display: inline-grid;
    place-items: center;
    align-self: flex-end;
    width: 44px;
    height: 44px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
  }
}

.drawer-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-scrim);
  /* 55% — strong enough to isolate the drawer, per scrim legibility. */
  background: var(--scrim);
  backdrop-filter: blur(2px);
}
.drawer-scrim[hidden] { display: none; }
@media (min-width: 1024px) { .drawer-scrim { display: none !important; } }

.sidenav__list { display: flex; flex-direction: column; gap: 2px; }
.sidenav__foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--space-3); }
.sidenav__foot .signout {
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-soft);
}

.navitem {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 44px; /* touch-target-size */
  padding: var(--space-2) var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  background: none;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 550;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  transition: background 0.15s var(--ease-out), color 0.15s var(--ease-out);
}
.navitem:hover { background: var(--surface); color: var(--text); }

/* Active state uses an accent rail + weight + colour — three cues, not one. */
.navitem[aria-current='page'] {
  background: var(--surface-2);
  color: var(--text);
  font-weight: 650;
  border-color: var(--border);
}
.navitem[aria-current='page']::before {
  content: '';
  position: absolute;
  left: -1px;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 22px;
  border-radius: 0 3px 3px 0;
  background: var(--brand);
}
.navitem[aria-current='page'] .icon { color: var(--brand-2); }

.navitem__label { flex: 1; min-width: 0; }

.navitem__cost {
  flex: none;
  font-size: 0.68rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 7px;
}
.navitem--danger { color: var(--text-faint); }
.navitem--danger:hover { background: var(--red-soft); color: var(--red); }

/* ---------------- Main ---------------- */

.main {
  grid-area: main;
  min-width: 0; /* stops wide tables forcing body-level horizontal scroll */
  padding: var(--space-5) var(--space-4) var(--space-7);
  padding-left: max(var(--space-4), env(safe-area-inset-left));
  padding-right: max(var(--space-4), env(safe-area-inset-right));
}
.main:focus { outline: none; }

.wrap { max-width: var(--page-max); margin-inline: auto; }

/* ==================================================================
   Page anatomy

   Every shell page is Page > PageHeader > Section*. Spacing and
   heading treatment live here once, so no page can quietly invent its
   own rhythm.
   ================================================================== */

.page { max-width: var(--page-max); margin-inline: auto; }
.page--narrow { max-width: 760px; }

/* Sections are separated by a consistent step, and by a hairline rule
   rather than by each one being a floating card. */
.page > .section + .section {
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-soft);
}

.pagehead { margin-bottom: var(--space-6); }
.pagehead__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-5);
  flex-wrap: wrap;
}
.pagehead__text { min-width: 0; }
.pagehead__eyebrow {
  font-size: var(--step--1);
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--text-faint);
  margin-bottom: var(--space-2);
}
.pagehead__lede {
  margin-top: var(--space-3);
  color: var(--text-dim);
  font-size: var(--step-0);
  max-width: var(--measure);
}
.pagehead__actions { flex: none; }

/* Headline figure in the page header — the balance, without the meter. */
.headstat {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: var(--surface);
}
.headstat__value {
  font-size: var(--step-3);
  font-weight: 650;
  letter-spacing: var(--track-display);
  line-height: 1;
}
.headstat__label { font-size: var(--step--1); color: var(--text-faint); line-height: 1.35; }

/* ---------------- Section ---------------- */

.section__head { margin-bottom: var(--space-4); }
.section__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: var(--track-title);
}
.section__title .icon { color: var(--text-faint); }
.section__desc {
  margin-top: var(--space-2);
  color: var(--text-dim);
  font-size: var(--step--1);
  max-width: var(--measure);
}

.section--boxed {
  padding: var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
/* A boxed section is already visually separated — don't rule it as well. */
.page > .section--boxed + .section--boxed {
  margin-top: var(--space-4);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-soft);
}

.stack { display: flex; flex-direction: column; gap: var(--space-4); }

/* ---------------- Split: main + rail ---------------- */

.split { display: grid; gap: var(--space-5); grid-template-columns: 1fr; }
@media (min-width: 960px) {
  .split { grid-template-columns: minmax(0, 1fr) 300px; align-items: start; }
  .split__rail { position: sticky; top: calc(var(--topbar-h) + var(--space-5)); }
}
.split__main { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

.rail {
  padding: var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.rail__title {
  font-size: var(--step--1);
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: var(--track-label);
  color: var(--text-faint);
  margin-bottom: var(--space-4);
}
.rail__list { display: flex; flex-direction: column; gap: var(--space-3); margin: 0; }

.datarow {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.datarow + .datarow { padding-top: var(--space-3); border-top: 1px solid var(--border-soft); }
.datarow__label { font-size: var(--step--1); color: var(--text-faint); flex: none; }
.datarow__value {
  margin: 0;
  font-size: var(--step--1);
  color: var(--text);
  text-align: right;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ---------------- Stat strip ---------------- */

.statstrip {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  margin-bottom: var(--space-5);
}
.stat {
  padding: var(--space-4) var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  /* Accent rail carries the tone; the number stays legible either way. */
  border-left: 3px solid var(--border);
}
.stat--green { border-left-color: var(--green); }
.stat--yellow { border-left-color: var(--yellow); }
.stat--red { border-left-color: var(--red); }
.stat__value {
  font-size: var(--step-3);
  font-weight: 650;
  letter-spacing: var(--track-display);
  line-height: 1.1;
}
.stat__label {
  margin-top: var(--space-1);
  font-size: var(--step--1);
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: var(--track-label);
}

/* ---------------- Disclosure ---------------- */

.disclosure {
  margin-bottom: var(--space-6);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  overflow: hidden;
}
.disclosure__summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 52px;
  padding: var(--space-3) var(--space-5);
  cursor: pointer;
  font-weight: 600;
  font-size: var(--step-0);
  list-style: none;
  transition: background var(--dur) var(--ease-out);
}
.disclosure__summary::-webkit-details-marker { display: none; }
.disclosure__summary:hover { background: var(--surface-2); }
.disclosure__summary .icon { color: var(--text-faint); }
.disclosure__summary > span { flex: 1; }
.disclosure__chev { transition: transform var(--dur) var(--ease-out); }
.disclosure[open] .disclosure__chev { transform: rotate(90deg); }
.disclosure__body {
  padding: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-soft);
}

.emptystate--boxed {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}

/* ==================================================================
   Components
   ================================================================== */

.card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: var(--space-5);
  box-shadow: var(--shadow);
}
.card__title { display: flex; align-items: center; gap: var(--space-2); }
.card__body { margin-top: var(--space-4); display: flex; flex-direction: column; gap: var(--space-4); }

/* ---------------- Tool launcher ---------------- */

/* An asymmetric grid, not N equal columns. The first tool spans two
   tracks and carries more weight; the rest fall into a denser rhythm
   beside it. Deliberately not a row of identical thirds. */
.launcher {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr;
}
@media (min-width: 720px) {
  .launcher { grid-template-columns: repeat(2, 1fr); }
  .launcher > .toolcard:first-child { grid-column: span 2; }
}
@media (min-width: 1180px) {
  .launcher { grid-template-columns: repeat(3, 1fr); }
  /* Two columns wide, one row tall. Spanning two rows as well left a large
     dead area inside the card that no amount of padding fixed. */
  .launcher > .toolcard:first-child { grid-column: span 2; }
}

/* No border + shadow + background all at once. The card is a surface
   and spacing; a hairline appears only on hover, where it means
   something. */
.toolcard {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--surface);
  color: inherit;
  text-decoration: none;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: transform var(--dur) var(--ease-spring),
    border-color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}
.toolcard:hover {
  transform: translateY(-3px);
  background: var(--surface-2);
  border-color: var(--border);
}
.toolcard:active { transform: translateY(-1px); }

/* Accent hairline along the top edge, drawn on hover only. */
.toolcard::before {
  content: '';
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--brand-line), transparent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease-out);
}
.toolcard:hover::before { opacity: 1; }

.toolcard__top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.toolcard__icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--text-dim);
  transition: color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}
.toolcard:hover .toolcard__icon { color: var(--brand-2); background: var(--brand-dim); }

.toolcard__name {
  font-size: var(--step-1);
  font-weight: 550;
  letter-spacing: var(--track-title);
}
.toolcard__blurb {
  color: var(--text-dim);
  font-size: var(--step--1);
  max-width: 46ch;
  margin-top: var(--space-1);
}

/* Pinned to the bottom so the "Open" affordances line up across the
   row no matter how long each blurb runs. */
.toolcard__foot {
  margin-top: auto;
  padding-top: var(--space-4);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--step--1);
  color: var(--text-faint);
}
.toolcard__go {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-dim);
  font-weight: 550;
  transition: color var(--dur) var(--ease-out), gap var(--dur) var(--ease-out);
}
.toolcard:hover .toolcard__go { color: var(--brand-2); gap: 10px; }

/* The lead card gets room to breathe rather than a louder colour. */
@media (min-width: 1180px) {
  .launcher > .toolcard:first-child { padding: var(--space-6); }
  .launcher > .toolcard:first-child .toolcard__name { font-size: var(--step-2); }
  .launcher > .toolcard:first-child .toolcard__icon { width: 46px; height: 46px; }
}

.cost-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px var(--space-2);
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-dim);
}
.cost-chip--free { color: var(--green); border-color: var(--green-line); background: var(--green-soft); }

/* Disabled tool card: allowance spent. Not a link, and says why. */
.toolcard--locked { opacity: 0.55; pointer-events: none; }
.toolcard--locked .toolcard__go { color: var(--text-faint); }

/* ---------------- Buttons (API matches the modules' existing .btn) --- */

.btn {
  --btn-bg: var(--surface-2);
  --btn-fg: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  font: inherit;
  font-weight: 600;
  font-size: 0.92rem;
  min-height: 44px;
  padding: 0.62rem 1.1rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--btn-bg);
  color: var(--btn-fg);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: transform 0.12s var(--ease-out), background 0.15s var(--ease-out),
    border-color 0.15s var(--ease-out), box-shadow 0.15s var(--ease-out);
}
.btn:hover { transform: translateY(-1px); border-color: var(--hover-line); }
.btn:active { transform: translateY(0); }
.btn:disabled, .btn[aria-disabled='true'] {
  opacity: 0.45; /* disabled-states: 0.38–0.5 */
  cursor: not-allowed;
  transform: none;
}
.btn--primary {
  --btn-fg: var(--brand-ink);
  background: var(--brand-grad);
  border-color: transparent;
  box-shadow: var(--shadow-accent);
}
.btn--primary:hover {
  border-color: transparent;
  box-shadow: 0 16px 30px -14px rgba(79, 140, 255, 0.9);
}
.btn--ghost { background: transparent; }
.btn--small { min-height: 36px; padding: 0.42rem 0.8rem; font-size: 0.84rem; }
.btn--danger { --btn-fg: var(--red); border-color: var(--red-line); background: var(--red-soft); }
.btn--block { width: 100%; }

.btn__spinner {
  width: 15px;
  height: 15px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.btn[data-loading='true'] { pointer-events: none; opacity: 0.7; }

/* ---------------- Forms ---------------- */

.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field + .field { margin-top: var(--space-4); }

.field__label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-dim);
}
.field__label .req { color: var(--red); margin-left: 2px; }

.input, .select, .textarea {
  font: inherit;
  font-size: 1rem; /* 16px stops iOS zoom-on-focus */
  min-height: 44px;
  width: 100%;
  padding: 0.6rem 0.8rem;
  color: var(--text);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s var(--ease-out);
}
.input::placeholder { color: var(--text-faint); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--hover-line); }
.input[aria-invalid='true'] { border-color: var(--red); }
.input:read-only { background: var(--surface); color: var(--text-dim); }
.input:disabled { opacity: 0.45; cursor: not-allowed; }

.field__help { font-size: 0.78rem; color: var(--text-faint); }
/* Errors sit below the field they belong to, never only at the top. */
.field__error {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 0.8rem;
  color: var(--red);
  font-weight: 550;
}

.input-group { position: relative; display: flex; }
.input-group .input { padding-right: 48px; }
.input-group__btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  background: none;
  color: var(--text-faint);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.input-group__btn:hover { color: var(--text); }

/* One-time-code input: wide tracking, monospace, tabular. */
.otp {
  font-family: var(--mono);
  font-size: 1.5rem;
  letter-spacing: 0.5em;
  text-align: center;
  text-indent: 0.5em;
  font-variant-numeric: tabular-nums;
}

/* ---------------- Alerts ---------------- */

.alert {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 0.88rem;
  color: var(--text-dim);
}
.alert .icon { margin-top: 2px; flex: none; }
.alert strong { color: var(--text); display: block; }
.alert--error { border-color: var(--red-line); background: var(--red-soft); color: #ffd7d7; }
.alert--error .icon { color: var(--red); }
.alert--success { border-color: var(--green-line); background: var(--green-soft); color: #cdf3e0; }
.alert--success .icon { color: var(--green); }
.alert--warn { border-color: var(--yellow-line); background: var(--yellow-soft); color: #ffeccb; }
.alert--warn .icon { color: var(--yellow); }

/* ---------------- Tables ---------------- */

/* Wide tables scroll inside their own box; the page body never scrolls sideways. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: var(--surface);
}
.table { width: 100%; border-collapse: collapse; font-size: 0.88rem; min-width: 720px; }
.table th, .table td {
  padding: var(--space-3) var(--space-4);
  text-align: left;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}
.table thead th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  font-weight: 700;
  background: var(--bg-2);
  position: sticky;
  top: 0;
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--row-hover); }
.table td.num { text-align: right; }

.emptystate {
  padding: var(--space-7) var(--space-5);
  text-align: center;
  color: var(--text-dim);
}
.emptystate .icon { color: var(--text-faint); margin-bottom: var(--space-3); }
.emptystate h3 { margin-bottom: var(--space-2); color: var(--text); }

/* ---------------- Auth ---------------- */

.authbody { display: grid; place-items: center; min-height: 100dvh; padding: var(--space-4); }
.auth { width: 100%; max-width: 420px; }
.auth__card {
  padding: var(--space-6) var(--space-5);
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.auth__foot { margin-top: var(--space-4); text-align: center; font-size: 0.8rem; color: var(--text-faint); }
.auth h1 { font-size: 1.25rem; margin-bottom: var(--space-2); }
.auth__lede { color: var(--text-dim); font-size: 0.9rem; margin-bottom: var(--space-5); }

.divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-5) 0;
  color: var(--text-faint);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.divider::before, .divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border-soft);
}

.qr-panel {
  display: grid;
  place-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  background: #fff; /* QR needs a light quiet zone to scan reliably */
  border-radius: var(--radius-sm);
}
.secret-readout {
  font-family: var(--mono);
  font-size: 0.85rem;
  letter-spacing: 0.08em;
  word-break: break-all;
  padding: var(--space-3);
  background: var(--bg-2);
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-dim);
}

/* ---------------- Mounted module frame ---------------- */

/* On a tool page the shell stops being a scrolling document and becomes a
   fixed frame: topbar and sidebar hold still, and only the module scrolls.
   Without this the page would grow two scrollbars — the outer document's and
   the frame's — and the sidebar would drift out of view. */
.body--module { overflow: hidden; }
.body--module .app { height: 100dvh; }
.body--module .main { padding: 0; overflow: hidden; }
.body--module .sidenav { overflow-y: auto; }

.module-mount { height: 100%; }
.module-frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  /* The module paints its own background; matching it here stops a flash of
     shell background while the frame document loads. */
  background: var(--bg);
}

/* Standalone framed documents (the not-built-yet placeholder) still need the
   page padding the shell would otherwise have provided. */
.framebody { padding: var(--space-6) var(--space-4); }

/* ==================================================================
   Utilities

   These exist because the portal runs under `style-src 'self'` with no
   'unsafe-inline'. A style="" attribute in the markup is blocked by the
   browser, so spacing that would otherwise be written inline lives here.
   ================================================================== */

.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mt-6 { margin-top: var(--space-6); }
.mt-7 { margin-top: var(--space-7); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-5 { margin-bottom: var(--space-5); }

.center { text-align: center; }
.muted { color: var(--text-dim); font-size: 0.9rem; }
.small { font-size: 0.85rem; }
.push-right { margin-left: auto; }

.wrap--narrow { max-width: 720px; }
.wrap--form { max-width: 620px; margin-top: 12vh; }

.row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
}

.field-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

.input--inline { width: 88px; min-height: 36px; }
.select--inline { width: auto; min-height: 36px; }

.ok-tick {
  color: var(--green);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.off-note { color: var(--text-faint); }

.auth-badge {
  display: inline-grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--yellow-soft);
  color: var(--yellow);
  margin-bottom: var(--space-4);
}

/* ==================================================================
   Motion & print
   ================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .sidenav { transition: none; }
}

@media print {
  .topbar, .sidenav, .drawer-scrim, .skip-link { display: none !important; }
  .app { display: block; }
  .main { padding: 0; }
}

/* 404 numeral: large, tight, and low-contrast so it reads as texture
   rather than competing with the message. */
.notfound__code {
  font-family: var(--mono);
  font-size: 3.5rem;
  font-weight: 600;
  letter-spacing: var(--track-display);
  line-height: 1;
  color: var(--text-faint);
  opacity: 0.5;
  margin-bottom: var(--space-4);
  font-variant-numeric: tabular-nums;
}
