/*
 * Jug Scope — Shop Portal styles (WS-J-U3).
 *
 * Jony §4.2: this file is a SIBLING of admin-console/styles.css — same token
 * NAMES, same 4/8/12/16/24/32 spacing, same 8/12/16/999 radii, same 1180px
 * content width, same table-kills-JSON primitive. It is never an import of
 * that file and this unit never touches admin-console/.
 *
 * THE THREE DELIBERATE DIVERGENCES FROM THE OPERATOR CONSOLE (§4.2):
 *   1. Light AND dark, not dark-only. Same token names in both, dark declared
 *      first as the default. The portal is opened in a bright office and in a
 *      hangar; the console is opened by one operator.
 *   2. No operator chrome. No env badge, no lock pill, no TOTP, no standing
 *      danger-zone card. Destructive acts get proportional inline friction on
 *      their own row (WS-J-U4's), not a red gradient zone.
 *   3. A money panel that cannot be clicked (§7.9) — .panel-static below has
 *      no hover state, no cursor change and no click target.
 *
 * CONTRAST: every foreground/background pair used for text is >= 4.5:1 in BOTH
 * themes, measured from rendered styles rather than assumed from the palette.
 * See docs/plans/PORTAL-WAVE2-SHELL.md for the measured table.
 */

/* ── Dark: the default declaration (Jony §4.2 divergence 1) ───────────────── */
:root{
  --bg:#0d0f13;
  --bg-side:#0a0c10;
  --bg-elev:#161a21;
  --bg-elev2:#1d222c;
  --bg-hover:#20262f;
  --border:#282e39;
  --border-soft:#20242d;

  --text:#e7eaf0;
  --text-2:#aab2c0;
  --muted:#8b93a2;

  --accent:#4f8cff;
  --accent-hover:#6ba0ff;
  --accent-dim:#16233d;
  /* Text ON the accent fill. MEASURED, not assumed: white on #4f8cff is
     3.22:1 — it failed the 4.5 floor on the primary button, which is the one
     control every session starts with. Dark ink on the same fill measures
     5.88:1. This is exactly the "verified against the actual token pairs, not
     assumed from the palette" clause in §7.11, and the palette lost. */
  --on-accent:#06121f;
  --safe:#33c076;   --safe-dim:#10301f;
  --warn:#e6a93c;   --warn-dim:#2e2410;
  --danger:#f0575c; --danger-dim:#2c1417;
  --info:#4f8cff;   --info-dim:#16233d;

  --focus:#8ab4ff;

  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --r-s:8px; --r-m:12px; --r-l:16px; --r-pill:999px;
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-6:24px; --sp-8:32px;
  --content:1180px;
  --shadow:0 1px 0 rgba(255,255,255,.02) inset, 0 8px 24px -12px rgba(0,0,0,.6);
  color-scheme: dark light;
}

/* ── Light: same token names, no new roles ───────────────────────────────── */
@media (prefers-color-scheme: light){
  :root{
    --bg:#f4f6f9;
    --bg-side:#e9edf3;
    --bg-elev:#ffffff;
    --bg-elev2:#f0f3f8;
    --bg-hover:#e2e7ef;
    --border:#c9d0da;
    --border-soft:#dde2ea;

    --text:#14171c;
    --text-2:#3d4450;
    --muted:#59616e;

    --accent:#1857c4;
    --accent-hover:#12459c;
    --accent-dim:#e4ecfb;
    --on-accent:#ffffff;   /* measured 6.55:1 on #1857c4 */
    --safe:#12653c;   --safe-dim:#e2f3ea;
    --warn:#7a4d00;   --warn-dim:#faf0dc;
    --danger:#a3231c; --danger-dim:#fbe6e5;
    --info:#1857c4;   --info-dim:#e4ecfb;

    --focus:#12459c;

    --shadow:0 1px 2px rgba(16,24,40,.06), 0 8px 24px -14px rgba(16,24,40,.35);
    color-scheme: light dark;
  }
}

