/*
 * Fronset v1 layer for the portal, sign-up, waitlist and login pages.
 * Canonical copy: docs/brand/migration/portal-v1-layer.css
 * Installed as apps/service_portal/static/service_portal/css/fronset-v1.css and loaded
 * AFTER portal.css in every base template that loads portal.css:
 *   apps/service_portal/templates/service_portal/base.html
 *   apps/service_portal/templates/service_portal/signup/signup_base.html
 *   apps/waitlist/templates/waitlist/base.html
 *
 * It overrides; it does not replace. The portal's accessibility contract (one H1, skip link
 * first, landmarks, aria-current, chips carry text) lives in the templates and is untouched.
 *
 * ⚠ Element-level base rules are wrapped in :where(body.portal) so they carry the
 * specificity of the bare element. Written as `body.portal a` (0,1,2) they beat every
 * single-class component rule: an <a class="portal-btn"> got off-white text on lime
 * (about 1.1:1), nav links turned lime on hover, and `body.portal h2` beat
 * `.portal-headline__label`. Keep new base rules inside :where() for the same reason.
 *
 * ⚠ Two portal contracts constrain this file as much as portal.css
 * (apps/service_portal/tests/test_portal_stress.py, test_portal_accessibility.py):
 * never truncate text (no text-overflow, no line-clamp, no overflow:hidden on text —
 * long names wrap), and never draw an icon as inline <svg> (any <svg> on a portal page
 * requires a captioned table on that page).
 */

