/* ─────────────────────────────────────────────────────────────────────────
   SinoSource Portal — visual polish layer (loaded last, 2026-08-17)
   Goals: solid (never translucent) surfaces, calmer typography, real button
   affordances, gentle motion, better focus states. Dark + light mode aware.
   ───────────────────────────────────────────────────────────────────────── */

/* ── Typography ─────────────────────────────────────────────────────────── */
/* Brand typeface, shape and motion tokens now live once in portal.css :root.
   This layer must not redeclare them. */
body { letter-spacing: .002em; }
.panel-header h2 {
   font-size: 21px;
   letter-spacing: -.02em;
   line-height: 1.25;
}
.panel-header p {
   font-size: 13.5px;
   line-height: 1.65;
   max-width: 72ch;
}

/* ── Solid surfaces — no see-through cards ──────────────────────────────── */
.decision-card,
.portal-monitor-record {
   background: linear-gradient(160deg, #20202b 0%, #1b1b25 100%);
   border: 1px solid rgba(255, 255, 255, .09);
   box-shadow: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 12px 32px rgba(0, 0, 0, .28);
}
.portal-update-card {
   background: #1c1c26;
   border: 1px solid rgba(255, 255, 255, .08);
}
.portal-update-card:hover {
   background: #212130;
   border-color: rgba(240, 165, 30, .35);
}
.portal-update-filter {
   background: #20202b;
   border: 1px solid rgba(255, 255, 255, .1);
}
.decision-empty {
   background: #191922;
   border: 1px dashed rgba(255, 255, 255, .14);
}
html.light-mode .decision-card,
html.light-mode .portal-monitor-record {
   background: linear-gradient(160deg, #ffffff 0%, #f7f7fa 100%);
   border-color: rgba(15, 18, 30, .1);
   box-shadow: 0 1px 0 rgba(255, 255, 255, .7) inset, 0 10px 26px rgba(20, 24, 40, .08);
}
html.light-mode .portal-update-card { background: #ffffff; border-color: rgba(15, 18, 30, .1); }
html.light-mode .portal-update-card:hover { background: #fbf8f2; border-color: rgba(200, 138, 20, .45); }
html.light-mode .portal-update-filter { background: #ffffff; border-color: rgba(15, 18, 30, .14); }
html.light-mode .decision-empty { background: #f4f4f8; border-color: rgba(15, 18, 30, .16); }

/* Interactive cards signal interactivity. */
.portal-update-card,
.decision-card--managed {
   transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
.portal-update-card:hover { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(0, 0, 0, .3); }
html.light-mode .portal-update-card:hover { box-shadow: 0 14px 30px rgba(20, 24, 40, .12); }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn { transition: transform .15s ease, box-shadow .15s ease, filter .15s ease, background .15s ease, border-color .15s ease, color .15s ease; }
.btn--gold {
   background: linear-gradient(135deg, #ffca52, #f0a51e 58%, #e2951a);
   box-shadow: 0 8px 22px rgba(240, 165, 30, .26);
}
.btn--gold:hover { transform: translateY(-2px); filter: brightness(1.05); box-shadow: 0 12px 30px rgba(240, 165, 30, .34); }
.btn--gold:active { transform: translateY(0); }
.btn--ghost:hover { border-color: rgba(240, 165, 30, .45); }
.btn:focus-visible, button:focus-visible, a:focus-visible,
.portal-input:focus-visible, .search-input:focus-visible, select:focus-visible {
   outline: 2px solid rgba(245, 188, 69, .8);
   outline-offset: 2px;
}
.btn:disabled { opacity: .5; transform: none; box-shadow: none; }

/* Card actions.
 *
 * These were gold-filled boxes — head and empty state alike — which put fifteen
 * competing gold buttons on the dashboard at once. Six identical cards each
 * wearing two identical gold pills is what made the cockpit read as one
 * template stamped out repeatedly rather than six different answers.
 *
 * Gold is the strongest signal this interface has. Spending it on every
 * navigation link leaves nothing to say "this is the thing that needs you",
 * which is the job it does in the follow-ups strip and the mode toggle.
 *
 * So: two tiers. A card head is navigation — quiet text that gains its arrow
 * and its colour on hover. An empty state's action is the one real thing to do
 * in that card, so it keeps a visible button, outlined rather than filled. */
.decision-card__head button {
   padding: 5px 2px;
   border: 0;
   border-radius: 0;
   background: none;
   color: var(--mid);
   font-weight: 650;
   transition: color .15s ease;
}
.decision-card__head button::after {
   content: '→';
   margin-left: 5px;
   opacity: 0;
   transform: translateX(-3px);
   display: inline-block;
   transition: opacity .15s ease, transform .15s ease;
}
.decision-card__head button:hover,
.decision-card__head button:focus-visible {
   text-decoration: none;
   color: var(--gold-t);
}
.decision-card__head button:hover::after,
.decision-card__head button:focus-visible::after { opacity: 1; transform: none; }

.decision-empty button {
   padding: 7px 13px;
   border-radius: var(--r-sm);
   border: 1px solid var(--border-m, rgba(255, 255, 255, .13));
   background: rgba(255, 255, 255, .022);
   color: var(--bright);
   transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.decision-empty button:hover {
   text-decoration: none;
   color: var(--gold-t);
   border-color: rgba(240, 165, 30, .45);
   background: rgba(240, 165, 30, .08);
}
html.light-mode .decision-card__head button { color: rgba(15, 18, 30, .58); }
html.light-mode .decision-empty button {
   background: rgba(15, 18, 30, .03);
   border-color: rgba(15, 18, 30, .14);
   color: #1A1D2A;
}

/* ── Inputs ─────────────────────────────────────────────────────────────── */
.portal-input, .search-input {
   transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.portal-input:focus, .search-input:focus {
   border-color: rgba(240, 165, 30, .6) !important;
   box-shadow: 0 0 0 3px rgba(240, 165, 30, .14);
}

/* ── Navigation ─────────────────────────────────────────────────────────── */
.nav-item, .mobile-nav-btn { transition: background .15s ease, color .15s ease, transform .15s ease; }
.nav-item:hover { background: rgba(255, 255, 255, .05); }
.nav-item.active {
   background: linear-gradient(90deg, rgba(240, 165, 30, .16), rgba(240, 165, 30, .05));
   box-shadow: inset 3px 0 0 var(--gold);
}
html.light-mode .nav-item:hover { background: rgba(15, 18, 30, .05); }
html.light-mode .nav-item.active { background: linear-gradient(90deg, rgba(200, 138, 20, .14), rgba(200, 138, 20, .04)); }

/* ── Panel entrance motion ──────────────────────────────────────────────── */
.panel.active { animation: sino-panel-in .32s cubic-bezier(.22, .9, .3, 1) both; }
@keyframes sino-panel-in {
   from { opacity: 0; transform: translateY(10px); }
   to   { opacity: 1; transform: none; }
}

/* ── Scrollbars ─────────────────────────────────────────────────────────
   Moved to css/scrollbars.css, which is loaded on every page rather than only
   where .portal-body applies, and which also clears the track and the arrow
   buttons. Styling the thumb alone — what used to live here — left Chrome
   drawing its native channel and arrows around it, so the scrollbar still
   looked like an operating-system control everywhere it appeared. Two partial
   definitions is how that survived; there is now one. */

/* ── Guide panel ────────────────────────────────────────────────────────── */
.guide-hero {
   background: linear-gradient(150deg, rgba(240, 165, 30, .14), rgba(240, 165, 30, .03) 55%, transparent);
   border: 1px solid rgba(240, 165, 30, .28);
   border-radius: 18px;
   padding: 26px 26px 22px;
   margin-bottom: 22px;
}
html.light-mode .guide-hero { background: linear-gradient(150deg, rgba(200, 138, 20, .1), rgba(200, 138, 20, .02) 60%, transparent); }
.guide-hero h3 { margin: 0 0 8px; font-size: 19px; letter-spacing: -.015em; color: var(--bright); }
.guide-hero p { margin: 0; color: var(--mid); font-size: 13.5px; line-height: 1.65; max-width: 70ch; }
.guide-steps { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; margin-bottom: 22px; }
.guide-step {
   background: linear-gradient(160deg, #20202b 0%, #1b1b25 100%);
   border: 1px solid rgba(255, 255, 255, .09);
   border-radius: 16px;
   padding: 18px;
   box-shadow: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 10px 26px rgba(0, 0, 0, .24);
}
html.light-mode .guide-step { background: #ffffff; border-color: rgba(15, 18, 30, .1); box-shadow: 0 8px 22px rgba(20, 24, 40, .07); }
.guide-step__num {
   display: inline-grid;
   place-items: center;
   width: 26px; height: 26px;
   border-radius: 8px;
   background: linear-gradient(135deg, #ffca52, #e2951a);
   color: #1a1305;
   font-size: 12.5px; font-weight: 800;
   margin-bottom: 10px;
}
.guide-step h4 { margin: 0 0 6px; font-size: 14.5px; color: var(--bright); letter-spacing: -.01em; }
.guide-step p { margin: 0; font-size: 12.8px; line-height: 1.6; color: var(--mid); }
.guide-step ul { margin: 8px 0 0; padding-left: 16px; font-size: 12.8px; line-height: 1.65; color: var(--mid); }
.guide-step li { margin-bottom: 3px; }
.guide-step__cta { margin-top: 12px; }
.guide-tips {
   background: #191922;
   border: 1px solid rgba(255, 255, 255, .09);
   border-radius: 16px;
   padding: 18px 20px;
}
html.light-mode .guide-tips { background: #f4f4f8; border-color: rgba(15, 18, 30, .1); }
.guide-tips h4 { margin: 0 0 10px; font-size: 14px; color: var(--bright); }
.guide-tips li { font-size: 13px; line-height: 1.7; color: var(--mid); margin-bottom: 4px; }
.guide-tips strong { color: var(--bright); font-weight: 650; }

@media (prefers-reduced-motion: reduce) {
   .panel.active { animation: none; }
   .btn, .portal-update-card, .nav-item { transition: none; }
}

/* ============================================================================
   RED THREAD — one typeface, one shape language, one motion signature.
   Added after the audit of 2026-08-17. These rules normalise the 22 button
   families, 27 radii and 3 transition speeds that had accumulated, without
   rewriting panel markup. Tokens live in portal.css :root.
   ============================================================================ */

/* 1. Controls must not opt out of the brand typeface.
      .nav-item (the whole sidebar) declared no font-family and fell back to the
      user-agent default. This is the single most visible fix in this file. */
button,
input,
select,
textarea,
.btn,
.nav-item,
.mobile-nav-btn,
.finder-chip,
.pipeline-tab,
.auth-tab {
   font-family: var(--font);
}

/* 2. One shape language. Controls and pills only; cards keep their own radius. */
.btn,
.nav-item,
.finder-chip,
.sourcer-ex-btn,
.sr-copy-btn,
.archive-filter-btn,
.goal-filter-btn,
.reg-niche-btn,
.reg-view-btn,
.pipeline-tab,
.portal-btn,
.report-notes__toggle {
   border-radius: var(--r-sm);
}
.plan-pill,
[class*="badge"],
[class*="chip"]:not(.finder-chip) {
   border-radius: var(--r-pill);
}

/* 3. One motion signature, and the two states that were missing.
      63 hover rules existed against 3 focus-visible and 2 active. */
.btn,
.nav-item,
.mobile-nav-btn,
.finder-chip,
.pipeline-tab,
.sourcer-ex-btn,
.sr-copy-btn,
.archive-filter-btn,
.goal-filter-btn,
.reg-niche-btn,
.portal-btn {
   transition: background-color var(--motion) var(--ease),
               border-color var(--motion) var(--ease),
               color var(--motion) var(--ease),
               transform var(--motion) var(--ease),
               box-shadow var(--motion) var(--ease);
}

/* Physical press feedback: the main reason the product felt untactile. */
.btn:active,
.nav-item:active,
.mobile-nav-btn:active,
.finder-chip:active,
.pipeline-tab:active,
.sourcer-ex-btn:active,
.sr-copy-btn:active,
.archive-filter-btn:active,
.goal-filter-btn:active,
.reg-niche-btn:active,
.portal-btn:active {
   transform: translateY(1px) scale(.985);
}

/* Keyboard affordance on every interactive element. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="button"]:focus-visible,
summary:focus-visible {
   outline: 2px solid var(--gold);
   outline-offset: 2px;
   border-radius: var(--r-sm);
}

/* 4. Gold is the status colour. The premium plan badge rendered lavender,
      which appears nowhere else in the brand. */
.plan-pill--premium,
.plan-pill--managed {
   color: #09090C;
   background: linear-gradient(135deg, var(--gold), #FFD277);
   border: 1px solid rgba(240, 165, 30, .55);
   box-shadow: 0 2px 10px rgba(240, 165, 30, .28);
   font-weight: 800;
   letter-spacing: .04em;
}

@media (prefers-reduced-motion: reduce) {
   .btn, .nav-item, .mobile-nav-btn, .finder-chip, .pipeline-tab,
   .sourcer-ex-btn, .sr-copy-btn, .archive-filter-btn, .goal-filter-btn,
   .reg-niche-btn, .portal-btn { transition: none; }
   .btn:active, .nav-item:active, .portal-btn:active { transform: none; }
}

/* 5. Never assert a plan before it is known.
      The markup used to ship "Plan: Basic" and "Welcome, Client", so a paying
      client saw a wrong plan on every load until the account call resolved.
      The pill now ships neutral; initPortal() replaces the class wholesale,
      which reveals it with the correct tier. */
.plan-pill--pending {
   visibility: hidden;
}

/* Fold the last control-radius stragglers onto the token. */
/* .decision-card__head button is deliberately absent: it is a text link now,
   not a control, and a radius on it only rounds the focus outline oddly. */
.btn--full,
.ft-logout,
.ai-drawer__send,
.decision-empty button {
   border-radius: var(--r-sm);
}

/* ============================================================================
   Sidebar groups — expandable per group.
   Replaces the single "Show all tools (20 more)" disclosure, which hid 20 of 29
   destinations behind one opaque control. Every group is now labelled and
   visible; the client opens the ones they use. State persists per group.
   ============================================================================ */
.sidebar-section-label {
   display: flex;
   align-items: center;
   justify-content: space-between;
   gap: 8px;
   width: 100%;
   padding: 7px 10px;
   margin: 0 0 2px;
   background: none;
   border: 0;
   cursor: pointer;
   text-align: left;
   font: inherit;
   font-size: 12.5px;
   font-weight: 700;
   letter-spacing: .005em;
   /* portal.css sets uppercase on this class; override it explicitly. */
   text-transform: none;
   color: var(--mid);
   border-radius: var(--r-sm);
   transition: color var(--motion) var(--ease), background-color var(--motion) var(--ease);
}
.sidebar-section-label:hover {
   color: var(--mid);
   background: rgba(255, 255, 255, .04);
}
html.light-mode .sidebar-section-label:hover { background: rgba(15, 18, 30, .05); }

.sidebar-section-chev {
   flex-shrink: 0;
   opacity: .65;
   transition: transform var(--motion) var(--ease);
}
.sidebar-section-label[aria-expanded="false"] .sidebar-section-chev {
   transform: rotate(-90deg);
}

/* A collapsed group must not keep its items in the tab order. */
.sidebar-section__items[hidden] { display: none; }

/* Expand / collapse motion. Height is driven from JS (measured), opacity and
   the small lift are pure CSS. Items settle in with a light stagger so the
   group unfolds rather than snapping. */
.sidebar-section__items {
   overflow: hidden;
   opacity: 1;
}
.sidebar-section__items.is-animating {
   transition: max-height 240ms var(--ease), opacity 200ms var(--ease);
}
.sidebar-section__items.is-animating:not(.is-open) {
   opacity: 0;
}
.sidebar-section__items.is-animating.is-open {
   opacity: 1;
}
.sidebar-section__items.is-animating.is-open .nav-item {
   animation: sino-navitem-in 260ms var(--ease) both;
}
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(1) { animation-delay: 20ms; }
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(2) { animation-delay: 45ms; }
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(3) { animation-delay: 70ms; }
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(4) { animation-delay: 95ms; }
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(5) { animation-delay: 120ms; }
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(6) { animation-delay: 145ms; }
.sidebar-section__items.is-animating.is-open .nav-item:nth-child(n+7) { animation-delay: 170ms; }

@keyframes sino-navitem-in {
   from { opacity: 0; transform: translateX(-6px); }
   to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
   .sidebar-section__items.is-animating { transition: none; }
   .sidebar-section__items.is-animating.is-open .nav-item { animation: none; }
}

/* The group holding the current panel reads as active even when scanning fast. */
.sidebar-section:has(.nav-item.active) > .sidebar-section-label { color: var(--gold-t); }

@media (prefers-reduced-motion: reduce) {
   .sidebar-section-chev, .sidebar-section-label { transition: none; }
}

/* ── Help & feedback panel ───────────────────────────────────────────────── */
/* Reachable on every plan. Built on the portal's own tokens so it also lands
   correctly in light mode, where #portalApp redefines them. */

.help-call {
   display: flex;
   align-items: center;
   gap: 16px;
   flex-wrap: wrap;
   background: linear-gradient(135deg, rgba(240, 165, 30, .09) 0%, rgba(240, 165, 30, .03) 100%);
   border: 1px solid rgba(240, 165, 30, .22);
   border-radius: var(--radius-lg, 16px);
   padding: 18px 20px;
   margin-bottom: 26px;
}
.help-call__icon {
   flex: none;
   width: 42px;
   height: 42px;
   border-radius: 50%;
   display: flex;
   align-items: center;
   justify-content: center;
   background: rgba(240, 165, 30, .12);
   border: 1px solid rgba(240, 165, 30, .26);
   color: var(--gold-t, #F5BC45);
}
.help-call__text {
   flex: 1 1 320px;
   min-width: 0;
}
.help-call__text strong {
   display: block;
   font-size: 14.5px;
   color: var(--bright);
   margin-bottom: 3px;
}
.help-call__text span {
   font-size: 13px;
   color: var(--mid);
   line-height: 1.55;
}
.help-call__btn {
   flex: none;
}

.help-modes {
   display: flex;
   gap: 8px;
   flex-wrap: wrap;
   margin-bottom: 16px;
}
.help-mode {
   display: inline-flex;
   align-items: center;
   gap: 7px;
   border: 1px solid var(--border);
   background: var(--bg-card);
   color: var(--mid);
   font-family: inherit;
   font-size: 13px;
   font-weight: 600;
   padding: 9px 14px;
   border-radius: var(--r-pill, 999px);
   cursor: pointer;
   transition: color var(--motion) var(--ease), border-color var(--motion) var(--ease),
      background var(--motion) var(--ease);
}
.help-mode:hover {
   color: var(--bright);
   border-color: var(--border-m);
}
.help-mode.is-on {
   color: var(--gold-t, #F5BC45);
   background: var(--gold-pale);
   border-color: rgba(240, 165, 30, .4);
}

/* The form already carries .help-contact from portal.css; these override the
   40px top margin and narrow max-width it uses in its standalone position. */
.help-compose .help-contact {
   max-width: 620px;
   margin-top: 0;
   background: var(--bg-card);
   border: 1px solid var(--border);
   border-radius: var(--radius-lg, 16px);
   padding: 22px 24px;
}
.help-reply-to {
   max-width: 320px;
}
.help-send {
   display: flex;
   align-items: center;
   gap: 14px;
   flex-wrap: wrap;
}
.help-send__note {
   font-size: 12.5px;
   color: var(--dim);
   line-height: 1.5;
}
.help-send__note--bad {
   color: var(--red, #D42B1E);
}
html.light-mode .help-send__note--bad {
   color: #B82216;
}

.help-faq-title {
   font-family: var(--font-display);
   font-size: 16px;
   font-weight: 700;
   color: var(--bright);
   margin: 38px 0 14px;
}

@media (max-width: 640px) {
   .help-call { padding: 16px; }
   .help-call__btn { width: 100%; justify-content: center; }
   .help-compose .help-contact { padding: 18px 16px; }
}

@media (prefers-reduced-motion: reduce) {
   .help-mode { transition: none; }
}

/* ── Plan chip ───────────────────────────────────────────────────────────
   Three lines of text at 10px vertical padding inside a 16px corner radius:
   the copy runs into the curve at top and bottom, which is what reads as
   crammed. The radius is right for the sidebar; the padding has to answer it.

   Also given a type hierarchy. "Your plan", the plan name and the niche were
   three near-equal lines competing for the same attention; the label is the
   least important of the three and now looks it. */
.plan-chip {
   padding: 14px 16px 15px;
   line-height: 1.35;
}
.plan-chip__label {
   margin-bottom: 5px;
   font-size: 9.5px;
   font-weight: 700;
   letter-spacing: .13em;
   text-transform: uppercase;
   color: var(--dim);
}
.plan-chip__name {
   font-size: 14px;
   letter-spacing: -.015em;
   /* €449/mo sits inside this line, so the digits should not shift width. */
   font-variant-numeric: tabular-nums;
}
.plan-chip__niche {
   margin-top: 4px;
   font-size: 11.5px;
   color: var(--mid);
}