*{box-sizing:border-box;}
html,body{margin:0;padding:0;min-height:100%;}
body{
  background:var(--bg); color:var(--text);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Inter,sans-serif;
  font-size:15px; line-height:1.5; -webkit-font-smoothing:antialiased;
  /* §7.11: the page body never scrolls horizontally. Tables scroll inside
     their own .tbl-wrap container instead. */
  overflow-x:hidden;
}
button,input,select,textarea{font-family:inherit; font-size:inherit;}
.mono{font-family:var(--mono);}
.muted{color:var(--muted);}
.sec2{color:var(--text-2);}
.hidden{display:none !important;}
.nowrap{white-space:nowrap;}

/* §7.11: a VISIBLE focus ring on every interactive element, in visual order.
   Never `outline: none`. :focus-visible plus a fallback for older engines. */
a:focus-visible,
button:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible{
  outline:3px solid var(--focus);
  outline-offset:2px;
  border-radius:var(--r-s);
}

a{color:var(--accent);}
a:hover{color:var(--accent-hover);}

/* Skip link — keyboard order starts here, not in the middle of the nav. */
.skip{
  position:absolute; left:var(--sp-2); top:-64px; z-index:50;
  background:var(--bg-elev); color:var(--text); border:1px solid var(--border);
  border-radius:var(--r-s); padding:var(--sp-2) var(--sp-3);
  transition:top .12s ease;
}
.skip:focus{top:var(--sp-2);}

/* ============ APP SHELL ============ */
.app{display:grid; grid-template-columns:248px 1fr; min-height:calc(100vh - var(--tier-band-h, 0px));}
/* W0b — signed in, holding no memberships. There are no sections to navigate,
   so the sidebar is not rendered AND its column is not reserved. Hiding the
   aside without collapsing the column leaves the page's only content squeezed
   into whatever is left, which is how an honest empty state reads as a broken
   one. */
.app.no-side{grid-template-columns:1fr;}

.side{
  background:var(--bg-side);
  border-right:1px solid var(--border-soft);
  display:flex; flex-direction:column;
  position:sticky; top:var(--tier-band-h, 0px); height:calc(100vh - var(--tier-band-h, 0px)); overflow-y:auto;
}
.brand{padding:var(--sp-6) var(--sp-4) var(--sp-3);}
.brand-name{font-weight:700; font-size:17px; letter-spacing:-.01em; margin:0;}
.brand-sub{font-size:12px; color:var(--muted); margin:var(--sp-1) 0 0;}
/* Shop switcher: a <select>, not a mode toggle (§7.3) — it changes WHICH
   shop's data is on screen and nothing about who the user is. */
.brand-switch{margin-top:var(--sp-3);}
.brand-switch label{display:block; font-size:12px; color:var(--muted); margin-bottom:var(--sp-1);}
select.shop-switcher{
  width:100%; padding:var(--sp-2) var(--sp-3);
  background:var(--bg-elev2); color:var(--text);
  border:1px solid var(--border); border-radius:var(--r-s);
}

.nav{display:flex; flex-direction:column; gap:2px; padding:var(--sp-2) var(--sp-2) var(--sp-6);}
.nav-item{
  display:block; width:100%; text-align:left;
  padding:var(--sp-2) var(--sp-3);
  background:transparent; color:var(--text-2);
  border:1px solid transparent; border-radius:var(--r-s);
  cursor:pointer;
}
.nav-item:hover{background:var(--bg-hover); color:var(--text);}
.nav-item[aria-current="page"]{
  background:var(--accent-dim); color:var(--text);
  border-color:var(--border); font-weight:600;
}

.main{display:flex; flex-direction:column; min-width:0;}
.topbar{
  display:flex; align-items:center; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4);
  border-bottom:1px solid var(--border-soft);
  background:var(--bg);
  position:sticky; top:var(--tier-band-h, 0px); z-index:10;
}
.hamb{
  display:none;
  background:var(--bg-elev); color:var(--text);
  border:1px solid var(--border); border-radius:var(--r-s);
  padding:var(--sp-2) var(--sp-3); cursor:pointer;
}
.crumb{font-weight:600;}
.topbar-right{margin-left:auto; display:flex; align-items:center; gap:var(--sp-3);}
.who{font-size:13px; color:var(--muted);}

.view{
  width:100%; max-width:var(--content);
  margin:0 auto; padding:var(--sp-6) var(--sp-4) var(--sp-8);
  min-width:0;
}