/* ============ base ============ */
:root { color-scheme: dark; }   /* checkboxes, date pickers, select pop-ups and scrollbars */
body.portal {
  background: var(--fs-bg);
  color: var(--fs-fg-2);
  font-family: var(--fs-font-sans);
  line-height: var(--fs-leading-body);
  -webkit-font-smoothing: antialiased;
}
:where(body.portal) a { color: var(--fs-link); text-decoration-color: var(--fs-link-underline); text-underline-offset: 3px; }
:where(body.portal) a:hover { color: var(--fs-link-hover); text-decoration-color: currentColor; }
:where(body.portal) :is(h1, h2, h3) { color: var(--fs-fg); letter-spacing: var(--fs-tracking-heading); }
:where(body.portal) strong { color: var(--fs-fg); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible, summary:focus-visible {
  outline: 2px solid var(--fs-lime); outline-offset: 2px;
}
.portal-skip-link:focus { background: var(--fs-lime); color: var(--fs-on-accent); }

/* Sign-up, login and waitlist put <main> directly in <body>, so they do not get the column
   the portal shell gets from .portal-body (max-width + padding). The child combinator keeps
   this off base.html, whose <main> sits inside .portal-body. */
body.portal > .portal-main { max-width: var(--fs-max-prose); margin: 0 auto; padding: var(--fs-space-7) var(--fs-gutter); }

/* ============ header ============ */
.portal-header { background: var(--fs-bg); border-bottom: 1px solid var(--fs-border); }
.portal-header__inner { min-height: var(--fs-header-h); }
.portal-brand { display: inline-flex; align-items: center; gap: var(--fs-space-3); color: var(--fs-fg); font-weight: 700; }
.portal-brand img { height: 26px; width: auto; display: block; }
.portal-tenant { color: var(--fs-fg-2); font-size: var(--fs-text-small); }
.portal-chip { border: 1px solid var(--fs-border-strong); border-radius: 999px; background: transparent; color: var(--fs-fg-2); font-size: var(--fs-text-micro); }
.portal-chip__label { color: var(--fs-muted); }
.portal-chip__value { color: var(--fs-fg); }

/* ============ nav ============ */
@media (min-width: 1024px) { .portal-nav { border-right: 1px solid var(--fs-border); } }  /* rail only on wide screens */
.portal-nav__group-label { font-family: var(--fs-font-mono); font-size: var(--fs-text-micro); color: var(--fs-muted); text-transform: uppercase; letter-spacing: var(--fs-tracking-label); }
.portal-nav__link { color: var(--fs-fg-2); text-decoration: none; border-radius: var(--fs-radius-sm); }
.portal-nav__link:hover { color: var(--fs-fg); background: var(--fs-hover); }
.portal-nav__link--active, .portal-nav__link[aria-current="page"] { color: var(--fs-fg); }  /* the lime rule comes from portal.css (border-bottom via --color-accent); do not add a second marker */

/* ============ page ============ */
.portal-page-title { color: var(--fs-fg); font-size: var(--fs-text-h1); letter-spacing: var(--fs-tracking-display); line-height: var(--fs-leading-tight); }
.portal-lede { color: var(--fs-fg-2); }
.portal-section > h2 { font-size: var(--fs-text-h3); }
.portal-note, .portal-maturity__note, .portal-footer__note, .portal-headline__note { color: var(--fs-muted); }
.portal-footer { border-top: 1px solid var(--fs-border); color: var(--fs-muted); }

/* ============ tables & numbers ============ */
.portal-table { border-collapse: collapse; }
.portal-table caption { color: var(--fs-muted); }
.portal-table thead th {
  font-family: var(--fs-font-mono); font-size: var(--fs-text-micro); font-weight: 500; color: var(--fs-muted);
  text-transform: uppercase; letter-spacing: var(--fs-tracking-label); border-bottom: 1px solid var(--fs-border-strong); background: transparent;
}
.portal-table td { border-bottom: 1px solid var(--fs-border); color: var(--fs-fg-2); }
.portal-table tbody tr:hover { background: var(--fs-hover); }
.portal-table .portal-num, .portal-kv .portal-num, .portal-money__amount, .portal-num {
  font-family: var(--fs-font-mono); font-variant-numeric: tabular-nums; color: var(--fs-fg);
}
.portal-money__basis { color: var(--fs-muted); font-size: var(--fs-text-micro); }
.portal-tm__slug { font-family: var(--fs-font-mono); color: var(--fs-muted); }
.portal-kv dt, .portal-tile dt { color: var(--fs-muted); font-size: var(--fs-text-small); }
.portal-kv dd, .portal-tile dd { color: var(--fs-fg); }
.portal-tile { background: var(--fs-surface); border: 1px solid var(--fs-border); border-radius: var(--fs-radius); }
.portal-headline { background: var(--fs-surface); border: 1px solid var(--fs-border); border-radius: var(--fs-radius); }
.portal-headline__label { font-family: var(--fs-font-mono); font-size: var(--fs-text-micro); color: var(--fs-muted); text-transform: uppercase; letter-spacing: var(--fs-tracking-label); }
.portal-headline__figure { font-family: var(--fs-font-mono); font-variant-numeric: tabular-nums; color: var(--fs-fg); }

/* ============ states (colour is a second channel; the label always carries the meaning) ============ */
/* Colours only: portal.css owns the 4px left edge. A `border` shorthand here would reset
   it for every state this block does not name. past_due is a WARNING, as portal.css and
   the component's own copy have it ("entitlements are unchanged while payment is retried"). */
.portal-state { background: var(--fs-surface); border-color: var(--fs-border); border-left-color: var(--fs-border-strong); border-radius: var(--fs-radius); color: var(--fs-fg-2); }
.portal-state__label { color: var(--fs-fg); }
.portal-state[data-portal-state="error"] { border-left-color: var(--fs-error); background: var(--fs-error-soft); }
.portal-state[data-portal-state="past_due"],
.portal-state[data-portal-state="permission_denied"] { border-left-color: var(--fs-warn); background: var(--fs-warn-soft); }
.portal-state[data-portal-state="exploring"] { border-left-color: var(--fs-info); background: var(--fs-info-soft); }
.portal-state[data-portal-state="insufficient_evidence"] { border-left-style: dashed; }
.portal-flag--on { color: var(--fs-fg); border-color: var(--fs-border-strong); }   /* --state-ok is --fs-fg after P1.6: a bright border otherwise */
.portal-flag--off { color: var(--fs-muted); }
.portal-badge--system, .portal-badge--own { border-color: var(--fs-border-strong); color: var(--fs-fg-2); }
.portal-checklist__mark { color: var(--fs-muted); }
.portal-checklist__item[data-ok="true"] .portal-checklist__mark { color: var(--fs-fg); }
.portal-checklist__todo { color: var(--fs-muted); }
.portal-checklist__item[data-ok="false"] .portal-checklist__todo { color: var(--fs-warn); }   /* only an OUTSTANDING step; the same class carries notes on done steps */

/* ============ notices ============ */
.portal-notice { background: var(--fs-surface); border-left: 3px solid var(--fs-border-strong); color: var(--fs-fg-2); border-radius: 0 var(--fs-radius-sm) var(--fs-radius-sm) 0; }
.portal-notice--success { border-left-color: var(--fs-border-strong); }   /* success is not coloured */
.portal-notice--warning { border-left-color: var(--fs-warn); background: var(--fs-warn-soft); }
.portal-notice--error { border-left-color: var(--fs-error); background: var(--fs-error-soft); }

/* ============ forms & buttons ============ */
/* Every form control is dark, not only those inside .portal-field: login, sign-up, the
   usage and convergence filters, billing and waitlist put controls straight into a form.
   Zero specificity (:where) so the component rules below and in portal.css still win.
   16px text: iPhone Safari zooms the page when a focused field's text is under 16px. */
:where(body.portal :is(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="range"]), select, textarea)) {
  background: var(--fs-surface-2); color: var(--fs-fg);
  border: 1px solid var(--fs-border-strong); border-radius: var(--fs-radius-sm);
  font: inherit; font-size: var(--fs-text-body); min-height: 40px; padding: 0 var(--fs-space-3);
}
:where(body.portal) textarea { padding: var(--fs-space-2) var(--fs-space-3); }
:where(body.portal) :is(input[type="checkbox"], input[type="radio"]) { accent-color: var(--fs-lime); }
.portal-fieldset { border: 1px solid var(--fs-border); border-radius: var(--fs-radius); }
.portal-field > label { color: var(--fs-fg); font-weight: 500; }
.portal-field input, .portal-field select, .portal-field textarea {
  background: var(--fs-surface-2); color: var(--fs-fg); border: 1px solid var(--fs-border-strong); border-radius: var(--fs-radius-sm);
}
.portal-field textarea { font-size: var(--fs-text-body); }   /* portal.css sets 0.9rem (14.4px) */
.portal-field :disabled { opacity: .5; }
.portal-hint, .portal-optional { color: var(--fs-muted); font-size: var(--fs-text-small); }
.portal-btn {
  background: var(--fs-accent-fill); color: var(--fs-on-accent); border: 1px solid transparent;
  border-radius: var(--fs-radius-sm); font-weight: 600; min-height: 40px;
}
/* The colour is restated on hover: a link's hover rule (0,1,1) would otherwise beat
   .portal-btn (0,1,0) and put lime text on the lime fill. */