/* ============ PRIMITIVES ============ */
h1{font-size:24px; letter-spacing:-.015em; margin:0 0 var(--sp-2);}
h2{font-size:18px; letter-spacing:-.01em; margin:0 0 var(--sp-2);}
h3{font-size:15px; margin:0 0 var(--sp-2);}
p{margin:0 0 var(--sp-3);}

.card{
  background:var(--bg-elev); border:1px solid var(--border);
  border-radius:var(--r-m); padding:var(--sp-4);
  box-shadow:var(--shadow);
}
.card + .card{margin-top:var(--sp-4);}

/* §7.9 / §4.2 divergence 3 — a panel that CANNOT be clicked. No hover state,
   no cursor change, no click target. Stated here as a class so the property is
   inspectable rather than a promise in prose. */
.panel-static{cursor:default;}
.panel-static *{cursor:default;}

.btn{
  display:inline-block;
  padding:var(--sp-2) var(--sp-4); min-height:40px;
  background:var(--bg-elev2); color:var(--text);
  border:1px solid var(--border); border-radius:var(--r-s);
  cursor:pointer;
}
.btn:hover{background:var(--bg-hover);}
.btn[disabled]{opacity:.55; cursor:default;}
.btn-primary{background:var(--accent); border-color:var(--accent); color:var(--on-accent);}
.btn-primary:hover{background:var(--accent-hover); border-color:var(--accent-hover);}
.btn-primary[disabled]{background:var(--accent); border-color:var(--accent);}

.tiles{display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-4);}
.tile{
  background:var(--bg-elev); border:1px solid var(--border);
  border-radius:var(--r-m); padding:var(--sp-4);
}
.tile-label{font-size:13px; color:var(--muted); margin:0 0 var(--sp-1);}
/* §7.11: no monetary or count value truncates at any width. */
.tile-value{font-size:28px; font-weight:650; letter-spacing:-.02em;
  overflow-wrap:normal; white-space:nowrap; text-overflow:clip;}
.tile-note{font-size:13px; color:var(--text-2); margin:var(--sp-2) 0 0;}

/* Table primitive — sticky uppercase headers, hairline dividers,
   right-aligned monospace for dates (§7.4). */
.tbl-wrap{overflow-x:auto;}
table.tbl{width:100%; border-collapse:collapse; font-size:14px;}
table.tbl th{
  position:sticky; top:var(--tier-band-h, 0px);
  text-align:left; text-transform:uppercase; letter-spacing:.06em;
  font-size:11px; color:var(--muted);
  background:var(--bg-elev);
  padding:var(--sp-2) var(--sp-3);
  border-bottom:1px solid var(--border);
}
table.tbl td{
  padding:var(--sp-3); border-bottom:1px solid var(--border-soft);
  vertical-align:top;
}
table.tbl td.num, table.tbl th.num{text-align:right; font-family:var(--mono);}

/* States. ERROR carries the API code AND human help text, never a bare number
   (§7.3). PARTIAL renders an em dash for the tile that failed. */
.state{border-radius:var(--r-m); padding:var(--sp-4); border:1px solid var(--border);}
.state.err{background:var(--danger-dim); border-color:var(--danger); color:var(--text);}
.state.warn{background:var(--warn-dim); border-color:var(--warn); color:var(--text);}
.state.info{background:var(--info-dim); border-color:var(--info); color:var(--text);}
.state h2{margin-top:0;}
.err-code{font-family:var(--mono); font-size:12px; color:var(--text-2);}

.skel{
  background:var(--bg-elev2); border-radius:var(--r-s);
  height:1em; width:60%;
}

/* The shared aria-live region. It sits OUTSIDE #portal-view (which the router
   clears on every navigation) so it is never removed and re-inserted. */
.live{
  width:100%; max-width:var(--content);
  margin:var(--sp-4) auto calc(-1 * var(--sp-3));
  padding:0 var(--sp-4);
  color:var(--text-2);
}
.live:empty{display:none;}

.hint{color:var(--text-2); font-size:14px;}
.small{font-size:13px;}

/* Sign-in surfaces (W0 on login.html, and the shell's signed-out gate). */
.wrap{
  max-width:520px; margin:0 auto;
  padding:var(--sp-8) var(--sp-4);
}
.card-auth{text-align:left;}
.card-auth h1{margin-bottom:var(--sp-3);}

/* ============ TIER IDENTITY (staging and beta only) ============ */

/*
 * SR-3: PRODUCTION RENDERS NONE OF THIS. Every rule below requires the
 * `.tier-band` or `.tier-lock` class, which no production node ever carries,
 * or reads `--tier-band-h`, which is never defined on production and falls back
 * to its identity value of 0px. The band is created by JavaScript in
 * core/session.js and appears in no HTML file — a static node could not be
 * deleted by the emit's literal substitution, and a selector keyed on a
 * substituted literal would move with it and hide the band on the wrong tier.
 *
 * BOTH THEMES BY CONSTRUCTION, not by a second block: every colour below is a
 * token that the prefers-color-scheme: light block above already redefines, so
 * there is no dark-only value here to forget to mirror.
 *
 * Sticky rather than scrolling away: an identity notice that leaves the screen
 * is one the reader stops having. No animation, no transition, nothing that
 * draws attention to the notice instead of to what it says.
 */
.tier-band{
  position:sticky; top:0; z-index:31;
  width:100%;
  padding:var(--sp-2) var(--sp-4);
  font-size:13.5px; font-weight:600; letter-spacing:.01em;
  border-bottom:1px solid var(--border);
  background:var(--bg-elev2); color:var(--text);
}
.tier-band p{margin:0;}
.tier-band.beta{background:var(--accent-dim); color:var(--text); border-bottom-color:var(--accent);}
.tier-band.staging{background:var(--bg-elev2); color:var(--text-2); border-bottom-color:var(--border);}

/* MISMATCH. A body-level sibling of #portal-gate and #portal-app, which go
   inert; never a descendant of either. It carries no control, deliberately —
   there is no safe next action on this page. */
.tier-lock{
  position:fixed; inset:0; z-index:100;
  display:flex; align-items:center; justify-content:center;
  padding:var(--sp-4);
  background:var(--bg);
}
.tier-lock-card{max-width:560px;}
.tier-lock-card h2{margin:0 0 var(--sp-3);}
.tier-lock-card h2:focus-visible{outline:3px solid var(--focus); outline-offset:3px;}
.tier-lock-card p{margin:0 0 var(--sp-2);}
.tier-lock-card p:last-child{margin-bottom:0;}

/* ============ BREAKPOINTS (§7.11) ============ */

/* 880px — the sidebar collapses behind the hamburger (admin-console
   behaviour, inherited). */
@media (max-width:880px){
  .app{grid-template-columns:1fr;}
  .side{
    position:fixed; inset:0 auto 0 0; width:264px; z-index:30;
    /* The band sits above the drawer (z-index 31) and the drawer starts below
       it, so no drawer control can be occluded. Undefined on production, where
       this resolves to the 0px `inset` already set on the line above. */
    top:var(--tier-band-h, 0px);
    transform:translateX(-100%); transition:transform .18s ease;
    border-right:1px solid var(--border);
  }
  .side.open{transform:translateX(0);}
  .hamb{display:inline-block;}
}

/* 560px — tables become STACKED CARDS, one card per row, with the column
   headers as labels. A shop owner opens this on a phone from an email, and a
   horizontally scrolling table on a phone is a table nobody reads. */
@media (max-width:560px){
  .tiles{grid-template-columns:1fr;}
  .view{padding:var(--sp-4) var(--sp-3) var(--sp-8);}
  table.tbl thead{
    position:absolute; width:1px; height:1px; overflow:hidden;
    clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
  }
  table.tbl, table.tbl tbody, table.tbl tr, table.tbl td{display:block; width:100%;}
  table.tbl tr{
    background:var(--bg-elev); border:1px solid var(--border);
    border-radius:var(--r-m); padding:var(--sp-2); margin-bottom:var(--sp-3);
  }
  table.tbl td{
    border-bottom:1px solid var(--border-soft);
    display:flex; gap:var(--sp-3); justify-content:space-between;
  }
  table.tbl tr td:last-child{border-bottom:none;}
  table.tbl td::before{
    content:attr(data-label);
    font-size:11px; text-transform:uppercase; letter-spacing:.06em;
    color:var(--muted); flex:0 0 auto;
  }
  table.tbl td.num{text-align:left;}
}

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