.portal-btn:hover { background: var(--fs-accent-fill-hover); color: var(--fs-on-accent); }
.portal-btn:disabled { opacity: .45; }
.portal-btn--quiet { background: transparent; color: var(--fs-fg); border: 1px solid var(--fs-border-strong); }
.portal-btn--quiet:hover { background: var(--fs-hover); color: var(--fs-fg); }
/* Destructive actions (revoke, remove, withdraw, deactivate, cancel): an error outline,
   never a fill (DESIGN_GUIDELINES.md §7). */
.portal-btn--danger { background: transparent; color: var(--fs-error); border: 1px solid var(--fs-error); }
.portal-btn--danger:hover { background: var(--fs-error-soft); color: var(--fs-error); }
/* "Sign out" is a button that reads as a link (portal.css: padding 0, underline). */
.portal-linkbtn { color: var(--fs-fg-2); text-decoration-color: var(--fs-link-underline); text-underline-offset: 3px; }
.portal-linkbtn:hover { color: var(--fs-accent-text); }

/* ============ code & one-time reveals ============ */
.portal-code { background: var(--fs-surface-2); color: var(--fs-fg); border: 1px solid var(--fs-border); border-radius: var(--fs-radius); font-family: var(--fs-font-mono); }
/* Not lime: .portal-code--answer marks every candidate answer in a loop on the task-model
   page and the playground answer. Lime is for the pick only. */
.portal-code--answer { border-left: 3px solid var(--fs-border-strong); }
.portal-reveal { background: var(--fs-surface); border: 1px solid var(--fs-warn); border-radius: var(--fs-radius); }
.portal-reveal__warning { color: var(--fs-warn); }
.portal-reveal__value { font-family: var(--fs-font-mono); background: var(--fs-surface-2); color: var(--fs-fg); }
/* The two one-time keys on signup/provisioned.html. They must wrap at 320px, never scroll
   off-screen: a key the customer cannot select in one gesture is a key they lose. */
.portal-secret {
  background: var(--fs-surface-2); color: var(--fs-fg); border: 1px solid var(--fs-border); border-radius: var(--fs-radius);
  padding: var(--fs-space-3) var(--fs-space-4); font-family: var(--fs-font-mono); white-space: pre-wrap; overflow-wrap: anywhere;
}

/* ============ figures ============ */
/* Simulated costs (_simulated_cost.html) sit beside _money.html figures: same mono numerals. */
.portal-sim, .portal-sim__amount { font-family: var(--fs-font-mono); font-variant-numeric: tabular-nums; color: var(--fs-fg); }
.portal-sim__basis { color: var(--fs-muted); font-size: var(--fs-text-micro); }
/* The pick: set by the template only when the figure IS the saving (convergence headline,
   and only when the view reports a positive saving). */
.portal-pick .portal-sim__amount, .portal-pick .portal-money__amount,
.portal-headline__figure.portal-pick { color: var(--fs-accent-text); }   /* the convergence headline, when it is a saving */
.portal-card { background: var(--fs-surface); border: 1px solid var(--fs-border); border-radius: var(--fs-radius); }

/* ============ charts ============ */
/* portal.css paints charts on --surface-2 (#1C1F23 after P1.6); gridlines in
   --fs-data-grid (#1E2125) would vanish on it (about 1.03:1). The page is the canvas. */
.portal-chart, .portal-chartist { background: transparent; }
.portal-chart__bar { fill: var(--fs-data-qualifies); }
.portal-chart__bar:hover { fill: var(--fs-fg-2); }
.portal-chart__axis { stroke: var(--fs-data-grid); }
.portal-chart__ticks, .portal-axis { fill: var(--fs-data-axis); color: var(--fs-data-axis); }
.portal-legend__key--sim { border-top-color: var(--fs-accent-text); }   /* the Fronset route = the pick */
.portal-legend__key--ref { border-top-color: var(--fs-muted); }
.portal-chartist .ct-series-a .ct-line { stroke: var(--fs-muted); }        /* reference series (dashed in portal.css) */
.portal-chartist .ct-series-b .ct-line { stroke: var(--fs-accent-text); }  /* the simulated Fronset route */
.portal-chartist .ct-grid { stroke: var(--fs-data-grid); }
.portal-chartist .ct-label { color: var(--fs-data-axis); fill: var(--fs-data-axis); }
.portal-details { border: 1px solid var(--fs-border); border-radius: var(--fs-radius); background: var(--fs-surface); }
.portal-details > summary { color: var(--fs-fg); }
